]> git.andy128k.dev Git - ipf.git/commitdiff
rework debug page for 500
authorAndrey Kutejko <andy128k@gmail.com>
Sun, 17 Aug 2014 13:54:03 +0000 (16:54 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Sun, 17 Aug 2014 13:54:03 +0000 (16:54 +0300)
composer.lock
ipf/http/request.php
ipf/http/response/servererror.php
ipf/http/response/servererrordebug.php
ipf/orm/collection.php
ipf/orm/pager.php
ipf/orm/pager/layout.php
ipf/orm/query/abstract.php
ipf/orm/record/abstract.php
ipf/router.php

index acf293f883b2d09eaf6ac6e46b68005279926655..87cb631ad2a717bf4bea4a8a0bc72850d5438a47 100644 (file)
@@ -12,7 +12,7 @@
             "source": {
                 "type": "git",
                 "url": "git://git.andy128k.net/ipf-template.git",
-                "reference": "ecb0223b97848beb7aa5841934de45b9c97bfd9f"
+                "reference": "ce8150e469804e5b547cda1f4ab51da22d1ce116"
             },
             "require-dev": {
                 "phpunit/phpunit": "3.7.*"
@@ -37,7 +37,7 @@
                 }
             ],
             "description": "Template Engine extracted from IPF Web Framework",
-            "time": "2013-10-06 15:58:13"
+            "time": "2014-08-17 06:31:33"
         },
         {
             "name": "andy128k/migrations",
@@ -74,7 +74,7 @@
             "source": {
                 "type": "git",
                 "url": "git://git.andy128k.net/missing-tools.git",
-                "reference": "a37bcfc615daa8682efffb59fbe685aab93d19aa"
+                "reference": "a7f7bd0891d1cfe8f6ce418af5b7f2998a145e1f"
             },
             "require": {
                 "andy128k/pegp": "0.1.*@dev",
@@ -99,7 +99,7 @@
                 }
             ],
             "description": "Miscellaneous utilities",
-            "time": "2014-07-22 11:53:58"
+            "time": "2014-08-17 13:46:37"
         },
         {
             "name": "andy128k/pegp",
index 78fa4e58110f666862b51efb6ab90ee90f7aace2..622706f1e0ab5e52fe7155f274d930a2050d41ee 100644 (file)
@@ -51,5 +51,18 @@ class IPF_HTTP_Request
     {
         return ($this->is_secure ? 'https://' : 'http://') . $this->http_host . $this->query;
     }
+
+    public function getHeaders()
+    {
+        if (function_exists('getallheaders'))
+            return getallheaders();
+        else
+            return false;
+    }
+
+    public function getBody()
+    {
+        return file_get_contents('php://input');
+    }
 }
 
