bkdotcom/PHPDebugConsole

View on GitHub
src/Debug/Route/Script.php

Summary

Maintainability
A
25 mins
Test Coverage
A
95%
<?php

/**
 * This file is part of PHPDebugConsole
 *
 * @package   PHPDebugConsole
 * @author    Brad Kent <bkfake-github@yahoo.com>
 * @license   http://opensource.org/licenses/MIT MIT
 * @copyright 2014-2024 Brad Kent
 * @version   v3.0
 */

namespace bdk\Debug\Route;

use bdk\Debug;
use bdk\Debug\Abstraction\Abstracter;
use bdk\Debug\Abstraction\Type;
use bdk\Debug\LogEntry;
use bdk\PubSub\Event;

/**
 * Output log as <script> tag
 */
class Script extends AbstractRoute
{
    /** @var array<string, mixed> */
    protected $cfg = array(
        'channels' => array('*'),
        'channelsExclude' => array(
            'events',
            'files',
        ),
    );

    /** @var list<string> */
    protected $consoleMethods = array(
        'assert',
        // 'count',    // output as log
        'error',
        'group',
        'groupCollapsed',
        'groupEnd',
        'info',
        'log',
        'table',
        // 'time',     // output as log
        'timeEnd',  // PHPDebugConsole never generates a timeEnd entry
        'trace',
        'warn',
    );

    /**
     * Constructor
     *
     * @param Debug $debug debug instance
     */
    public function __construct(Debug $debug)
    {
        parent::__construct($debug);
        $this->dumper = $debug->getDump('base');
    }

    /**
     * output the log as javascript
     *    which outputs the log to the console
     *
     * @param Event $event Debug::EVENT_OUTPUT event object
     *
     * @return string|void
     */
    public function processlogEntries(Event $event)
    {
        $this->dumper->crateRaw = false;
        $this->data = $this->debug->data->get();
        $str = '<script>' . "\n";
        $str .= $this->processLogEntryViaEvent(new LogEntry(
            $this->debug,
            'groupCollapsed',
            array(
                'PHP',
                $this->getRequestMethodUri(),
                $this->getErrorSummary(),
            )
        ));
        $str .= $this->processAlerts();
        $str .= $this->processSummary();
        $str .= $this->processLog();
        $str .= $this->processLogEntryViaEvent(new LogEntry(
            $this->debug,
            'groupEnd'
        ));
        $str .= '</script>' . "\n";
        $this->data = array();
        $event['return'] .= $str;
        $this->dumper->crateRaw = true;
    }

    /**
     * Return log entry as javascript console.xxxx
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return string
     */
    public function processLogEntry(LogEntry $logEntry)
    {
        $method = $logEntry['method'];
        if (\in_array($method, array('table', 'trace'), true)) {
            $logEntry->setMeta(array(
                'forceArray' => false,
                'undefinedAs' => Abstracter::UNDEFINED,
            ));
        }
        $this->dumper->processLogEntry($logEntry);
        $str = $this->buildConsoleCall($logEntry);
        $str = \str_replace(
            array(
                // ensure that </script> doesn't appear inside our <script>
                '</script>',
                \json_encode(Type::TYPE_FLOAT_INF),
                \json_encode(Type::TYPE_FLOAT_NAN),
                \json_encode(Abstracter::UNDEFINED),
            ),
            array(
                '<\\/script>',
                'Infinity',
                'NaN',
                'undefined',
            ),
            $str
        );
        return $str;
    }

    /**
     * Build the console.xxxx() call
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return string
     */
    protected function buildConsoleCall(LogEntry $logEntry)
    {
        $method = $logEntry['method'];
        $args = $logEntry['args'];
        $meta = $logEntry['meta'];
        switch ($method) {
            case 'assert':
                \array_unshift($args, false);
                break;
            case 'error':
            case 'warn':
                if (isset($meta['file'])) {
                    $args[] = \sprintf('%s: line %s', $meta['file'], $meta['line']);
                }
                break;
            case 'table':
                $args = $this->dumper->valDumper->dump($args);
                break;
            default:
                if (\in_array($method, $this->consoleMethods, true) === false) {
                    $method = 'log';
                }
        }
        $args = \json_encode($args, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        $args = \substr($args, 1, -1);
        return 'console.' . $method . '(' . $args . ');' . "\n";
    }

    /**
     * Get number of errors per category
     *
     * @return string
     */
    private function getErrorSummary()
    {
        $errorStats = $this->debug->errorStats();
        $errorStr = '';
        if ($errorStats['inConsole']) {
            $errorStr = 'Errors: ';
            foreach ($errorStats['counts'] as $category => $vals) {
                $errorStr .= $vals['inConsole'] . ' ' . $category . ', ';
            }
            $errorStr = \substr($errorStr, 0, -2);
        }
        return $errorStr;
    }
}