/** * @param string $className The name of a class that implements {@see ComponentPropertiesInterface} * @throws ReflectionException */ function __construct($className) { if (!implementsInterface($className, ComponentPropertiesInterface::class)) { throw new ReflectionException("Class %s does not implement %s", Debug::formatClassName($className), Debug::formatClassName(ComponentPropertiesInterface::class)); } $this->name = $className; }
/** * Performs the main execution sequence. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * @return ResponseInterface * @throws FatalException * @throws FileException * @throws FlashMessageException */ function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { $this->request = $request; $this->response = $response; $this->initialize(); //custom setup $this->model(); switch ($this->request->getMethod()) { /** @noinspection PhpMissingBreakStatementInspection */ case 'POST': // Perform the requested action. $res = $this->doFormAction(); if ($res) { if ($res instanceof ResponseInterface) { throw new FatalException(sprintf("Invalid HTTP response type: %s<p>Expected: <kbd>ResponseInterface</kbd>", Debug::typeInfoOf($res))); } $response = $res; } if (!$this->renderOnAction) { if (!$res) { $response = $this->autoRedirect(); } break; } case 'GET': // Render the component. $out = $this->getRendering(); $response->getBody()->write($out); } $this->finalize($response); return $response; }
/** * @param string|Component[] $content * @return Component[] */ private static function checkContent($content) { if (!is_array($content) && !is_string($content)) { throw new \InvalidArgumentException(sprintf("Block content must be <kbd>string|Component[]</kbd>, %s given", Debug::typeInfoOf($content))); } return $content; }
function inspect() { $VMFilter = function ($k, $v, $o) { if ($v instanceof KernelSettings || $v instanceof NavigationInterface || $v instanceof NavigationLinkInterface || $v instanceof SessionInterface || $v instanceof ServerRequestInterface || $v instanceof DocumentContext || $v instanceof Component) { return '...'; } return true; }; return _log()->getTable([Debug::getType($this->viewModel) => Debug::RAW_TEXT . _log()->getTable($this->viewModel, '', true, true, 2, $VMFilter), is_null($this->props) ? 'Properties' : Debug::getType($this->props) => Debug::RAW_TEXT . _log()->getTable($this->props, '', true, true, 1, ['props', 'component', 'hidden'])], Debug::getType($this)); }
function __construct($s) { if (is_null($s)) { $this->s = ''; } elseif ($s instanceof RenderableInterface) { $this->s = $s->getRendering(); return; } elseif (!is_string($s)) { throw new MatisseException("A <kbd>RawText</kbd> instance must hold a string value, not a " . Debug::typeInfoOf($s)); } $this->s = $s; }
function __call($name, $args) { $method = "filter_{$name}"; if (isset($this->filters[$method])) { return call_user_func_array($this->filters[$method], $args); } if (isset($this->fallbackHandler)) { if (method_exists($this->fallbackHandler, $method)) { return call_user_func_array([$this->fallbackHandler, $method], $args); } } throw new FilterHandlerNotFoundException(sprintf("<p><p>Handler method: <kbd>%s</kbd><p>Arguments: <kbd>%s</kbd>", $method, print_r(map($args, function ($e) { return Debug::typeInfoOf($e); }), true))); }
/** * For internal use. * * @param Component $component * @param bool $deep * @throws ComponentException */ private static function _inspect(Component $component, $deep = true) { if (self::$recursionMap->contains($component)) { echo "<i>recursion</i>"; return; } self::$recursionMap->attach($component); $COLOR_BIND = '#5AA'; $COLOR_CONST = '#5A5'; $COLOR_INFO = '#CCC'; $COLOR_PROP = '#B00'; $COLOR_TAG = '#000;font-weight:bold'; $COLOR_TYPE = '#55A'; $COLOR_VALUE = '#333'; $COLOR_SHADOW_DOM = '#5AA;font-weight:bold'; $Q = "<i style='color:#CCC'>\"</i>"; $tag = $component->getTagName(); $hasContent = false; echo "<div class=__component><span style='color:{$COLOR_TAG}'><{$tag}</span>"; $isDoc = $component instanceof DocumentFragment; if (!$component->parent && !$isDoc) { echo " <span style='color:{$COLOR_INFO}'>(detached)</span>"; } $type = typeOf($component) . ' #' . Debug::objectId($component); echo "<span class='icon hint--rounded hint--right' data-hint='Component:\n{$type}'><i class='fa fa-info-circle'></i></span>"; $type1 = str_pad('#' . Debug::objectId($component->context), 4, ' ', STR_PAD_LEFT); $type2 = str_pad('#' . Debug::objectId($component->getDataBinder()), 4, ' ', STR_PAD_LEFT); $type3 = str_pad('#' . Debug::objectId($component->getViewModel()), 4, ' ', STR_PAD_LEFT); $type4 = str_pad('#' . Debug::objectId($component->getDataBinder()->getViewModel()), 4, ' ', STR_PAD_LEFT); $type5 = str_pad('#' . Debug::objectId($component->getDataBinder()->getProps()), 4, ' ', STR_PAD_LEFT); echo "<span class='icon hint--rounded hint--bottom' data-hint='Context: {$type1} Data binder: {$type2}\nView model: {$type3} Binder view model: {$type4}\nProperties: {$type5}'><i class='fa fa-database'></i></span>"; // Handle text node if ($component instanceof Text) { echo "<span style='color:{$COLOR_TAG}'>></span><div style='margin:0 0 0 15px'>"; try { if ($component->isBound('value')) { /** @var Expression $exp */ $exp = $component->getBinding('value'); $exp = self::inspectString((string) $exp); echo "<span style='color:{$COLOR_BIND}'>{$exp}</span> = "; $v = self::getBindingValue('value', $component, $error); if ($error) { echo $v; return; } if (!is_string($v)) { echo Debug::typeInfoOf($v); return; } } else { $v = $component->props->value; } $v = strlen(trim($v)) ? HtmlSyntaxHighlighter::highlight($v) : "<i>'{$v}'</i>"; echo $v; } finally { echo "</div><span style='color:{$COLOR_TAG}'></{$tag}><br></span></div>"; } return; } // Handle other node types if ($component instanceof DocumentFragment) { self::inspectViewModel($component); } if ($component->supportsProperties()) { /** @var ComponentProperties $propsObj */ $propsObj = $component->props; if ($propsObj) { $props = $propsObj->getAll(); } else { $props = null; } if ($props) { ksort($props); } if ($props) { $type = typeOf($propsObj); $tid = Debug::objectId($propsObj); echo "<span class='icon hint--rounded hint--right' data-hint='Properties: #{$tid}\n{$type}'><i class='fa fa-list'></i></span>"; echo "<table class='__console-table' style='color:{$COLOR_VALUE}'>"; // Display all scalar properties. foreach ($props as $k => $v) { $t = $component->props->getTypeOf($k); $isModified = $component->props->isModified($k); $modifStyle = $isModified ? ' class=__modified' : ' class=__original'; if ($t != type::content && $t != type::collection && $t != type::metadata) { $tn = $component->props->getTypeNameOf($k); echo "<tr{$modifStyle}><td style='color:{$COLOR_PROP}'>{$k}<td><i style='color:{$COLOR_TYPE}'>{$tn}</i><td>"; // Display data-binding if ($component->isBound($k)) { /** @var Expression $exp */ $exp = $component->getBinding($k); $exp = self::inspectString((string) $exp); echo "<span style='color:{$COLOR_BIND}'>{$exp}</span> = "; $v = self::getBindingValue($k, $component, $error); if ($error) { break; } } if (is_null($v)) { echo "<i style='color:{$COLOR_INFO}'>null</i>"; } else { switch ($t) { case type::bool: echo "<i style='color:{$COLOR_CONST}'>" . ($v ? 'true' : 'false') . '</i>'; break; case type::id: echo "{$Q}{$v}{$Q}"; break; case type::number: echo $v; break; case type::string: echo "{$Q}<span style='white-space: pre-wrap'>" . self::inspectString(strval($v)) . "</span>{$Q}"; break; default: if (is_object($v)) { echo sprintf("<i style='color:{$COLOR_CONST}'>%s</i>", Debug::typeInfoOf($v)); } elseif (is_array($v)) { echo sprintf("<i style='color:{$COLOR_CONST}'>array(%d)</i>", count($v)); } else { $v = _e($v); echo "{$Q}{$v}{$Q}"; } } } } } // Display all slot properties. foreach ($props as $k => $v) { $t = $component->props->getTypeOf($k); if ($t == type::content || $t == type::collection || $t == type::metadata) { $tn = $component->props->getTypeNameOf($k); $isModified = $component->props->isModified($k); $modifStyle = $isModified ? ' style="background:#FFE"' : ' style="opacity:0.5"'; echo "<tr{$modifStyle}><td style='color:{$COLOR_PROP}'>{$k}<td><i style='color:{$COLOR_TYPE}'>{$tn}</i><td>"; /** @var Expression $exp */ $exp = $component->getBinding($k); if (isset($exp)) { $exp = self::inspectString((string) $exp); echo "<span style='color:{$COLOR_BIND}'>{$exp}</span> = "; $v = self::getBindingValue($k, $component, $error); if ($error) { echo $v; break; } } if ($v && ($v instanceof Component || is_array($v))) { switch ($t) { case type::content: if ($v) { echo "<tr><td><td colspan=2>"; self::_inspect($v, $deep); } else { echo "<i style='color:{$COLOR_INFO}'>null</i>"; } break; case type::metadata: if ($v) { echo "<tr><td><td colspan=2>"; self::_inspect($v, $deep); } else { echo "<i style='color:{$COLOR_INFO}'>null</i>"; } break; case type::collection: echo "of <i style='color:{$COLOR_TYPE}'>", $component->props->getRelatedTypeNameOf($k), '</i>'; if ($v) { echo "<tr><td><td colspan=2>"; self::_inspectSet($v, true); } else { echo " = <i style='color:{$COLOR_INFO}'>[]</i>"; } break; } } else { if (is_array($v)) { echo "<i style='color:{$COLOR_INFO}'>[]</i>"; } else { if (isset($v)) { printf("<b style='color:red'>WRONG TYPE: %s</b>", Debug::typeInfoOf($v)); } else { echo "<i style='color:{$COLOR_INFO}'>null</i>"; } } } echo '</tr>'; } } echo "</table>"; } } // If deep inspection is enabled, recursively inspect all children components. if ($deep) { $content = $shadowDOM = null; if ($component->hasChildren()) { $content = $component->getChildren(); } if ($component instanceof CompositeComponent) { $shadowDOM = $component->provideShadowDOM(); } if ($content || $shadowDOM) { echo "<span style='color:{$COLOR_TAG}'>></span><div style=\"margin:0 0 0 15px\">"; if ($content) { self::_inspectSet($content, $deep); } if ($shadowDOM) { echo "<span style='color:{$COLOR_SHADOW_DOM}'><Shadow DOM></span><div style=\"margin:0 0 0 15px\">"; self::_inspect($shadowDOM, $deep); echo "</div><span style='color:{$COLOR_SHADOW_DOM}'></Shadow DOM></span>"; } echo '</div>'; $hasContent = true; } } echo "<span style='color:{$COLOR_TAG}'>" . ($hasContent ? "</{$tag}><br>" : "/><br>") . "</span></div>"; }
/** * Throws an exception if the specified property is not available. * * @param $propName * @throws ComponentException */ function ensurePropertyExists($propName) { if (!$this->defines($propName)) { throw new ComponentException($this->component, sprintf("Invalid property <kbd>%s</kbd> specified for a %s instance.", $propName, Debug::typeInfoOf($this))); } }
/** * ReflectionPropertyException constructor. * @param string $className * @param string $propertyName * @param string $message * @param array ...$args */ public function __construct($className, $propertyName, $message, ...$args) { array_push($args, Debug::formatClassName($className), $propertyName); parent::__construct(sprintf("{$message}.<p>Property %s-><kbd>%s</kbd>.", ...$args)); }
private function assertContext() { if (!$this->context) { throw new ComponentException($this, sprintf("Can't render the component's template because the rendering context is not set.\n<p>See <kbd>%s</kbd>", Debug::formatClassName(RenderableInterface::class))); } }
/** * @param mixed $val The value to be inspected. * @param mixed $alt If not null, a replacement for inspection; type information about $val is displayed but the * inspection is performed on this argument instead. * @return string */ private function getInspection2($val, $alt = null) { $arg = $this->table(isset($alt) ? $alt : $val); if (is_scalar($val) || is_null($val)) { $arg = '<i>(' . Debug::getType($val) . ")</i>{$arg}"; return "<#data>{$arg}</#data>"; } if ($val instanceof \PowerString) { return Debug::toString($val); } return $this->formatType($val, $arg); }
/** * @param \Exception $exception * @return string */ private static function getStackTrace($exception) { ob_start(); // $trace = self::filterStackTrace ($exception instanceof PHPError ? debug_backtrace () : $exception->getTrace ()); $trace = $exception->getTrace(); if (count($trace) && $trace[count($trace) - 1]['function'] == '{main}') { array_pop($trace); } $count = count($trace); foreach ($trace as $k => $v) { $class = isset($v['class']) ? $v['class'] : ''; if ($class == 'ErrorHandler') { continue; } //$class = $class ? "<span class='class'>$class</span>" : ''; if (isset($v['function'])) { $f = $v['function']; $type = isset($v['type']) ? $v['type'] : '->'; if (strpos($f, '{closure}') !== false) { if ($class) { $fn = "<span class='info' title='On class {$class}'>Closure</span>"; } else { $fn = "<span class='type'>Closure</span>"; } } else { if ($class) { $z = explode('\\', $class); $className = array_pop($z); $namespace = implode('\\', $z); $fn = $f == '__construct' ? "new <span class='class' title='{$namespace}'>{$className}</span>" : "<span class='class' title='{$namespace}'>{$className}</span>{$type}<span class='fn'>{$f}</span>"; } else { $fn = "<span class='fn'>{$f}</span>"; } } $fn = "Call {$fn}"; } else { $fn = 'global scope'; } if (isset($v['function'])) { $args = []; if (isset($v['args'])) { foreach ($v['args'] as $arg) { switch (gettype($arg)) { case 'boolean': $arg = $arg ? 'true' : 'false'; break; case 'string': $arg = mb_strlen($arg) > self::TRIM_WIDTH ? sprintf("'<span class='string hint--rounded hint--top' data-hint='%s'>%s</span>'", htmlspecialchars(mb_strimwidth(chunk_split($arg, self::TRIM_WIDTH, "\n"), 0, self::TOOLTIP_MAX_LEN, "..."), ENT_QUOTES), htmlspecialchars(mb_strimwidth($arg, 0, self::TRIM_WIDTH, "..."))) : sprintf("'<span class='string'>%s</span>'", htmlspecialchars($arg, ENT_QUOTES)); break; case 'integer': case 'double': break; case 'array': $arg = '<span class="info __type hint--rounded hint--top" data-hint="' . ($arg ? "[\n " . htmlspecialchars(implode(",\n ", array_map(function ($k, $v) use($arg) { return "{$k} => " . self::debugVal($v); }, array_keys($arg), $arg))) . "\n]" : 'Empty array') . '">array</span>'; break; default: if (is_object($arg)) { switch (get_class($arg)) { case \ReflectionMethod::class: /** @var \ReflectionMethod $arg */ $arg = sprintf('<span class=type>ReflectionMethod</span><%s::%s>', $arg->getDeclaringClass()->getName(), $arg->getName()); break; case \ReflectionFunction::class: /** @var \ReflectionFunction $arg */ $arg = sprintf('<span class=type>ReflectionFunction</span><function at %s>', self::errorLink($arg->getFileName(), $arg->getStartLine(), 1, sprintf('%s line %d', basename($arg->getFileName()), $arg->getStartLine()), 'tag hint--rounded hint--top')); break; case \ReflectionParameter::class: /** @var \ReflectionParameter $arg */ $arg = sprintf('<span class=type>ReflectionParameter</span><$%s>', $arg->getName()); break; default: $arg = Debug::typeInfoOf($arg); } } else { $arg = Debug::typeInfoOf($arg); } } $args[] = $arg; } } $args = implode(", ", $args); $args = "({$args})"; } else { $args = ''; } $file = isset($v['file']) ? $v['file'] : ''; $fitems = explode(DIRECTORY_SEPARATOR, $file); $fname = '<span class="file">' . end($fitems) . '</span>'; $line = isset($v['line']) ? $v['line'] : ' '; $lineStr = $line ? "<span class='line'>{$line}</span>" : ''; $edit = $file ? self::errorLink($file, $line, 1, 'edit', '__btn') : ''; $at = $file ? self::errorLink($file, $line, 1) : '<unknown location>'; ErrorConsoleRenderer::renderStackFrame($count - $k, $fname, $lineStr, $fn, $args, $at, $edit); } return ob_get_clean(); }
private function unwind($e) { $this->routingLogger->writef("<#row>%sUnwinding the stack...</#row>", self::$unwinding ? '' : '<span class=__alert>' . Debug::getType($e) . '</span> '); self::$unwinding = true; throw $e; }
/** * @param \Error|\Exception $e * @param Expression $exp * @throws ComponentException */ private function evalError($e, Expression $exp) { throw new ComponentException($this, Debug::grid(['Expression' => Debug::RAW_TEXT . "<kbd>{$exp}</kbd>", 'Compiled' => sprintf('%s<code>%s</code>', Debug::RAW_TEXT, \PhpCode::highlight("{$exp->translated}")), 'Error' => sprintf('%s%s %s', Debug::RAW_TEXT, Debug::typeInfoOf($e), $e->getMessage()), 'At' => sprintf('%s%s, line <b>%s</b>', Debug::RAW_TEXT, ErrorConsole::errorLink($e->getFile(), $e->getLine()), $e->getLine())], 'Error while evaluating data-binding expression')); }
/** * Returns a formatted properties table. * * @param array $props * @return string */ private static function properties(array $props) { return "<h6>Assigned properties</h6><table class=grid>\n" . str_replace(["'", '...'], ["<i>'</i>", '<i>...</i>'], implode('', map($props, function ($v, $k) { return "<tr><th>{$k}<td>" . (is_string($v) ? "'" . htmlspecialchars(trimText($v, 300, '...')) . "'" : Debug::toString($v)); })), $o) . "\n</table>"; }
/** * Invokes a request handler. * * <p>The router does not call handlers directly; instead, it does it trough this method, so that calls can be * intercepted, validated and logged. * * > This method also functions as a router extension point. * * @param callable $handler * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable $next * @return ResponseInterface */ protected function callHandler(callable $handler, ServerRequestInterface $request, ResponseInterface $response, callable $next) { $this->currentRequestMutator->set($request); if ($handler instanceof RenderableInterface) { $class = $handler->getContextClass(); $handler->setContext($this->injector->make($class)); } /*try { $response = $handler ($request, $response, $next); } catch (HttpException $error) { // Convert HTTP exceptions to normal responses $msg = $error->getTitle () ?: str_segmentsFirst ($error->getMessage (), "\n"); // use only the first line of text return $response->withStatus ($error->getCode (), $msg); }*/ $response = $handler($request, $response, $next); if (!$response) { throw new \RuntimeException(sprintf("Request handler <span class=__type>%s</span> did not return a response.", Debug::getType($handler))); } if (!$response instanceof ResponseInterface) { throw new \RuntimeException(sprintf("Response from request handler <span class=__type>%s</span> is not a <span class=type>ResponseInterface</span> implementation.", Debug::getType($handler))); } return $response; }
protected function afterRender() { parent::afterRender(); //---------------------------------------------------------------------------------------- // View Model panel // (MUST run before the DOM panel to capture the data-binding stack at its current state) //---------------------------------------------------------------------------------------- DebugConsole::registerPanel('view', new ConsoleLogger('View', 'fa fa-eye')); $VMFilter = function ($k, $v, $o) { if ($v instanceof DocumentContext || $v instanceof Component || $k === 'parent' || $k === 'model') { return '...'; } return true; }; $expMap = Expression::$inspectionMap; ksort($expMap); DebugConsole::logger('view')->withFilter($VMFilter, $this->context)->write('<#section|Compiled expressions>')->inspect($expMap)->write('</#section>'); //------------ // Model panel //------------ DebugConsole::registerPanel('model', new ConsoleLogger('Model', 'fa fa-table')); $shadowDOM = $this->getShadowDOM(); if ($shadowDOM) { $VMFilter = function ($k, $v, $o) { if ($v instanceof KernelSettings || $v instanceof NavigationInterface || $v instanceof NavigationLinkInterface || $v instanceof SessionInterface || $v instanceof ServerRequestInterface || $v instanceof DocumentContext || $v instanceof Component) { return '...'; } return true; }; $binder = $shadowDOM->getDataBinder(); DebugConsole::logger('model')->write('<#i>PAGE DATA BINDER: ' . Debug::getType($binder) . "</#i>")->write("<#section|PAGE VIEW MODEL>")->withFilter($VMFilter, $binder->getViewModel())->write("</#section>"); } //----------- // DOM panel //----------- if ($this->matisseSettings->inspectDOM()) { DebugConsole::registerPanel('DOM', new ConsoleLogger('Server-side DOM', 'fa fa-sitemap')); $insp = $this->inspect(true); DebugConsole::logger('DOM')->write($insp); } }