index 3c9717b90e62947acaa2eb06bda9794d066432b6..c61f34559d3b9cf316699e0531ebde30619b7a07 100644 (file)
@@ -2,7 +2,7 @@
 
 class IPF_HTTP_Response_ServerError extends IPF_HTTP_Response
 {
-    function __construct($e, $mimetype=null)
+    function __construct($request, $e, $mimetype=null)
     {
         parent::__construct('<h1>500 Server Error</h1><p>Our apologies&hellip;</p><p>Please return later</p>', $mimetype);
         $this->status_code = 500;
index 207572151e2ac8221966100c62fdc9b3a6b607ba..3fc726487710f6d9aab34b96df4e7e6b9396b162 100644 (file)
@@ -1,11 +1,14 @@
 <?php
 
+use \PFF\HtmlBuilder\Tag as Tag;
+
 class IPF_HTTP_Response_ServerErrorDebug extends IPF_HTTP_Response
 {
-    function __construct($e, $mimetype=null)
+    function __construct($request, $exception, $mimetype=null)
     {
         $this->status_code = 500;
-        $this->content = IPF_HTTP_Response_ServerErrorDebug_Pretty($e);
+        $page = new IPF_HTTP_ServerErrorDebugPage($request, $exception);
+        $this->content = $page->html();
     }
 }
 
@@ -13,51 +16,13 @@ function debug_print_r($v, $indent=0)
 {
     $result = array();
 
-    if ($v instanceof IPF_HTTP_Request) {
-        return 'IPF_HTTP_Request';
-    } elseif ($v instanceof IPF_ORM_Query_Abstract) {
-        $result = array(
-            get_class($v),
-            '{',
-            '    sql: ' . $v->getQuery(),
-            '}');
-    } elseif ($v instanceof IPF_ORM_Record_Abstract) {
-        $result[] = get_class($v);
-        $result[] = '{';
-        foreach ($v->getTable()->getColumnNames() as $column) {
-            $result[] = '    ' . $column . ': ' . debug_print_r($v->get($column), $indent+2);
-        }
-        $result[] = '}';
-    } elseif ($v instanceof IPF_ORM_Collection) {
-        $result[] = get_class($v);
-        $result[] = '{';
-        foreach ($v as $key => $value) {
-            $result[] = '    ' . $key . ': ' . debug_print_r($value, $indent+2);
-        }
-        $result[] = '}';
-    } elseif ($v instanceof IPF_Template_Context) {
-        $result[] = get_class($v);
+    if (is_object($v) && method_exists($v, '__debugInfo')) {
+        $result[] = get_class($v) . ' Object';
         $result[] = '{';
-        foreach ($v->_vars as $var => $value) {
-            $result[] = '    ' . $var . ': ' . debug_print_r($value, $indent+2);
+        foreach ($v->__debugInfo() as $key => $val) {
+            $result[] = '    [' . $key . '] => ' . debug_print_r($val, $indent+2);
         }
         $result[] = '}';
-    } elseif ($v instanceof IPF_Template_ContextVars) {
-        $result[] = get_class($v);
-        $result[] = '{';
-        foreach ($v as $var => $value) {
-            $result[] = '    ' . $var . ': ' . debug_print_r($value, $indent+2);
-        }
-        $result[] = '}';
-    } elseif ($v instanceof IPF_ORM_Pager_Layout) {
-        $pager = $v->getPager();
-        $result = array(
-            'IPF_ORM_Pager_Layout',
-            '{',
-            '    page:  ' . $pager->getPage(),
-            '    size:  ' . $pager->getMaxPerPage(),
-            '    query: ' . debug_print_r($pager->getQuery(), $indent+2),
-            '}');
     } elseif ($v instanceof stdClass) {
         $result[] = 'stdClass';
         $result[] = '{';
@@ -69,7 +34,7 @@ function debug_print_r($v, $indent=0)
         $result[] = 'Array';
         $result[] = '{';
         foreach ($v as $k => $v) {
-            $result[] = '    ' . $k . ' => ' . debug_print_r($v, $indent+2);
+            $result[] = '    [' . $k . '] => ' . debug_print_r($v, $indent+2);
         }
         $result[] = '}';
     } elseif (is_bool($v)) {
@@ -84,338 +49,354 @@ function debug_print_r($v, $indent=0)
     return ltrim(implode("\n", $result));
 }
 
-function IPF_HTTP_Response_ServerErrorDebug_Pretty($e) 
+class IPF_HTTP_ServerErrorDebugPage
 {
-    $o = create_function('$in','return htmlspecialchars($in);');
-    $sub = create_function('$f','$loc="";if(isset($f["class"])){
-        $loc.=$f["class"].$f["type"];}
-        if(isset($f["function"])){$loc.=$f["function"];}
-        if(!empty($loc)){$loc=htmlspecialchars($loc);
-        $loc="<strong>$loc</strong>";}return $loc;');
-    $parms = create_function('$f','$params=array();if(isset($f["function"])){
-        try{if(isset($f["class"])){
-        $r=new ReflectionMethod($f["class"]."::".$f["function"]);}
-        else{$r=new ReflectionFunction($f["function"]);}
-        return $r->getParameters();}catch(Exception $e){}}
-        return $params;');
-    $src2lines = create_function('$file','$src=nl2br(highlight_file($file,TRUE));
-        return explode("<br />",$src);');
-    $clean = create_function('$line','return trim(strip_tags($line));');
-    $desc = get_class($e)." making ".$_SERVER['REQUEST_METHOD']." request to ".
-        $_SERVER['REQUEST_URI'];
-    $out = '
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-  "http://www.w3.org/TR/html4/loose.dtd">
-<html lang="en">
-<head>
-  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-  <meta name="robots" content="NONE,NOARCHIVE" />
-     <title>'.$o($desc).'</title>
-  <style type="text/css">
-    html * { padding:0; margin:0; }
-    body * { padding:10px 20px; }
-    body * * { padding:0; }
-    body { font:small sans-serif; background: #70DBFF; }
-    body>div { border-bottom:1px solid #ddd; }
-    h1 { font-weight:normal; }
-    h2 { margin-bottom:.8em; }
-    h2 span { font-size:80%; color:#666; font-weight:normal; }
-    h2 a { text-decoration:none; }
-    h3 { margin:1em 0 .5em 0; }
-    h4 { margin:0.5em 0 .5em 0; font-weight: normal; font-style: italic; }
-    table { 
-        border:1px solid #ccc; border-collapse: collapse; background:white; }
-    tbody td, tbody th { vertical-align:top; padding:2px 3px; }
-    thead th { 
-        padding:1px 6px 1px 3px; background:#70FF94; text-align:left; 
-        font-weight:bold; font-size:11px; border:1px solid #ddd; }
-    tbody th { text-align:right; color:#666; padding-right:.5em; }
-    table.vars { margin:5px 0 2px 40px; }
-    table.vars td, table.req td { font-family:monospace; }
-    table td { background: #70FFDB; }
-    table td.code { width:95%;}
-    table td.code div { overflow:hidden; }
-    table.source th { color:#666; }
-    table.source td { 
-        font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
-    ul.traceback { list-style-type:none; }
-    ul.traceback li.frame { margin-bottom:1em; }
-    div.context { margin:5px 0 2px 40px; background-color:#70FFDB; }
-    div.context ol { 
-        padding-left:30px; margin:0 10px; list-style-position: inside; }
-    div.context ol li { 
-        font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
-    div.context li.current-line { color:black; background-color:#70FF94; }
-    div.commands { margin-left: 40px; }
-    div.commands a { color:black; text-decoration:none; }
-    p.headers { background: #70FFDB; font-family:monospace; }
-    #summary { background: #00B8F5; }
-    #summary h2 { font-weight: normal; color: #666; }
-    #traceback { background:#eee; }
-    #request { background:#f6f6f6; }
-    #response { background:#eee; }
-    #summary table { border:none; background:#00B8F5; }
-    #summary td  { background:#00B8F5; }
-    .switch { text-decoration: none; }
-    .whitemsg { background:white; color:black;}
-  </style>
-  <script type="text/javascript">
-  //<!--
-    function getElementsByClassName(oElm, strTagName, strClassName){
-        // Written by Jonathan Snook, http://www.snook.ca/jon; 
-        // Add-ons by Robert Nyman, http://www.robertnyman.com
-        var arrElements = (strTagName == "*" && document.all)? document.all :
-        oElm.getElementsByTagName(strTagName);
-        var arrReturnElements = new Array();
-        strClassName = strClassName.replace(/\-/g, "\\-");
-        var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
-        var oElement;
-        for(var i=0; i<arrElements.length; i++){
-            oElement = arrElements[i];
-            if(oRegExp.test(oElement.className)){
-                arrReturnElements.push(oElement);
+    private $request, $exception, $desc;
+
+    public function __construct($request, $exception)
+    {
+        $this->request = $request;
+        $this->exception = $exception;
+        $this->desc = get_class($this->exception)." making ".$_SERVER['REQUEST_METHOD']." request to ".$_SERVER['REQUEST_URI'];
+    }
+
+    function html()
+    {
+        return "<!DOCTYPE html>\n" . Tag::create('html', array('lang' => 'en'),
+            Tag::head(null,
+                Tag::meta(array('charset' => 'utf-8')),
+                Tag::title(null, $this->desc),
+                $this->css(),
+                $this->js()),
+            Tag::body(null,
+                $this->Summary(),
+                $this->SectionStacktrace(),
+                $this->SectionRequest(),
+                $this->SectionResponse()));
+    }
+
+
+    function Summary()
+    {
+        $msg = $this->exception->getMessage();
+        if ($this->exception->getCode())
+            $msg = $this->exception->getCode(). ' : ' . $msg;
+
+        return Tag::div(array('id' => 'summary'),
+            Tag::h1(null, $this->desc),
+            Tag::h2(null, $msg),
+            Tag::table(null,
+                Tag::tr(null,
+                    Tag::th(null, 'PHP'),
+                    Tag::td(null, $this->exception->getFile().', line '.$this->exception->getLine())),
+                Tag::tr(null,
+                    Tag::th(null, 'URI'),
+                    Tag::td(null, $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI']))));
+    }
+
+
+    private function section($id, $title, $content)
+    {
+        return Tag::div(array('id' => $id, 'class' => 'section'))
+            ->append(Tag::h2()
+                ->append($title)
+                ->append(' ')
+                ->append(Tag::a(array('href' => '#', 'class' => 'section-toggle'))
+                    ->append(Tag::span(array('class' => 'section-switch'))->append('▶'))))
+            ->append(Tag::div(array('class' => 'section-body'))
+                ->append($content));
+    }
+
+
+    function SectionStacktrace()
+    {
+        return $this->section('traceback', 'Stacktrace',
+            $this->StacktraceFrames());
+    }
+
+    function StacktraceFrames()
+    {
+        $ul = Tag::ul(array('class' => 'traceback'));
+
+        $frames = $this->exception->getTrace();
+        foreach ($frames as $frame) {
+            if (!isset($frame['file'])) {
+                $frame['file'] = 'No File';
+                $frame['line'] = '0';
+            }
+            $name = '';
+            if (isset($frame["class"]))
+                $name .= $frame["class"].$frame["type"];
+            if (isset($frame["function"]))
+                $name .= $frame["function"];
+
+            $li = Tag::li(array('class' => 'frame'),
+                Tag::strong(null, $name),
+                ' ['.$frame['file'].', line '.$frame['line'].']');
+
+            if (isset($frame['args']) && count($frame['args']) > 0) {
+                $li->append($this->StacktraceArgs($frame));
+            }
+
+            if (is_readable($frame['file']) ) {
+                $li->append($this->StacktraceSourceFile($frame['file'], $frame['line']));
+            } else {
+                $li->append(Tag::div(array('class' => 'commands'), 'No src available'));
             }
+
+            $ul->append($li);
         }
-        return (arrReturnElements)
+        return $ul;
     }
-    function hideAll(elems) {
-      for (var e = 0; e < elems.length; e++) {
-        elems[e].style.display = \'none\';
-      }
+
+    function StacktraceArgs($frame)
+    {
+        $params = array();
+        if (isset($frame["function"])) {
+            if (isset($frame["class"])) {
+                $r = new ReflectionMethod($frame["class"]."::".$frame["function"]);
+            } else {
+                $r = new ReflectionFunction($frame["function"]);
+            }
+            $params = $r->getParameters();
+        }
+
+        $tbody = Tag::tbody();
+        foreach ($frame['args'] as $k => $v) {
+            $name = isset($params[$k]) ? '$'.$params[$k]->name : '?';
+            $tbody->append(Tag::tr(null,
+                Tag::td(null, $k),
+                Tag::td(null, $name),
+                Tag::td(array('class' => 'code'),
+                    Tag::div()->raw(highlight_string(debug_print_r($v), true)))));
+        }
+
+        return Tag::div(array('class' => 'section'),
+            Tag::div(array('class' => 'commands'),
+                Tag::a(array('href' => '#', 'class' => 'section-toggle'),
+                    Tag::span(array('class' => 'section-switch'), '▶'),
+                    ' Args')),
+            Tag::table(array('class' => 'section-body vars'),
+                Tag::thead(null,
+                    Tag::tr(null,
+                        Tag::th(null, 'Arg'),
+                        Tag::th(null, 'Name'),
+                        Tag::th(null, 'Value'))),
+                $tbody));
     }
-    function toggle() {
-      for (var i = 0; i < arguments.length; i++) {
-        var e = document.getElementById(arguments[i]);
-        if (e) {
-          e.style.display = e.style.display == \'none\' ? \'block\' : \'none\';
+
+    function StacktraceSourceFile($file, $line)
+    {
+        $start = max($line - 5, 0);
+        $ol = Tag::ol(array('start' => $start));
+
+        $rows = explode('<br />', nl2br(highlight_file($file, true)));
+        $rows = array_slice($rows, $start, 10);
+
+        foreach ($rows as $k => $row) {
+            $li = Tag::li(null, Tag::code()->raw($row));
+            if ($k + $start === $line)
+                $li->addClass('current-line');
+            $ol->append($li);
         }
-      }
-      return false;
+
+        return Tag::div(array('class' => 'section'),
+            Tag::div(array('class' => 'commands'),
+                Tag::a(array('href' => '#', 'class' => 'section-toggle'),
+                    Tag::span(array('class' => 'section-switch'), '▶'),
+                    ' Src')),
+            Tag::div(array('class' => 'section-body context'),
+                $ol));
     }
-    function varToggle(link, id, prefix) {
-      toggle(prefix + id);
-      var s = link.getElementsByTagName(\'span\')[0];
-      var uarr = String.fromCharCode(0x25b6);
-      var darr = String.fromCharCode(0x25bc);
-      s.innerHTML = s.innerHTML == uarr ? darr : uarr;
-      return false;
+
+
+    function SectionRequest()
+    {
+        return $this->section('request', 'Request', array(
+            $this->RequestRaw(),
+
+            Tag::h3(null, 'Request <span>(parsed)</span>'),
+            Tag::h4(null, '$_GET'),
+            $this->RequestSuperlobal($_GET),
+
+            Tag::h4(null, '$_POST'),
+            $this->RequestSuperlobal($_POST),
+
+            Tag::h4(null, '$_COOKIE'),
+            $this->RequestSuperlobal($_COOKIE),
+
+            Tag::h4(null, '$_SERVER'),
+            $this->RequestSuperlobal($_SERVER),
+
+            Tag::h4(null, '$_ENV'),
+            $this->RequestSuperlobal($_ENV),
+        ));
     }
-    function sectionToggle(span, section) {
-      toggle(section);
-      var span = document.getElementById(span);
-      var uarr = String.fromCharCode(0x25b6);
-      var darr = String.fromCharCode(0x25bc);
-      span.innerHTML = span.innerHTML == uarr ? darr : uarr;
-      return false;
+
+
+    function RequestRaw()
+    {
+        return array(
+            Tag::h3(null, 'Request ', Tag::span('(raw)')),
+            $this->RequestRawHeaders(),
+            $this->RequestRawBody(),
+        );
     }
-    
-    window.onload = function() {
-      hideAll(getElementsByClassName(document, \'table\', \'vars\'));
-      hideAll(getElementsByClassName(document, \'div\', \'context\'));
-      hideAll(getElementsByClassName(document, \'ul\', \'traceback\'));
-      hideAll(getElementsByClassName(document, \'div\', \'section\'));
+
+    function RequestRawHeaders()
+    {
+        $r = array(
+            Tag::h4('Headers'),
+        );
+        $headers = $this->request->getHeaders();
+        if ($headers) {
+            $h = Tag::p(array('class' => 'headers'));
+            foreach ($headers as $name => $val) {
+                $h->append($name.': '.$val)->append(Tag::br());
+            }
+            $r[] = $h;
+        } else {
+            $r[] = Tag::p(null, 'No headers.');
+        }
+        return $r;
     }
-    //-->
-  </script>
-</head>
-<body>
-
-<div id="summary">
-  <h1>'.$o($desc).'</h1>
-  <h2>';
-    if ($e->getCode()) { 
-        $out .= $o($e->getCode()). ' : '; 
+
+    function RequestRawBody()
+    {
+        $body = $this->request->getBody();
+        if (!$body)
+            return '';
+
+        return array(
+            Tag::h4('Body'),
+            Tag::p(array('class' => 'req', 'style' => 'padding-bottom: 2em'),
+                Tag::code(null, $body)),
+        );
     }
-    $out .= ' '.$o($e->getMessage()).'</h2>
-  <table>
-    <tr>
-      <th>PHP</th>
-      <td>'.$o($e->getFile()).', line '.$o($e->getLine()).'</td>
-    </tr>
-    <tr>
-      <th>URI</th>
-      <td>'.$o($_SERVER['REQUEST_METHOD'].' '.
-        $_SERVER['REQUEST_URI']).'</td>
-    </tr>
-  </table>
-</div>
-
-<div id="traceback">
-  <h2>Stacktrace
-    <a href=\'#\' onclick="return sectionToggle(\'tb_switch\',\'tb_list\')">
-    <span id="tb_switch">▶</span></a></h2>
-  <ul id="tb_list" class="traceback">';
-    $frames = $e->getTrace(); 
-    foreach ($frames as $frame_id=>$frame) { 
-        if (!isset($frame['file'])) {
-            $frame['file'] = 'No File';
-            $frame['line'] = '0';
-        }
-        $out .= '<li class="frame">'.$sub($frame).'
-        ['.$o($frame['file']).', line '.$o($frame['line']).']';
-        if (isset($frame['args']) && count($frame['args']) > 0) {
-            $params = $parms($frame);
-            $out .= '
-          <div class="commands">
-              <a href=\'#\' onclick="return varToggle(this, \''.
-              $o($frame_id).'\',\'v\')"><span>▶</span> Args</a>
-          </div>
-          <table class="vars" id="v'.$o($frame_id).'">
-            <thead>
-              <tr>
-                <th>Arg</th>
-                <th>Name</th>
-                <th>Value</th>
-              </tr>
-            </thead>
-            <tbody>';
-            foreach ($frame['args'] as $k => $v) {
-                $name = isset($params[$k]) ? '$'.$params[$k]->name : '?';
-                $out .= '
-                <tr>
-                  <td>'.$o($k).'</td>
-                  <td>'.$o($name).'</td>
-                  <td class="code">
-                    <div>'.highlight_string(debug_print_r($v), true).'</div>
-                  </td>
-                </tr>';
-            }
-            $out .= '</tbody></table>';
-        } 
-        if (is_readable($frame['file']) ) { 
-            $out .= '
-        <div class="commands">
-            <a href=\'#\' onclick="return varToggle(this, \''
-                .$o($frame_id).'\',\'c\')"><span>▶</span> Src</a>
-        </div>
-        <div class="context" id="c'.$o($frame_id).'">';
-            $lines = $src2lines($frame['file']);
-            $start = $frame['line'] < 5 ?
-                0 : $frame['line'] -5; $end = $start + 10;
-            $out2 = '';
-            foreach ( $lines as $k => $line ) {
-                if ( $k > $end ) { break; }
-                $line = trim(strip_tags($line));
-                if ( $k < $start && isset($frames[$frame_id+1]["function"])
-                     && preg_match('/function( )*'.preg_quote($frames[$frame_id+1]["function"]).'/',
-                                   $line) ) {
-                    $start = $k;
-                }
-                if ( $k >= $start ) {
-                    if ( $k != $frame['line'] ) {
-                $out2 .= '<li><code>'.$clean($line).'</code></li>'."\n"; }
-              else {
-                $out2 .= '<li class="current-line"><code>'.
-                  $clean($line).'</code></li>'."\n"; }
-            }
-          }
-            $out .= "<ol start=\"$start\">\n".$out2. "</ol>\n";
-            $out .= '</div>';
-        } else { 
-            $out .= '<div class="commands">No src available</div>';
-        } 
-        $out .= '</li>';
-    } 
-    $out .= '
-  </ul>
-  
-</div>
-
-<div id="request">
-  <h2>Request
-    <a href=\'#\' onclick="return sectionToggle(\'req_switch\',\'req_list\')">
-    <span id="req_switch">▶</span></a></h2>
-  <div id="req_list" class="section">';
-    if ( function_exists('apache_request_headers') ) {
-        $out .= '<h3>Request <span>(raw)</span></h3>';
-        $req_headers = apache_request_headers();
-        $out .= '<h4>HEADERS</h4>';
-        if ( count($req_headers) > 0 ) {
-            $out .= '<p class="headers">';
-            foreach ($req_headers as $req_h_name => $req_h_val) {
-                $out .= $o($req_h_name.': '.$req_h_val);
-                $out .=  '<br>';
-            }
-            $out .= '</p>';
-        } else { 
-            $out .= '<p>No headers.</p>';
-        } 
-        $req_body = file_get_contents('php://input');
-        if ( strlen( $req_body ) > 0 ) {
-            $out .='
-      <h4>Body</h4>
-      <p class="req" style="padding-bottom: 2em"><code>
-       '.$o($req_body).'
-      </code></p>';
-        } 
-    } 
-    $out .= '
-    <h3>Request <span>(parsed)</span></h3>';
-    $superglobals = array('$_GET','$_POST','$_COOKIE','$_SERVER','$_ENV');
-    foreach ( $superglobals as $sglobal ) {
-        $sfn = create_function('','return '.$sglobal.';');
-        $out .= '<h4>'.$sglobal.'</h4>';
-        if ( count($sfn()) > 0 ) {
-            $out .= '
-      <table class="req">
-        <thead>
-          <tr>
-            <th>Variable</th>
-            <th>Value</th>
-          </tr>
-        </thead>
-        <tbody>';
-            foreach ( $sfn() as $k => $v ) {
-                $out .= '<tr>
-              <td>'.$o($k).'</td>
-              <td class="code">
-                <div>'.$o(print_r($v,TRUE)).'</div>
-                </td>
-            </tr>';
+
+
+    function RequestSuperlobal($var)
+    {
+        if (count($var)) {
+            $table = Tag::table(array('class' => 'req'));
+
+            $thead = Tag::thead()
+                ->append(Tag::tr()
+                    ->append(Tag::th(null, 'Variable'))
+                    ->append(Tag::th(null, 'Value')));
+
+            $tbody = Tag::tbody();
+            foreach ($var as $k => $v) {
+                $tbody->append(Tag::tr()
+                    ->append(Tag::td()
+                        ->append($k))
+                    ->append(Tag::td(array('class' => 'code'))
+                        ->append(Tag::div()->append(print_r($v, true)))));
             }
-            $out .= '
-        </tbody>
-      </table>';
-        } else { 
-            $out .= '
-      <p class="whitemsg">No data</p>';
-        } 
-    } 
-    $out .= '
-      
-  </div>
-</div>';
-    if ( function_exists('headers_list') ) { 
-        $out .= '
-<div id="response">
-
-  <h2>Response
-    <a href=\'#\' onclick="return sectionToggle(\'resp_switch\',\'resp_list\')">
-    <span id="resp_switch">▶</span></a></h2>
-  
-  <div id="resp_list" class="section">
-
-    <h3>Headers</h3>';
-        $resp_headers = headers_list();
-        if (count($resp_headers) > 0) {
-            $out .= '
-    <p class="headers">';
-            foreach ( $resp_headers as $resp_h ) {
-                $out .= $o($resp_h);
-                $out .= '<br>';
+
+            return $table->append($thead)->append($tbody);
+        } else {
+            return Tag::p(array('class' => 'whitemsg'), 'No data');
+        }
+    }
+
+
+    function SectionResponse()
+    {
+        return $this->section('response', 'Response',
+            $this->ResponseHeaders());
+    }
+
+    function ResponseHeaders()
+    {
+        $r = array(
+            Tag::h3('Headers'),
+        );
+        $headers = headers_list();
+        if ($headers) {
+            $h = Tag::p(array('class' => 'headers'));
+            foreach ($headers as $header) {
+                $h->append($header)->append(Tag::br());
             }
-            $out .= '    </p>';
+            $r[] = $h;
         } else {
-            $out .= '
-      <p>No headers.</p>';
-        } 
-        $out .= '
-</div>';
-    } 
-    $out .= '
-</body>
-</html>
-';
-    return $out;
+            $r[] = Tag::p(null, 'No headers.');
+        }
+        return $r;
+    }
+
+
+    function css()
+    {
+        return Tag::style()->raw('html * { padding:0; margin:0; }
+body * { padding:10px 20px; }
+body * * { padding:0; }
+body { font:small sans-serif; background: #70DBFF; }
+body>div { border-bottom:1px solid #ddd; }
+h1 { font-weight:normal; }
+h2 { margin-bottom:.8em; }
+h2 span { font-size:80%; color:#666; font-weight:normal; }
+h2 a { text-decoration:none; }
+h3 { margin:1em 0 .5em 0; }
+h4 { margin:0.5em 0 .5em 0; font-weight: normal; font-style: italic; }
+table { border:1px solid #ccc; border-collapse: collapse; background:white; }
+tbody td, tbody th { vertical-align:top; padding:2px 3px; }
+thead th { padding:1px 6px 1px 3px; background:#70FF94; text-align:left; font-weight:bold; font-size:11px; border:1px solid #ddd; }
+tbody th { text-align:right; color:#666; padding-right:.5em; }
+.vars table { margin:5px 0 2px 40px; }
+.vars table td, table.req td { font-family:monospace; }
+table td { background: #70FFDB; }
+table td.code { width:95%;}
+table td.code div { overflow:hidden; }
+table.source th { color:#666; }
+table.source td {  font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
+ul.traceback { list-style-type:none; }
+ul.traceback li.frame { margin-bottom:1em; }
+div.context { margin:5px 0 2px 40px; background: #fff; border: 1px dashed #666; }
+div.context ol {  padding-left:10px; margin:0 10px; list-style-position: inside; }
+div.context ol li { font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
+div.context li.current-line { color:black; background-color:#70FF94; }
+div.commands { margin-left: 40px; }
+div.commands a { color:black; text-decoration:none; }
+p.headers { background: #70FFDB; font-family:monospace; padding: 2px; }
+#summary { background: #00B8F5; }
+#summary h2 { font-weight: normal; color: #666; }
+#traceback { background:#eee; }
+#request { background:#f6f6f6; }
+#response { background:#eee; }
+#summary table { border:none; background:#00B8F5; }
+#summary td  { background:#00B8F5; }
+.switch { text-decoration: none; }
+.whitemsg { background:white; color:black;}');
+    }
+
+    function js()
+    {
+        return Tag::script()->raw('
+window.onload = function() {
+  function onClick(e, c) {
+    var args = Array.prototype.slice.call(arguments, 2);
+    if (e.addEventListener)
+      e.addEventListener("click", function(ev) { c.apply(this, args); ev.preventDefault(); }, false);
+    else
+      e.attachEvent("onclick", function(ev) { c.apply(this, args); ev.returnValue = false; });
+  }
+
+  var i, bd, sections = document.querySelectorAll(".section");
+  for (i = 0; i < sections.length; ++i) {
+    bd = sections[i].querySelector(".section-body");
+    bd.style.display = \'none\';
+    onClick(sections[i].querySelector(".section-toggle"), function (sw, bd) {
+        bd.style.display = bd.style.display == \'none\' ? \'block\' : \'none\';
+
+        var uarr = String.fromCharCode(0x25b6);
+        var darr = String.fromCharCode(0x25bc);
+        sw.innerHTML = sw.innerHTML == uarr ? darr : uarr;
+      },
+      sections[i].querySelector(".section-switch"),
+      bd);
+  }
+}');
+    }
 }
 
index be683a5089d9a83a3ac87808378d9bdac7779203..9bf5e52f812ef8bef0113341f3ca302d49595f98 100644 (file)
@@ -544,4 +544,13 @@ class IPF_ORM_Collection extends IPF_ORM_Access implements Countable, IteratorAg
     {
         return $this->relation;
     }
+
+    public function __debugInfo()
+    {
+        $r = array();
+        foreach ($this->data as $item)
+            $r[] = $item;
+        return $r;
+    }
 }
+
index bf143d024db26e157f9c60f9d5fd591b8eb3c7cf..744f44e16db96fb1235f066dff16b60c467a2329 100644 (file)
@@ -252,4 +252,14 @@ class IPF_ORM_Pager
         }
         return $this->getQuery()->execute($params, $hydrationMode);
     }
-}
\ No newline at end of file
+
+    public function __debugInfo()
+    {
+        return array(
+            'page' => $this->getPage(),
+            'size' => $this->getMaxPerPage(),
+            'query' => $this->getQuery(),
+        );
+    }
+}
+
index 1d83ebb7314e03108a7f0658f21a77bf1f4fcd9d..a5c1a32b74aed32e1f0854aa7acf62e5a094965a 100644 (file)
@@ -225,4 +225,12 @@ class IPF_ORM_Pager_Layout
 
         return strtr($str, $replacements);
     }
+
+    public function __debugInfo()
+    {
+        return array(
+            'pager' => $this->getPager()
+        );
+    }
 }
+
index 025ac448d2bb20518d1daf77d38070abf81a4e1d..6e0f48ac2723e7f5bc75aef814181b652443f6ec 100644 (file)
@@ -989,4 +989,10 @@ abstract class IPF_ORM_Query_Abstract
     {
         return $this->getSqlQuery($params);
     }
+
+    public function __debugInfo()
+    {
+        return array('sql' => $this->getQuery());
+    }
 }
+
index 3d9a91a2481ecdb74b268484c223586038997e96..07aab0d0ade0eeab6cfd9cefc7b48035ce6e61f5 100644 (file)
@@ -48,5 +48,13 @@ abstract class IPF_ORM_Record_Abstract extends IPF_ORM_Access
         }
         return $this;
     }
+
+    public function __debugInfo()
+    {
+        $r = array();
+        foreach ($this->getTable()->getColumnNames() as $column)
+            $r[$column] = $this->get($column);
+        return $r;
+    }
 }
 
index ffe2dacb50dc4266dcf9f9c3a91fcdb701c77948..2c85ab5fab9cca0e101d21d34417a93d29c81119 100644 (file)
@@ -24,13 +24,13 @@ class IPF_Router
         }
     }
 
-    public static function response500($e)
+    public static function response500($request, $exception)
     {
-        error_log($e);
+        error_log($exception);
         if (IPF::get('debug'))
-            return new IPF_HTTP_Response_ServerErrorDebug($e);
+            return new IPF_HTTP_Response_ServerErrorDebug($request, $exception);
         else
-            return new IPF_HTTP_Response_ServerError($e);
+            return new IPF_HTTP_Response_ServerError($request, $exception);
     }
 
     public function dispatch($req)
@@ -68,7 +68,7 @@ class IPF_Router
             }
             return array($req, $response);
         } catch (IPF_Exception $e) {
-            $response = self::response500($e);
+            $response = self::response500($req, $e);
             $response->render();
         }
    }
@@ -88,13 +88,13 @@ class IPF_Router
             try {
                 $r = IPF::callFunction($func, array($req, $match));
                 if (!is_a($r, 'IPF_HTTP_Response')) {
-                    return self::response500(new IPF_Exception('function '.$func.'() must return IPF_HTTP_Response instance'));
+                    return self::response500($req, new IPF_Exception('function '.$func.'() must return IPF_HTTP_Response instance'));
                 }
                 return $r;
             } catch (IPF_HTTP_Error404 $e) {
                 return new IPF_HTTP_Response_NotFound($req);
             } catch (IPF_Exception $e) {
-                return self::response500($e);
+                return self::response500($req, $e);
             }
         }