/** * @test */ public function ignoredClassesCanBeOverwrittenBySettings() { $object = new ApplicationContext('Development'); $this->assertEquals('TYPO3\\Flow\\Core\\ApplicationContext prototype object', Debugger::renderDump($object, 10, TRUE)); Debugger::clearState(); $currentConfiguration = ObjectAccess::getProperty($this->configurationManager, 'configurations', TRUE); $configurationOverwrite['Settings']['TYPO3']['Flow']['error']['debugger']['ignoredClasses']['TYPO3\\\\Flow\\\\Core\\\\.*'] = FALSE; $newConfiguration = Arrays::arrayMergeRecursiveOverrule($currentConfiguration, $configurationOverwrite); ObjectAccess::setProperty($this->configurationManager, 'configurations', $newConfiguration, TRUE); $this->assertContains('rootContextString', Debugger::renderDump($object, 10, TRUE)); }
/** * A var_dump function optimized for Flow's object structures * * @param mixed $variable The variable to display a dump of * @param string $title optional custom title for the debug output * @param boolean $return if TRUE, the dump is returned for displaying it embedded in custom HTML. If FALSE (default), the variable dump is directly displayed. * @param boolean $plaintext If TRUE, the dump is in plain text, if FALSE the debug output is in HTML format. If not specified, the mode is guessed from FLOW_SAPITYPE * @return void|string if $return is TRUE, the variable dump is returned. By default, the dump is directly displayed, and nothing is returned. * @api */ function var_dump($variable, $title = NULL, $return = FALSE, $plaintext = NULL) { if ($plaintext === NULL) { $plaintext = FLOW_SAPITYPE === 'CLI'; $ansiColors = $plaintext && DIRECTORY_SEPARATOR === '/'; } else { $ansiColors = FALSE; } if ($title === NULL) { $title = 'Flow Variable Dump'; } if ($ansiColors) { $title = "[1m" . $title . "[0m"; } \TYPO3\Flow\Error\Debugger::clearState(); if (!$plaintext && \TYPO3\Flow\Error\Debugger::$stylesheetEchoed === FALSE) { echo '<style type="text/css">' . file_get_contents('resource://TYPO3.Flow/Public/Error/Debugger.css') . '</style>'; \TYPO3\Flow\Error\Debugger::$stylesheetEchoed = TRUE; } if ($plaintext) { $output = $title . chr(10) . \TYPO3\Flow\Error\Debugger::renderDump($variable, 0, TRUE, $ansiColors) . chr(10) . chr(10); } else { $output = ' <div class="Flow-Error-Debugger-VarDump ' . ($return ? 'Flow-Error-Debugger-VarDump-Inline' : 'Flow-Error-Debugger-VarDump-Floating') . '"> <div class="Flow-Error-Debugger-VarDump-Top"> ' . htmlspecialchars($title) . ' </div> <div class="Flow-Error-Debugger-VarDump-Center"> <pre dir="ltr">' . \TYPO3\Flow\Error\Debugger::renderDump($variable, 0, FALSE, FALSE) . '</pre> </div> </div> '; } if ($return === TRUE) { return $output; } else { echo $output; } }
/** * Prepare a response in case an error occurred. * * @param \Throwable $exception * @param Http\Response $response * @return void */ protected function prepareErrorResponse($exception, Http\Response $response) { $pathPosition = strpos($exception->getFile(), 'Packages/'); $filePathAndName = $pathPosition !== false ? substr($exception->getFile(), $pathPosition) : $exception->getFile(); $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : ''; $content = PHP_EOL . 'Uncaught Exception in Flow ' . $exceptionCodeNumber . $exception->getMessage() . PHP_EOL; $content .= 'thrown in file ' . $filePathAndName . PHP_EOL; $content .= 'in line ' . $exception->getLine() . PHP_EOL . PHP_EOL; $content .= Debugger::getBacktraceCode($exception->getTrace(), false, true) . PHP_EOL; if ($exception instanceof Exception) { $statusCode = $exception->getStatusCode(); } else { $statusCode = 500; } $response->setStatus($statusCode); $response->setContent($content); $response->setHeader('X-Flow-ExceptionCode', $exception->getCode()); $response->setHeader('X-Flow-ExceptionMessage', $exception->getMessage()); }
/** * @test */ public function considersProxyClassWhenIsProxyPropertyIsPresent() { $object = new \stdClass(); $object->__IS_PROXY__ = TRUE; $this->assertRegExp('/\\sclass=\\"debug\\-proxy\\"/', Debugger::renderDump($object, 0, FALSE)); }
/** * Renders background information about the circumstances of the exception. * * @param string $message * @param array $backTrace * @return string */ protected function renderBacktrace($message, $backTrace) { return $message . PHP_EOL . PHP_EOL . Debugger::getBacktraceCode($backTrace, false, true); }
/** * Returns the statically rendered exception message * * @param integer $statusCode * @param \Exception $exception * @return void */ protected function renderStatically($statusCode, \Exception $exception) { $statusMessage = Response::getStatusMessageByCode($statusCode); $exceptionHeader = ''; while (true) { $pathPosition = strpos($exception->getFile(), 'Packages/'); $filePathAndName = $pathPosition !== false ? substr($exception->getFile(), $pathPosition) : $exception->getFile(); $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : ''; $moreInformationLink = $exceptionCodeNumber != '' ? '<p><a href="http://typo3.org/go/exception/' . $exception->getCode() . '">More information</a></p>' : ''; $exceptionMessageParts = $this->splitExceptionMessage($exception->getMessage()); $exceptionHeader .= '<h2 class="ExceptionSubject">' . $exceptionCodeNumber . htmlspecialchars($exceptionMessageParts['subject']) . '</h2>'; if ($exceptionMessageParts['body'] !== '') { $exceptionHeader .= '<p class="ExceptionBody">' . nl2br(htmlspecialchars($exceptionMessageParts['body'])) . '</p>'; } $exceptionHeader .= $moreInformationLink . ' <span class="ExceptionProperty">' . get_class($exception) . '</span> thrown in file<br /> <span class="ExceptionProperty">' . $filePathAndName . '</span> in line <span class="ExceptionProperty">' . $exception->getLine() . '</span>.<br />'; if ($exception instanceof FlowException) { $exceptionHeader .= '<span class="ExceptionProperty">Reference code: ' . $exception->getReferenceCode() . '</span><br />'; } if ($exception->getPrevious() === null) { break; } $exceptionHeader .= '<br /><div style="width: 100%; background-color: #515151; color: white; padding: 2px; margin: 0 0 6px 0;">Nested Exception</div>'; $exception = $exception->getPrevious(); } $backtraceCode = Debugger::getBacktraceCode($exception->getTrace()); echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"> <head> <title>' . $statusCode . ' ' . $statusMessage . '</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> .ExceptionSubject { margin: 0; padding: 0; font-size: 15px; color: #BE0027; } .ExceptionBody { padding: 10px; margin: 10px; color: black; background: #DDD; } .ExceptionProperty { color: #101010; } pre { margin: 0; font-size: 11px; color: #515151; background-color: #D0D0D0; padding-left: 30px; } </style> </head> <div style=" position: absolute; left: 10px; background-color: #B9B9B9; outline: 1px solid #515151; color: #515151; font-family: Arial, Helvetica, sans-serif; font-size: 12px; margin: 10px; padding: 0; "> <div style="width: 100%; background-color: #515151; color: white; padding: 2px; margin: 0 0 6px 0;">Uncaught Exception in Flow</div> <div style="width: 100%; padding: 2px; margin: 0 0 6px 0;"> ' . $exceptionHeader . ' <br /> ' . $backtraceCode . ' </div> </div> '; }
/** * Show the current status of entities and mappings * * Shows basic information about which entities exist and possibly if their * mapping information contains errors or not. * * To run a full validation, use the validate command. * * @param boolean $dumpMappingData If set, the mapping data will be output * @return void * @see typo3.flow:doctrine:validate */ public function entityStatusCommand($dumpMappingData = FALSE) { $info = $this->doctrineService->getEntityStatus(); if ($info === array()) { $this->output('You do not have any mapped Doctrine ORM entities according to the current configuration. '); $this->outputLine('If you have entities or mapping files you should check your mapping configuration for errors.'); } else { $this->outputLine('Found %d mapped entities:', array(count($info))); foreach ($info as $entityClassName => $entityStatus) { if ($entityStatus instanceof ClassMetadata) { $this->outputLine('[OK] %s', array($entityClassName)); if ($dumpMappingData) { Debugger::clearState(); $this->outputLine(Debugger::renderDump($entityStatus, 0, TRUE, TRUE)); } } else { $this->outputLine('[FAIL] %s', array($entityClassName)); $this->outputLine($entityStatus); $this->outputLine(); } } } }
/** * Sends the given HTTP request * * @param Http\Request $httpRequest * @return Http\Response * @throws Http\Exception * @api */ public function sendRequest(Http\Request $httpRequest) { $requestHandler = $this->bootstrap->getActiveRequestHandler(); if (!$requestHandler instanceof FunctionalTestRequestHandler) { throw new Http\Exception('The browser\'s internal request engine has only been designed for use within functional tests.', 1335523749); } $this->securityContext->clearContext(); $this->validatorResolver->reset(); $response = new Http\Response(); $requestHandler->setHttpRequest($httpRequest); $requestHandler->setHttpResponse($response); $objectManager = $this->bootstrap->getObjectManager(); $baseComponentChain = $objectManager->get(\TYPO3\Flow\Http\Component\ComponentChain::class); $componentContext = new ComponentContext($httpRequest, $response); try { $baseComponentChain->handle($componentContext); } catch (\Exception $exception) { $pathPosition = strpos($exception->getFile(), 'Packages/'); $filePathAndName = $pathPosition !== FALSE ? substr($exception->getFile(), $pathPosition) : $exception->getFile(); $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : ''; $content = PHP_EOL . 'Uncaught Exception in Flow ' . $exceptionCodeNumber . $exception->getMessage() . PHP_EOL; $content .= 'thrown in file ' . $filePathAndName . PHP_EOL; $content .= 'in line ' . $exception->getLine() . PHP_EOL . PHP_EOL; $content .= Debugger::getBacktraceCode($exception->getTrace(), FALSE, TRUE) . PHP_EOL; if ($exception instanceof Exception) { $statusCode = $exception->getStatusCode(); } else { $statusCode = 500; } $response->setStatus($statusCode); $response->setContent($content); $response->setHeader('X-Flow-ExceptionCode', $exception->getCode()); $response->setHeader('X-Flow-ExceptionMessage', $exception->getMessage()); } $session = $this->bootstrap->getObjectManager()->get(\TYPO3\Flow\Session\SessionInterface::class); if ($session->isStarted()) { $session->close(); } return $response; }
/** * Initializes the runtime Object Manager * * @param Bootstrap $bootstrap * @return void */ public static function initializeObjectManager(Bootstrap $bootstrap) { $configurationManager = $bootstrap->getEarlyInstance('TYPO3\\Flow\\Configuration\\ConfigurationManager'); $objectConfigurationCache = $bootstrap->getEarlyInstance('TYPO3\\Flow\\Cache\\CacheManager')->getCache('Flow_Object_Configuration'); $objectManager = new \TYPO3\Flow\Object\ObjectManager($bootstrap->getContext()); Bootstrap::$staticObjectManager = $objectManager; $objectManager->injectAllSettings($configurationManager->getConfiguration(\TYPO3\Flow\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS)); $objectManager->setObjects($objectConfigurationCache->get('objects')); foreach ($bootstrap->getEarlyInstances() as $objectName => $instance) { $objectManager->setInstance($objectName, $instance); } $objectManager->get('TYPO3\\Flow\\SignalSlot\\Dispatcher')->injectObjectManager($objectManager); \TYPO3\Flow\Error\Debugger::injectObjectManager($objectManager); $bootstrap->setEarlyInstance('TYPO3\\Flow\\Object\\ObjectManagerInterface', $objectManager); }
/** * @test */ public function ignoredClassesAreNotRendered() { $object = new ApplicationContext('Development'); $this->assertEquals('TYPO3\\Flow\\Core\\ApplicationContext object', Debugger::renderDump($object, 10, true)); }
/** * Show the current status of entities and mappings * * Shows basic information about which entities exist and possibly if their * mapping information contains errors or not. * * To run a full validation, use the validate command. * * @param boolean $dumpMappingData If set, the mapping data will be output * @param string $entityClassName If given, the mapping data for just this class will be output * @return void * @see typo3.flow:doctrine:validate */ public function entityStatusCommand($dumpMappingData = false, $entityClassName = null) { $info = $this->doctrineService->getEntityStatus(); if ($info === []) { $this->output('You do not have any mapped Doctrine ORM entities according to the current configuration. '); $this->outputLine('If you have entities or mapping files you should check your mapping configuration for errors.'); } else { $this->outputLine('Found %d mapped entities:', [count($info)]); $this->outputLine(); if ($entityClassName === null) { foreach ($info as $entityClassName => $entityStatus) { if ($entityStatus instanceof ClassMetadata) { $this->outputLine('<success>[OK]</success> %s', [$entityClassName]); if ($dumpMappingData) { Debugger::clearState(); $this->outputLine(Debugger::renderDump($entityStatus, 0, true, true)); } } else { $this->outputLine('<error>[FAIL]</error> %s', [$entityClassName]); $this->outputLine($entityStatus); $this->outputLine(); } } } else { if (array_key_exists($entityClassName, $info) && $info[$entityClassName] instanceof ClassMetadata) { $entityStatus = $info[$entityClassName]; $this->outputLine('<success>[OK]</success> %s', [$entityClassName]); if ($dumpMappingData) { Debugger::clearState(); $this->outputLine(Debugger::renderDump($entityStatus, 0, true, true)); } } else { $this->outputLine('<info>[FAIL]</info> %s', [$entityClassName]); $this->outputLine('Class not found.'); $this->outputLine(); } } } }
/** * Renders background information about the circumstances of the exception. * * @param string $message * @param array $backTrace * @return string */ protected function renderBacktrace($message, $backTrace) { return $message . PHP_EOL . PHP_EOL . Debugger::getBacktraceCode($backTrace, FALSE, TRUE); }
/** * Initializes the runtime Object Manager * * @param Bootstrap $bootstrap * @return void */ public static function initializeObjectManager(Bootstrap $bootstrap) { $configurationManager = $bootstrap->getEarlyInstance(ConfigurationManager::class); $objectConfigurationCache = $bootstrap->getEarlyInstance(CacheManager::class)->getCache('Flow_Object_Configuration'); $objectManager = new ObjectManager($bootstrap->getContext()); Bootstrap::$staticObjectManager = $objectManager; $objectManager->injectAllSettings($configurationManager->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS)); $objectManager->setObjects($objectConfigurationCache->get('objects')); foreach ($bootstrap->getEarlyInstances() as $objectName => $instance) { $objectManager->setInstance($objectName, $instance); } $objectManager->get(Dispatcher::class)->injectObjectManager($objectManager); Debugger::injectObjectManager($objectManager); $bootstrap->setEarlyInstance(ObjectManagerInterface::class, $objectManager); }
/** * Renders background information about the circumstances of the exception. * * @param array $backTrace * @return string */ protected function renderPostMortemInfo($message, $backTrace) { $output = $message . PHP_EOL . PHP_EOL . \TYPO3\Flow\Error\Debugger::getBacktraceCode($backTrace, FALSE, TRUE); if (Bootstrap::$staticObjectManager instanceof ObjectManagerInterface) { $bootstrap = Bootstrap::$staticObjectManager->get('TYPO3\\Flow\\Core\\Bootstrap'); /* @var Bootstrap $bootstrap */ $requestHandler = $bootstrap->getActiveRequestHandler(); if ($requestHandler instanceof HttpRequestHandlerInterface) { $request = $requestHandler->getHttpRequest(); $response = $requestHandler->getHttpResponse(); $output .= PHP_EOL . 'HTTP REQUEST:' . PHP_EOL . ($request == '' ? '[request was empty]' : $request) . PHP_EOL; $output .= PHP_EOL . 'HTTP RESPONSE:' . PHP_EOL . ($response == '' ? '[response was empty]' : $response) . PHP_EOL; } } return $output; }
/** * Returns a link pointing to Forge to create a new issue. * * @param \Exception $exception * @return string */ protected function getCreateIssueLink(\Exception $exception) { $filename = basename($exception->getFile()); return 'http://forge.typo3.org/projects/package-typo3-flow/issues/new?issue[subject]=' . urlencode(get_class($exception) . ' thrown in file ' . $filename) . '&issue[description]=' . urlencode($exception->getMessage() . chr(10) . strip_tags(str_replace(array('<br />', '</pre>'), chr(10), Debugger::getBacktraceCode($exception->getTrace(), FALSE))) . chr(10) . 'Please include more helpful information!') . '&issue[category_id]=554&issue[priority_id]=7'; }
/** * Formats and echoes the exception as XHTML. * * @param \Exception $exception The exception object * @return void */ protected function echoExceptionWeb(\Exception $exception) { if (!headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); } $exceptionHeader = ''; while (TRUE) { $pathPosition = strpos($exception->getFile(), 'Packages/'); $filePathAndName = $pathPosition !== FALSE ? substr($exception->getFile(), $pathPosition) : $exception->getFile(); $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : ''; $moreInformationLink = $exceptionCodeNumber != '' ? '(<a href="http://typo3.org/go/exception/' . $exception->getCode() . '">More information</a>)' : ''; $createIssueLink = $this->getCreateIssueLink($exception); $exceptionHeader .= ' <strong style="color: #BE0027;">' . $exceptionCodeNumber . htmlspecialchars($exception->getMessage()) . '</strong> ' . $moreInformationLink . '<br /> <br /> <span class="ExceptionProperty">' . get_class($exception) . '</span> thrown in file<br /> <span class="ExceptionProperty">' . $filePathAndName . '</span> in line <span class="ExceptionProperty">' . $exception->getLine() . '</span>.<br />'; if ($exception instanceof \TYPO3\Flow\Exception) { $exceptionHeader .= '<span class="ExceptionProperty">Reference code: ' . $exception->getReferenceCode() . '</span><br />'; } if ($exception->getPrevious() === NULL) { $exceptionHeader .= '<br /><a href="' . $createIssueLink . '">Go to the FORGE issue tracker and report the issue</a> - <strong>if you think it is a bug!</strong><br />'; break; } else { $exceptionHeader .= '<br /><div style="width: 100%; background-color: #515151; color: white; padding: 2px; margin: 0 0 6px 0;">Nested Exception</div>'; $exception = $exception->getPrevious(); } } $backtraceCode = \TYPO3\Flow\Error\Debugger::getBacktraceCode($exception->getTrace()); echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"> <head> <title>Flow Exception</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <style> .ExceptionProperty { color: #101010; } pre { margin: 0; font-size: 11px; color: #515151; background-color: #D0D0D0; padding-left: 30px; } </style> <div style=" position: absolute; left: 10px; background-color: #B9B9B9; outline: 1px solid #515151; color: #515151; font-family: Arial, Helvetica, sans-serif; font-size: 12px; margin: 10px; padding: 0; "> <div style="width: 100%; background-color: #515151; color: white; padding: 2px; margin: 0 0 6px 0;">Uncaught Exception in Flow</div> <div style="width: 100%; padding: 2px; margin: 0 0 6px 0;"> ' . $exceptionHeader . ' <br /> ' . $backtraceCode . ' </div> </div> '; $response = new \TYPO3\Flow\Http\Response(); $response->setStatus(400); \Debug\Toolbar\Service\DataStorage::add('Request:Responses', $response); $this->emitAboutToRenderDebugToolbar(); $toolbar = new \Debug\Toolbar\Toolbar\View(); echo $toolbar->render(); }