ExceptionCatcher.php

<?php

namespace Lia;

/**
 * Catches exceptions & provides helpful error messages
 */
class ExceptionCatcher {

    protected $trace;
    protected $message;
    protected $dir;

    protected $subs = [];

    public $liaMessage;

    /**
     * prints the informative message (use output buffering if you want)
     * @param Exception $e 
     */
    static public function message($e){
        // echo 'zippity zeep';
        // exit;
        echo "\n";
        $trace = $e->getTrace();
        foreach ($trace as $index=>$row){
            $row['class'] = $row['class'] ?? 'n/a';

            if ($row['class']=='Lia\\Addon\\Resources'
                &&$row['function']=='addFile'
            ){

                $msg = $e->getMessage();
                echo 'Message: '.$msg;
                static::report($trace[$index]??null);
                break;
            }

            if ($row['class']=='Lia\\Addon\\Cache'
                &&$row['function']=='get_cache_file_content'
            ){
                
                $msg = $e->getMessage();
                $begin = 'file_get_contents(): Filename cannot be empty';
                if ($msg == $begin) {
                    echo 'Message: You probably need to set the cache dir.';
                } else {
                   echo "Message: There was an error with cache, but i don't know what it is."; 
                }
                static::report($trace[$index]??null);
                break;
            }


            if ($row['class']=='Lia\\Addon\\View'
                &&$row['function']=='view'
            ){
                
                $msg = $e->getMessage();
                $begin = 'Undefined index: ';
                if (substr($msg,0,strlen($begin))==$begin){
                    $name = substr($msg,strlen($begin));
                    echo "Message: View was not found. Either the namespace is unavailable or the view was not set. The key is `{$name}`";
                } else {
                   echo "Message: There was an error with views, but i don't know what it is."; 
                }
                $dir = dirname(__DIR__);
                $len = strlen($dir);
                $report_row = $trace[$index];
                while (substr($report_row['file'], 0, $len)==$dir){
                    $report_row = $trace[++$index];
                }
                static::report($trace[$index]??null);
                break;
            } 

            
            if ($row['class']=='Lia\\Addon\\Hook'
                &&$row['function']=='call'
            ){
                $msg = $e->getMessage();
                $begin = 'Undefined index: ';
                if (substr($msg,0,strlen($begin))==$begin){
                    echo "Message: Hook named `".substr($msg,strlen($begin)).'` does not exist and cannot be called';
                } else {
                    // echo "Message: You tried to call an api method that is not set.";
                    echo "I don't know what the problem is, but I think it starts at this:";
                }
                static::report($trace[$index]??null);
                break;

            }


            /**
             * report an error on a magic __call() on Lia
             */
            if ($row['class']=='Lia'
                &&$row['function']=='__call'
            ){
                $msg = $e->getMessage();
                $begin = 'Undefined index: ';
                if (substr($msg,0,strlen($begin))==$begin){
                    echo "Message: Api method `".substr($msg,strlen($begin)).'` does note exist on Lia';
                } else {
                    // echo "Message: You tried to call an api method that is not set.";
                    echo "I don't know what the problem is, but I think it starts at this:";
                }
                static::report($trace[$index]??null);
                break;
            }
        }

    }

    /**
     * prints the stack trace
     * @param Exception $e 
     */
    static public function trace($e){

        throw $e;
        // $trace = $e->getTrace();
//
        // echo "\n\n---begin stacktrace---\n";
//
        // print_r($trace);
    }

    /** 
     * throw the given error after printing a custom trace and message
     *
     * @param Exception $e 
     * @param $print_messages false to disable printing of the custom trace & message output
     */
    static public function throw($e, $print_messages=true){
        if ($print_messages){
            static::trace($e);
            static::message($e);
        }
        throw $e;
    }

    static public function report($trace_entry){
        echo "\n\n";
        echo "Called from: "
            ."\n - File: ".$trace_entry['file']
            ."\n - Line: ".$trace_entry['line']
            ."\n - Function: ".$trace_entry['function']
            ;
        echo "\n\n";
    }

    static public function dir(){
        return '--dir-not-implemented-yet--';
    }

    static public function getExternalTrace($exception){
        // if ($this->trace!=null)return  $this->trace;

        $list = $exception->getTrace();
        $et = null;

        $message = "";
        $dir = static::dir($exception);

        foreach ($list as $depth => $trace){        #2 [internal function]: Lia\Route\Router->global_contentFor()
            $trace['line'] = $trace['line'] ?? '--n/a--';
            $file = $trace['file'] ?? '--n/a--';
            $trace['file'] = $file;
            $sub = substr($file,0,strlen($dir));
            if ($file=='--n/a--'){
                $message .= "Anonymous functions at stack #".$depth."\n";
                continue;
            } else if ($sub==$dir){
                continue;
            }
            $et = $trace;
            $next = $list[$depth+1] ?? null;
            break;
        }
        $trace = (object) array_merge(
            ['raw'=>$et,
            'depth'=>$depth,
            'extraInfo'=>$message,
            ],
            $et,
        );
        $trace->calledClass = $trace->class;
        unset($trace->class);
        $trace->calledFunction = $trace->function;
        if ($trace->function=='__call'){
            //@TODO get the args (using debug_backtrace in the constructor) & provide the actual method call.
        }

        unset($trace->function);
        $trace->fromClass = $next['class'] ?? '--n/a--';
        $trace->fromFunction = $next['function'] ?? '--n/a--';

        $trace->message = $exception->getMessage();

        return $trace;
    }
}