<?php
/**
 * -----------------------------------------------------------------------------
 *
 * SyL - Web Application Framework for PHP
 *
 * PHP version 4 (>= 4.3.x) or 5
 *
 * Copyright (C) 2006 k.watanabe
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * -----------------------------------------------------------------------------
 * @package   SyL
 * @author    k.watanabe <k.watanabe@syl.jp>
 * @copyright 2006 k.watanabe
 * @license   http://www.opensource.org/licenses/lgpl-license.php
 * @version   CVS: $Id: SyL_Error.php,v 1.9 2007/01/03 11:17:37 seasonstream Exp $
 * @link      http://www.syl.jp/
 * -----------------------------------------------------------------------------
 */

/**
 * エラークラス
 *
 * @package   SyL
 * @author    k.watanabe <k.watanabe@syl.jp>
 * @copyright 2006 k.watanabe
 * @license   http://www.opensource.org/licenses/lgpl-license.php
 * @version   CVS: $Id: SyL_Error.php,v 1.9 2007/01/03 11:17:37 seasonstream Exp $
 * @link      http://www.syl.jp/
 */
class SyL_Error
{
    /**
     * エラーメッセージ配列
     * 
     * @access public
     * @var array
     */
    var $error_messages = array();
    /**
     * 改行コード
     * 
     * @access public
     * @var string
     */
    var $eof = "\r\n";
    /**
     * コントローラオブジェクト
     * 
     * @access protected
     * @var object
     */
    var $controller = null;
    /**
     * データ管理オブジェクト
     * 
     * @access protected
     * @var object
     */
    var $dm = null;

    /**
     * コンストラクタ
     *
     * @access public
     * @param object コントローラ
     */
    function SyL_Error()
    {
    }

    /**
     * SyL_Errorクラスのインスタンス取得
     *
     * singletonモデルを採用しているので、
     * 常に1つのインスタンスの参照が取得される。
     *
     * ※取得方法
     *   $SyL_Error =& SyL_Error::getInstance();
     *
     * @access public
     * @param object コントローラ
     */
    function &getInstance(&$controller)
    {
        static $singleton;
        if (!is_object($singleton)) {
            $class_name = 'SyL_Error' . ucfirst(SYL_ENV_TYPE);
            include_once SYL_INCLUDE_DIR . "/framework/Error/{$class_name}.php";
            // 子クラスのインスタンス生成
            $singleton = new $class_name();
            $singleton->setController($controller);
        }
        return $singleton;
    }

    /**
     * コントローラをセット
     *
     * @access public
     * @param object コントローラ
     */
    function setController(&$controller)
    {
        $this->controller =& $controller;
    }

    /**
     * エラーハンドラを設定
     * 
     * @static
     * @access public
     */
    function setErrorHandler()
    {
        $error =& SyL_Error::getInstance(null);
        if ($error->controller->error_handler_method != '') {
            set_error_handler(array(&$error->controller, $error->controller->error_handler_method));
        }
    }

    /**
     * エラーハンドラを初期化
     * 
     * @static
     * @access public
     */
    function resetErrorHandler()
    {
        restore_error_handler();
    }

    /**
     * エラーメッセージをセット
     * 
     * @static
     * @access public
     * @param string エラーメッセージ
     */
    function setErrorMessage($error_message)
    {
        $error =& SyL_Error::getInstance(null);
        $error->error_messages[] = $error_message;
    }

    /**
     * 全エラーメッセージを取得
     * 
     * @access public
     * @param string エラーメッセージ
     */
    function getErrorMessages()
    {
        return array_merge($this->error_messages, $this->controller->getErrorMessage());
    }

    /**
     * 処理を中断し、共通エラー画面を表示
     * 
     * @static
     * @access public
     * @param string エラーメッセージ
     * @param int エラーレベル
     */
    function trigger($error_string='', $error_type=E_USER_ERROR)
    {
        trigger_error($error_string, $error_type);
    }

    /**
     * エラーハンドラーの実体
     * 
     * @access public
     * @param object データ管理オブジェクト
     */
    function errorHandler() {}

    /**
     * エラータイプを返す
     * ※ただし、実際にプログラムでハンドリングできるのは
     *   E_WARNING
     *   E_NOTICE
     *   E_USER_ERROR
     *   E_USER_WARNING
     *   E_USER_NOTICE
     * のみ
     *
     * @access public
     * @param  int    エラーNo
     * @return string エラータイプ名
     */
    function getErrorType()
    {
        switch ($this->controller->getErrorNo()) {
        case E_ERROR           : return 'Error';
        case E_WARNING         : return 'Warning';
        case E_PARSE           : return 'Parsing Error';
        case E_NOTICE          : return 'Notice';
        case E_CORE_ERROR      : return 'Core Error';
        case E_CORE_WARNING    : return 'Core Warning';
        case E_COMPILE_ERROR   : return 'Compile Error';
        case E_COMPILE_WARNING : return 'Compile Warning';
        case E_USER_ERROR      : return 'User Error';
        case E_USER_WARNING    : return 'User Warning';
        case E_USER_NOTICE     : return 'User Notice';
        default:
            if (defined('E_STRICT') && ($errorNo == E_STRICT)) {
                return 'Strict';
            }
            if (defined('E_RECOVERABLE_ERROR') && ($errorNo == E_RECOVERABLE_ERROR)) {
                return 'Recoverable Error';
            }
        }

        return 'Unknonwn';
    }

    /**
     * トレース情報を取得
     *
     * @access public
     * @return array トレース情報
     */
    function getTrace()
    {
        // エラートレース取得
        $error_trace = array();
        foreach (array_reverse($this->controller->getErrorTrace()) as $value) {
            // ユーザー定義エラー時は、「trigger_error」関数以降を排除
            // その他のエラー時は、「errorhandler」関数以降を排除
            if (isset($value['class']) && (strtolower($value['class']) == strtolower(get_class($this)))) {
                break;
            }
            $tmp = array();
            $tmp['file'] = isset($value['file']) ? $value['file'] : '';
            $tmp['line'] = isset($value['line']) ? $value['line'] : '';
            if (isset($value['class']) && isset($value['type'])) {
                $tmp['function'] = $value['class'] . $value['type'] . $value['function'];
            } else {
                $tmp['function'] = isset($value['function']) ? $value['function'] : '';
            }
            $error_trace[] = $tmp;
        }

        return array_reverse($error_trace);
    }

    /**
     * ロギングを保存
     *
     * @access public
     * @param int エラーNo
     * @param string エラーメッセージ
     */
    function logging()
    {
        $error_no = $this->controller->getErrorNo();
        if ($error_no <= SYL_DEBUG) {
            $log_string  = '[' . $this->getErrorType() . '] ' . implode($this->eof, $this->getErrorMessages()) . $this->eof;
            foreach ($this->getTrace() as $value) {
                $log_string .= "[file] "     . $value['file'] . " ";
                $log_string .= "[line] "     . $value['line'] . " ";
                $log_string .= "[function] " . $value['function'] . $this->eof;
            }

            // エラーレベル毎にログ保存
            switch ($error_no) {
            case E_WARNING:
            case E_USER_WARNING:
                SyL_Loggers::warn($log_string);
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                SyL_Loggers::notice($log_string);
                break;
            default:
                SyL_Loggers::error($log_string);
                break;
            }
        }
    }
}

?>
