Skip to content

Instantly share code, notes, and snippets.

@jnrbsn
Created December 19, 2012 03:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnrbsn/4334276 to your computer and use it in GitHub Desktop.
Save jnrbsn/4334276 to your computer and use it in GitHub Desktop.
Objected-oriented command line output library for PHP.
<?php
/**
* Objected-oriented command line output library for PHP.
*
* Dependencies:
* - Console_Color PEAR package
* - Bash
*
* PHP version 5
*
* @author Jonathan Robson <jnrbsn@gmail.com>
* @copyright 2011 Jonathan Robson
* @license MIT License http://www.opensource.org/licenses/mit-license.php
* @version 0.1-beta
* @link N/A
*/
/**
* The main class for the library.
*/
class Outy
{
/**
* Stores the message of the current task or false if not doing anything.
*
* @var mixed
* @since 0.1
*/
private $_currentTask = false;
/**
* Creates an instance of the class.
*
* Sets the error handler to $this->errorHandler().
*
* @since 0.1
*/
public function __construct()
{
// Turn on all PHP errors.
error_reporting(E_ALL);
// Set a custom error handler.
set_error_handler(array($this, 'errorHandler'));
}//end __construct()
/**
* Prints a status message to the console.
*
* @param string $message The message to print.
* @param boolean $clearLine Whether or not to clear the line before printing.
*
* @since 0.1
* @return void
*/
public function status($message, $clearLine=false)
{
if ($clearLine === true) {
echo "\033[K\r";
} else if ($this->_currentTask !== false && $this->_currentTask !== $message) {
$this->success();
}
$this->_currentTask = $message;
echo str_pad($message.':', 59);
}//end status()
/**
* Prints "[ OK ]" in green.
*
* @since 0.1
* @return void
*/
public function success()
{
if ($this->_currentTask !== false) {
$this->_currentTask = false;
echo '[ '.Console_Color::convert('%gOK%n').' ]'."\n";
}
}//end success()
/**
* Prints "[FAILED]" in red.
*
* @since 0.1
* @return void
*/
public function failure()
{
if ($this->_currentTask !== false) {
$this->_currentTask = false;
echo '['.Console_Color::convert('%rFAILED%n').']'."\n";
}
}//end failure()
/**
* Prints "[ SKIP ]" in yellow.
*
* @since 0.1
* @return void
*/
public function skip()
{
if ($this->_currentTask !== false) {
$this->_currentTask = false;
echo '[ '.Console_Color::convert('%ySKIP%n').' ]'."\n";
}
}//end skip()
/**
* Prints a percentage of progress.
*
* Designed to be used while a task is running.
*
* @param float $decimal A float between 0 and 1.
*
* @since 0.1
* @return void
*/
public function percentProgress($decimal)
{
echo str_pad(number_format($decimal * 100, 1).'% ', 8, ' ', STR_PAD_LEFT);
echo str_repeat("\010", 8);
}//end percentProgress()
/**
* Ask a question at the CLI and get the answer.
*
* @param string $question The prompt to display.
* @param boolean $pattern A regular expression that answer must match.
* @param string $default The default answer if no answer is given.
* @param boolean $echo Whether or not to echo the answer as it's typed.
*
* @since 0.1
* @return string The answer.
*/
public function prompt($question, $pattern=null, $default=null, $echo=true)
{
if ($default === null) {
$default = '';
}
if ($pattern === null) {
$pattern = '/.*/';
}
do {
if (isset($answer)) {
echo "\n".self::formatText('Invalid answer! Please try again...')."\n";
}
$question = rtrim(self::formatText($question), "\r\n").' ';
$answer = rtrim(
shell_exec(
'read -e'.($echo ? '' : 's').' -p '.escapeshellarg($question).
' OUTY_PROMPT_ANSWER; echo $OUTY_PROMPT_ANSWER 2>&1'
), "\r\n"
);
if (!$echo) {
echo "\n";
}
} while (!preg_match($pattern, $answer));
if (empty($answer) && !empty($default)) {
$answer = $default;
}
return $answer;
}//end prompt()
/**
* The error handler.
*
* Tries to output errors in a consistent way.
*
* @param integer $level The error level.
* @param string $message The error message.
* @param string $file The path to the file in which the error occurred.
* @param integer $line The line number on which the error occurred.
*
* @since 0.1
* @return bool Returns true or dies.
*/
public function errorHandler($level, $message, $file, $line)
{
if (error_reporting() === 0) {
// Return early if an error-control operator was used.
return true;
}
$filename_length_max = 50 - strlen($line);
$filename_length = strlen($file);
if ($filename_length > $filename_length_max) {
$file = '...'.substr($file, $filename_length - $filename_length_max);
}
$formattedMessage = self::formatText(
$message."\n".'{'.$file.':'.$line.'}',
4,
false
)."\n";
if ($level == E_ERROR || $level == E_USER_ERROR) {
if ($this->_currentTask !== false) {
$this->failure();
}
fwrite(STDERR, "\n ".Console_Color::convert('%RERROR:%n ').$formattedMessage);
exit(2);
} else if ($level == E_WARNING || $level == E_USER_WARNING) {
if ($this->_currentTask !== false) {
$this->failure();
}
fwrite(STDERR, "\n ".Console_Color::convert('%YWARNING:%n ').$formattedMessage);
} else if ($level == E_NOTICE || $level == E_USER_NOTICE) {
return true;
} else if ($level == E_STRICT) {
return true;
} else if (defined('E_DEPRECATED')
&& ($level == E_DEPRECATED || $level == E_USER_DEPRECATED)
) {
return true;
} else {
if ($this->_currentTask !== false) {
$this->failure();
}
fwrite(
STDERR,
"\n ".Console_Color::convert('%RUNKNOWN ERROR ('.$level.'):%n ').
$formattedMessage
);
exit(1);
}//end if
return true;
}//end errorHandler()
/**
* Formats some arbitary text in preparation for outputing it to the console.
*
* @param string $text The text to format.
* @param integer $indentation The amount of indentation for each level.
* @param boolean $indent_first_line Whether or not to indent the very first line.
* @param boolean $indent_forced_wraps Whether or not to indent text that gets wrapped an
* additional level.
*
* @since 0.1
* @return string The formatted text.
*/
public static function formatText($text, $indentation=4, $indent_first_line=true,
$indent_forced_wraps=true
) {
$padding = str_repeat(' ', $indentation);
$line_length = 80;
$formatted = '';
foreach (explode("\n", trim($text)) as $line) {
if (strlen($line) <= $line_length - $indentation) {
$formatted .= $padding.$line."\n";
continue;
}
$end_of_first_line = strrpos(substr($line, 0, $line_length - $indentation + 1), ' ');
$formatted .= $padding.substr($line, 0, $end_of_first_line)."\n";
$formatted .= $indent_forced_wraps === true ? $padding.$padding : $padding;
$formatted .= wordwrap(
substr($line, $end_of_first_line + 1),
$line_length - ($indentation * ($indent_forced_wraps === true ? 2 : 1)),
"\n".($indent_forced_wraps === true ? $padding.$padding : $padding)
);
$formatted .= "\n";
}
if ($indent_first_line === false) {
$formatted = ltrim($formatted);
}
return $formatted;
}//end formatText()
/**
* Converts a string to the color blue for console output.
*
* @param string $string The string to convert.
*
* @since 0.1
* @return string The colored text.
*/
public static function blue($string)
{
return Console_Color::convert('%c'.$string.'%n');
}//end blue()
/**
* Converts a string to the color green for console output.
*
* @param string $string The string to convert.
*
* @since 0.1
* @return string The colored text.
*/
public static function green($string)
{
return Console_Color::convert('%g'.$string.'%n');
}//end green()
/**
* Converts a string to the color red for console output.
*
* @param string $string The string to convert.
*
* @since 0.1
* @return string The colored text.
*/
public static function red($string)
{
return Console_Color::convert('%r'.$string.'%n');
}//end red()
/**
* Converts a string to the color yellow for console output.
*
* @param string $string The string to convert.
*
* @since 0.1
* @return string The colored text.
*/
public static function yellow($string)
{
return Console_Color::convert('%y'.$string.'%n');
}//end yellow()
}//end class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment