Location: PHPKode > projects > ZZ/OSS Installer > zic-1.1.0dev1/installer/lib/HTML/Progress/Error/Raise/Error.php
<?php
/**
 * Error class for the Error_Raise package.
 * @package Error_Raise
 * @version 0.2.2
 * @author Greg Beaver <hide@address.com>
 */
/**#@+
 * Error constants for Error_Raise
 */
/**
 * Error used if a class passed to initialize hasn't been defined yet
 *
 * {@link initialize()} allows
 */
define('ERROR_RAISE_ERROR_CLASS_DOESNT_EXIST', 1);
/**
 * Error used if a package raises an error, but has no registered code->message
 * mapping function.
 */
define('ERROR_RAISE_ERROR_CODENOMSG', 3);
/**
 * Error used if a package already has a package_Raise class and
 * Error_Raise::initialize('package') is called
 */
define('ERROR_RAISE_ERROR_ALREADY_INITIALIZED', 4);
/**
 * Error used if a method doesn't exist in a callback passed in
 */
define('ERROR_RAISE_ERROR_METHOD_DOESNT_EXIST', 5);
/**
 * Error used if a function doesn't exist in a callback passed in
 */
define('ERROR_RAISE_ERROR_FUNCTION_DOESNT_EXIST', 6);
/**
 * Error used when parameters to functions don't match expected types
 */
define('ERROR_RAISE_ERROR_INVALID_INPUT', 7);
/**
 * Error used when a new error class is not a descendant of Error_Raise_Error
 */
define('ERROR_RAISE_ERROR_INVALID_ERROR_CLASS', 8);
/**
 * Error used when an internal function is passed as a callback - this is never
 * allowed.
 */
define('ERROR_RAISE_ERROR_INTERNAL_FUNCTION', 9);
/**
 * Error used when an invalid callback is passed as an error message generator
 */
define('ERROR_RAISE_ERROR_INVALID_ERRMSGGEN', 10);
/**
 * Error used when an invalid callback is passed as a context grabber
 */
define('ERROR_RAISE_ERROR_INVALID_CONTEXT_GRABBER', 11);
/**
 * Error used when a context grabber does not return an array
 */
define('ERROR_RAISE_ERROR_INVALID_CONTEXTGRABBER_RETURN', 12);
/**#@-*/

/**
 * Extended error class with support for extensive user info
 *
 * Enhancements to PEAR_Error include:
 *
 * - Error messages are generated dynamically at runtime, preserving specific
 *   error data that would otherwise need to be extracted from an error message
 *   using a regexp hack.  This allows greater control and automatic error
 *   processing
 * - {@link getMessage()} accepts a parameter indicating what display environment
 *   the message exists in.  Legal values are ERROR_RAISE_TEXT, ERROR_RAISE_ANSI,
 *   and ERROR_RAISE_HTML
 * - {@link getPackage()} returns the package associated with an error.  No
 *   longer is there any guesswork involved with hacking getType()
 * - {@link getErrorType()} allows for the first time, error levels.  Not all
 *   errors are simply fatal errors, and this uses PHP's default error levels
 *   and allows notice/warning/error/exception levels.
 * - Customizable automatic context information.  {@link getErrorPrefix()}
 *   and {@link getErrorSuffix()} are used in conjunction with
 *   {@link Error_Raise::setContextGrabber()} to display things like File/Line
 *   number, class and function of calling context, and optionally, a stack
 *   trace (this is only possible in PHP 4.3.0 and above)
 * - Cascading errors.  If another error was transformed into this one,
 *   {@link getParent()} can be used to retrieve the error object that
 *   originally caused the current one to be thrown.  An example might be when
 *   a database error occurs in a CMS.  The common user shouldn't see database
 *   errors, but administrators should.  By accessing getParent() for admins,
 *   and just the CMS error for users, this is easy to implement.
 * @version 0.2.2
 * @author Greg Beaver <hide@address.com>
 * @package Error_Raise
 * @todo Implement pretty stack dump for those who want it
 */
class Error_Raise_Error extends PEAR_Error {
    /**
     * Parameters passed to the constructor to be formatted into User Info
     * @var array
     * @access private
     */
    var $_params;
    /**
     * File in which this error originated
     * @var string|null
     * @access private
     */
    var $_file;
    /**
     * Line number on which this error originated
     * @var integer|null
     * @access private
     */
    var $_line;
    /**
     * Class in which this error originated
     * @var string|null
     * @access private
     */
    var $_class;
    /**
     * Function/method on which this error originated
     * @var string|null
     * @access private
     */
    var $_function;
    /**
     * Parent error, if this is a cascaded error
     * @see getParent()
     * @var Error_Raise_Error|false
     * @access private
     */
    var $_parent = false;
    /**
     * Used for determining package name
     * @access private
     * @var string
     */
    var $_type = 'error';
    /**
     * Used for determining how man lines of code on either side of an error
     * to include in a context code listing
     * @var integer
     * @access private
     */
    var $_contextLines = 5;
    /**
     * @var string
     * @access private
     */
    var $_package = 'error_raise';
    
    /**
     * Note that error objects should not be created directly, but with the
     * help of {@link Error_Raise::raise()} or the easy helper functions listed
     * below.
     * @see Error_Raise::exception()
     * @see Error_Raise::error()
     * @see Error_Raise::warning()
     * @see Error_Raise::notice()
     * @param string error type (notice/warning/error/exception)
     * @param integer error code
     * @param array extra information to be passed to the error message
     *        generation
     * @param integer|null mode, see {@link PEAR.php}
     * @param string|array|null callback function/method for PEAR_ERROR_CALLBACK
     */
    function Error_Raise_Error($package, $type, $code, $extrainfo = array(),
        $mode = null, $extracallback = null, $backtrace = null, $parent = null)
    {
        $this->_type = $type;
        $this->_parent = $parent;
        $this->_package = strtolower($package);
        $this->backtrace = $backtrace;
        $this->userinfo = $extrainfo;
        $this->code = $code;
        if ($mode === null) {
            $mode = 0;
        }
        $this->mode = $mode;
        if ($type == 'exception') {
            $this->mode |= PEAR_ERROR_EXCEPTION;
        }
        if ($type == 'warning') {
            $this->level = E_USER_WARNING;
        }
        if ($type == 'notice') {
            $this->level = E_USER_NOTICE;
        }
        if ($type == 'error'
              || $type == 'exception') {
            $this->level = E_USER_ERROR;
        }
        $this->callback = $extracallback;
        if ($this->mode & PEAR_ERROR_TRIGGER) {
            trigger_error($this->getMessage(), $this->level);
        }
        if ($this->mode & PEAR_ERROR_DIE) {
            die($this->getMessage());
        }
        if ($this->mode & PEAR_ERROR_CALLBACK) {
            if (is_string($this->callback) && strlen($this->callback)) {
                call_user_func($this->callback, $this);
            } elseif (is_array($this->callback) &&
                      sizeof($this->callback) == 2 &&
                      is_object($this->callback[0]) &&
                      is_string($this->callback[1]) &&
                      strlen($this->callback[1])) {
                      call_user_func($this->callback, $this);
            }
        }
        if (PEAR_ZE2 && $this->mode & PEAR_ERROR_EXCEPTION) {
            eval('throw $this;');
        }
    }
    
    /**
     * Process a debug_backtrace.  This method should be called by
     * either getErrorPrefix() or getErrorSuffix() in situations where it is
     * needed.
     * @param array output from debug_backtrace
     * @param Error_Raise_Error
     * @param string error type (warning, error, exception, notice)
     * @access protected
     */
    function _grabBacktrace()
    {
        if (isset($GLOBALS['_ERROR_RAISE_CONTEXTGRABBER']
              [$this->_package])) {
            list($frame, $functionframe) = Error_Util::_parseBacktrace(
                $this->backtrace, $this->_type, $this);
            $func = $GLOBALS['_ERROR_RAISE_CONTEXTGRABBER']
                [$this->_package];
            $fileline = call_user_func($func, $this->backtrace,
                $frame, $functionframe);
            if ($fileline) {
                if (!is_array($fileline)) {
                    if ($this->_package == 'error_raise') {
                        die('EXCEPTION: Error_Raise context grabber '
                        . 'did NOT return an array in '
                        . 'Error_Raise::_grabBacktrace().  You should NEVER'
                        . 'see this message');
                    }
                    return Error_Raise::exception('error_raise',
                        ERROR_RAISE_ERROR_INVALID_CONTEXTGRABBER_RETURN,
                        array('type' => gettype($fileline),
                              'package' => $this->_package));
                }
                foreach($fileline as $var => $value) {
                    // for future extensibility
                    $this->$var = $value;
                }
                if (!isset($this->_context) && isset($this->_file) &&
                      isset($this->_line)) {
                    $this->_context =
                        Error_Util::getErrorContext($this->_file, $this->_line);
                }
            }
        }
    }
    
    /**
     * Retrieve the package name of this error object
     * @return string
     */
    function getPackage()
    {
        return $this->_package;
    }
    
    /**
     * Retrieve the error message for this object
     *
     * Error messages are dynamically generated from the callback
     * set by {@link Error_Raise::initialize()}, or passed to
     * {@link Error_Raise::setErrorMsgGenerator()}.  The function is passed the
     * error code, user information that was set in the constructor, and the
     * display state, and must return a string.
     *
     * An example error message generator is Error_Raises's own generator
     * found at {@link Error_Raise::_getErrorMessage()}
     * @uses getErrorPrefix() grab the error prefix generated dynamically
     *       from context information
     * @return string
     * @throws ERROR_RAISE_ERROR_CODENOMSG if no error message generator
     *         function has been registered for this package
     * @param ERROR_RAISE_TEXT|ERROR_RAISE_HTML|ERROR_RAISE_ANSI format state
     *        that error message should be in
     * @param boolean determines whether source code context is displayed with
     *        the message.  By default, the presence of a context grabbing
     *        function sets this to true.  Pass in true to turn off context
     *        display
     */
    function getMessage($state = ERROR_RAISE_TEXT, $context = false)
    {
        $package = $this->_package;
        if (isset($GLOBALS['_ERROR_RAISE_MSGS'][$package])) {
            if (function_exists('debug_backtrace')) {
                $e = $this->_grabBacktrace($this->backtrace, $this, $this->_type);
                if (PEAR::isError($e)) {
                    return $e;
                }
            }
            $this->error_message_prefix = $this->getErrorPrefix($state, $context);
            $this->message = $this->getBareMessage($state);
            $this->error_message_suffix = $this->getErrorSuffix($state, $context);
            return $this->error_message_prefix . $this->message .
                $this->error_message_suffix;
        } else {
            $e = Error_Raise::warning('error_Raise', ERROR_RAISE_ERROR_CODENOMSG,
                array('package' => $package));
            if (strlen($this->message)) {
                return parent::getMessage();
            }
            return $e->getMessage($state);
        }
    }
    
    /**
     * Return the error message without prefix or suffix
     * @param ERROR_RAISE_TEXT|ERROR_RAISE_HTML|ERROR_RAISE_ANSI format state
     *        that error message should be in
     */
    function getBareMessage($state = ERROR_RAISE_TEXT)
    {
        $info = $this->getUserInfo();
        if (!is_array($info)) {
            $info = array();
        }
        $args = array_merge(array($this->code), array($info), array($state));
        return call_user_func_array(
                $GLOBALS['_ERROR_RAISE_MSGS'][$this->getPackage()], $args);
    }
    
    /**
     * Returns default error prefix
     *
     * The default error prefix is:
     *
     * Packagename exception|error|warning|notice[ in file "filename"][
     * on line ##]:
     *
     * If the Console_Color package is present, ERROR_RAISE_ANSI will return
     * a colored error message for console display.
     * @param ERROR_RAISE_TEXT|ERROR_RAISE_HTML|ERROR_RAISE_ANSI format state
     *        that error message should be in
     * @param boolean If true, then return any context information.  By default,
     *                this is ignored in getErrorPrefix(), and handled in
     *                {@link getErrorSuffix()}
     * @see Error_Raise::setContextGrabber()
     * @return string
     */
    function getErrorPrefix($state = ERROR_RAISE_TEXT, $context = false)
    {
        if (isset($this->backtrace)) {
            $this->_grabBacktrace();
        }
        $vars = array('package' => $this->getPackage(),
                      'errortype' => $this->getErrorType());
        $prefix = '%package% %errortype%';
        if (isset($this->_file)) {
            $vars['file'] = $this->_file;
            $prefix .= ' in file "%file%"';
        }
        if (isset($this->_function)) {
            $prefix .= ', ';
            if (isset($this->_class)) {
                $vars['class'] = $this->_class;
                $prefix .= '%class%::';
            }
            $vars['function'] = $this->_function;
            $prefix .= '%function%';
        }
        if (isset($this->_line)) {
            $vars['line'] = $this->_line;
            $prefix .= ' on line %line%';
        }
        $prefix .= " :\n";
        return Error_Raise::sprintfErrorMessageWithState($prefix, $vars, $state);
    }
    
    /**
     * Returns default error suffix
     * @param ERROR_RAISE_TEXT|ERROR_RAISE_HTML|ERROR_RAISE_ANSI format state
     *        that error message should be in
     * @param boolean If true, then return any context information.  By default,
     *                the source code is highlighted as PHP in HTML and returned
     *                or just returned as is in other states
     */
    function getErrorSuffix($state = ERROR_RAISE_TEXT, $context = false)
    {
        if ($context) {
            if (isset($this->backtrace)) {
                $this->_grabBacktrace();
            }
            if (isset($this->_file) && isset($this->_line)) {
                $context = Error_Util::getErrorContext($this->_file, $this->_line,
                                                       $this->_contextLines);
                if ($state == ERROR_RAISE_HTML) {
                    return @highlight_string(trim($context['source']), true);
                } else {
                    $vars['context'] = trim($context['source']);
                }
                $suffix = "\n%context%\n";
                return Error_Raise::sprintfErrorMessageWithState($suffix, $vars,
                    $state);
            }
        } else {
            return '';
        }
    }
    
    /**
     * Get the name of this error, one of error, exception, warning, or notice.
     * @return string
     */
    function getErrorType()
    {
        return $this->_type;
    }
    
    /**
     * Get parent error, if this is a cascaded error
     *
     * If this error object is a result of an error from another package,
     * it is a cascaded error.  An example might be a database error in a CMS.
     * The CMS most likely will not want to display to the user an error that
     * states "this table does not have that field", but instead re-package
     * the error into format "your request failed because ...".  However, a
     * CMS administrator would want to see the database error in order to
     * pass on debug information to developers (or fix it himself/herself).
     * This variable stores the parent object, making this possible.  Cascading
     * is unlimited, and can be accessed through getParent()
     * @return false|Error_Raise_Error parent error object
     */
    function &getParent()
    {
        return $this->_parent;
    }
    
    /**
     * Set the parent error object, for error cascading
     * @see getParent()
     * @param Error_Raise_Error|false
     */
    function setParent(&$parent)
    {
        $this->_parent = &$parent;
    }
    
    /**
     * Set the number of lines of source code to use for errors that contain
     * file and line number information.
     *
     * This setting should be considered 1/2 of the number of lines - for
     * instance, if this is set to 5, then there will be up to 5 lines of code
     * from before and 5 lines of code from after the error code line.
     *
     * If $lines > 10 we reset it to 10
     * @param integer
     */
    function setContextLines($lines)
    {
        if (!is_int($lines)) {
            // no errors for the dummies
            $lines = 5;
        }
        if ($lines > 10) {
            $lines = 10;
        }
        $this->_contextLines = $lines;
    }
    
    /**
     * Re-assign an error to this error's package
     *
     * If an error is returned that needs to be re-defined for another package,
     * this method should be called from the pre-existing error in order to
     * transform it into another package's error
     * @param string package name of new error object
     * @param error|warning|notice|exception error severity
     * @param integer error code
     * @param array|null|false any new information for the error message,
     *        otherwise existing information will be used.  If passed false,
     *        the new information will be set to null
     * @throws ERROR_RAISE_ERROR_INVALID_INPUT
     */
    function &rePackageError($package, $type, $code, $extrainfo = null)
    {
        if (!is_string($type)) {
            return Error_Raise::exception('error_raise',
                ERROR_RAISE_ERROR_INVALID_INPUT,
                array('was' => gettype($type), 'expected' => 'string',
                'param' => '$type', 'paramnum' => 2));
        }
        $type = strtolower($type);
        if (!in_array($type, array('error', 'warning', 'notice', 'exception'))) {
            return Error_Raise::exception('error_raise',
                ERROR_RAISE_ERROR_INVALID_INPUT,
                array('was' => $type, 'expected' => array('error', 'warning',
                 'notice', 'exception'), 'param' => '$type', 'paramnum' => 2));
        }
        if (!is_string($package)) {
            return Error_Raise::exception('error_raise',
                ERROR_RAISE_ERROR_INVALID_INPUT,
                array('was' => gettype($package), 'expected' => 'string',
                'param' => '$package', 'paramnum' => 1));
        }
        if (!class_exists($errorclass = $package . '_error')) {
            $errorclass = 'error_raise_error';
        }
        $backtrace = false;
        if (function_exists('debug_backtrace')) {
            $backtrace = debug_backtrace();
        }
        $e = new $errorclass($package, $type, $code, $extrainfo, $this->mode,
            $this->callback, $backtrace, $this);
        return $e;
    }
}
?>
Return current item: ZZ/OSS Installer