/** * Sends the given HTTP request * * @param \TYPO3\FLOW3\Http\Request $request * @return \TYPO3\FLOW3\Http\Response * @throws \TYPO3\FLOW3\Http\Exception * @api */ public function sendRequest(Request $request) { $requestHandler = $this->bootstrap->getActiveRequestHandler(); if (!$requestHandler instanceof \TYPO3\FLOW3\Tests\FunctionalTestRequestHandler) { throw new \TYPO3\FLOW3\Http\Exception('The browser\'s internal request engine has only been designed for use within functional tests.', 1335523749); } $response = new Response(); $requestHandler->setHttpRequest($request); $requestHandler->setHttpResponse($response); try { $actionRequest = $this->router->route($request); $this->securityContext->clearContext(); $this->securityContext->injectRequest($actionRequest); $this->dispatcher->dispatch($actionRequest, $response); } 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 FLOW3 ' . $exceptionCodeNumber . $exception->getMessage() . PHP_EOL; $content .= 'thrown in file ' . $filePathAndName . PHP_EOL; $content .= 'in line ' . $exception->getLine() . PHP_EOL . PHP_EOL; $content .= \TYPO3\FLOW3\Error\Debugger::getBacktraceCode($exception->getTrace(), FALSE, TRUE) . PHP_EOL; $response->setStatus(500); $response->setContent($content); $response->setHeader('X-FLOW3-ExceptionCode', $exceptionCodeNumber); $response->setHeader('X-FLOW3-ExceptionMessage', $exception->getMessage()); } return $response; }
/** * @test * @dataProvider commandIdentifiersAndCompiletimeControllerInfo */ public function isCompileTimeCommandControllerChecksIfTheGivenCommandIdentifierRefersToACompileTimeController($compiletimeCommandControllerIdentifiers, $givenCommandIdentifier, $expectedResult) { $bootstrap = new Bootstrap('Testing'); foreach ($compiletimeCommandControllerIdentifiers as $compiletimeCommandControllerIdentifier) { $bootstrap->registerCompiletimeCommand($compiletimeCommandControllerIdentifier); } $this->assertSame($expectedResult, $bootstrap->isCompiletimeCommand($givenCommandIdentifier)); }
/** * Invokes a single step of this sequence and also invokes all steps registered * to be executed after the given step. * * @param \TYPO3\FLOW3\Core\Booting\Step $step The step to invoke * @param \TYPO3\FLOW3\Core\Bootstrap $bootstrap * @return void */ protected function invokeStep(Step $step, Bootstrap $bootstrap) { $bootstrap->getSignalSlotDispatcher()->dispatch(__CLASS__, 'beforeInvokeStep', array($step)); $identifier = $step->getIdentifier(); $step($bootstrap); $bootstrap->getSignalSlotDispatcher()->dispatch(__CLASS__, 'afterInvokeStep', array($step)); if (isset($this->steps[$identifier])) { foreach ($this->steps[$identifier] as $followingStep) { $this->invokeStep($followingStep, $bootstrap); } } }
/** * Adds a CSRF token as argument in ExtDirect requests * * @FLOW3\Around("method(TYPO3\ExtJS\ExtDirect\Transaction->buildRequest()) && setting(TYPO3.FLOW3.security.enable)") * @param \TYPO3\FLOW3\Aop\JoinPointInterface $joinPoint The current join point * @return \TYPO3\FLOW3\Mvc\ActionRequest */ public function transferCsrfTokenToExtDirectRequests(\TYPO3\FLOW3\Aop\JoinPointInterface $joinPoint) { $extDirectRequest = $joinPoint->getAdviceChain()->proceed($joinPoint); $requestHandler = $this->bootstrap->getActiveRequestHandler(); if ($requestHandler instanceof \TYPO3\FLOW3\Http\HttpRequestHandlerInterface) { $arguments = $requestHandler->getHttpRequest()->getArguments(); if (isset($arguments['__csrfToken'])) { $requestArguments = $extDirectRequest->getArguments(); $requestArguments['__csrfToken'] = $arguments['__csrfToken']; $extDirectRequest->setArguments($requestArguments); } } return $extDirectRequest; }
/** * Initializes the context after all dependencies have been injected. * * @return void */ public function initializeObject() { $this->locale = new Locale('mul_ZZ'); $activeRequestHandler = $this->bootstrap->getActiveRequestHandler(); if ($activeRequestHandler instanceof \TYPO3\FLOW3\Http\HttpRequestHandlerInterface) { $matchingDomains = $this->domainRepository->findByHost($activeRequestHandler->getHttpRequest()->getUri()->getHost()); if (count($matchingDomains) > 0) { $this->currentDomain = $matchingDomains[0]; $this->currentSite = $matchingDomains[0]->getSite(); } else { $this->currentSite = $this->siteRepository->findFirst(); } } else { $this->currentSite = $this->siteRepository->findFirst(); } }
/** * Returns an array that contains all available command identifiers and their shortest non-ambiguous alias * * @return array in the format array('full.command:identifier1' => 'alias1', 'full.command:identifier2' => 'alias2') */ protected function getShortCommandIdentifiers() { if ($this->shortCommandIdentifiers === NULL) { $commandsByCommandName = array(); foreach ($this->getAvailableCommands() as $availableCommand) { list($packageKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier()); if (!isset($commandsByCommandName[$commandName])) { $commandsByCommandName[$commandName] = array(); } if (!isset($commandsByCommandName[$commandName][$controllerName])) { $commandsByCommandName[$commandName][$controllerName] = array(); } $commandsByCommandName[$commandName][$controllerName][] = $packageKey; } foreach ($this->getAvailableCommands() as $availableCommand) { list($packageKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier()); if (count($commandsByCommandName[$commandName][$controllerName]) > 1 || $this->bootstrap->isCompiletimeCommand($availableCommand->getCommandIdentifier())) { $packageKeyParts = array_reverse(explode('.', $packageKey)); for ($i = 1; $i <= count($packageKeyParts); $i++) { $shortCommandIdentifier = implode('.', array_slice($packageKeyParts, 0, $i)) . ':' . $controllerName . ':' . $commandName; try { $this->getCommandByIdentifier($shortCommandIdentifier); $this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = $shortCommandIdentifier; break; } catch (\TYPO3\FLOW3\Mvc\Exception\CommandException $exception) { } } } else { $this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = sprintf('%s:%s', $controllerName, $commandName); } } } return $this->shortCommandIdentifiers; }
/** * Starts the shutdown sequence * * @param string $runlevel Either "Compiletime" or "Runtime" * @return void */ protected function shutdown($runlevel) { $this->bootstrap->shutdown($runlevel); if ($runlevel === 'Compiletime') { $this->objectManager->get('TYPO3\\FLOW3\\Core\\LockManager')->unlockSite(); } exit($this->response->getExitCode()); }
/** * Detects the (resources) base URI and stores it as a protected class variable. * * $this->resourcesPublishingPath must be set prior to calling this method. * * @return void */ protected function detectResourcesBaseUri() { $requestHandler = $this->bootstrap->getActiveRequestHandler(); if ($requestHandler instanceof \TYPO3\FLOW3\Http\HttpRequestHandlerInterface) { $uri = $requestHandler->getHttpRequest()->getBaseUri(); } else { $uri = ''; } $this->resourcesBaseUri = $uri . substr($this->resourcesPublishingPath, strlen(FLOW3_PATH_WEB)); }
/** * Resolves a few dependencies of this request handler which can't be resolved * automatically due to the early stage of the boot process this request handler * is invoked at. * * @return void */ protected function resolveDependencies() { $objectManager = $this->bootstrap->getObjectManager(); $this->dispatcher = $objectManager->get('TYPO3\\FLOW3\\Mvc\\Dispatcher'); $configurationManager = $objectManager->get('TYPO3\\FLOW3\\Configuration\\ConfigurationManager'); $this->settings = $configurationManager->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'TYPO3.FLOW3'); $this->routesConfiguration = $configurationManager->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_ROUTES); $this->router = $objectManager->get('TYPO3\\FLOW3\\Mvc\\Routing\\Router'); $this->securityContext = $objectManager->get('TYPO3\\FLOW3\\Security\\Context'); }
/** * Returns autocomplete suggestions on hitting the TAB key. * * @param string $partialCommand The current (partial) command where the TAB key was hit * @param integer $index The cursor index at the current (partial) command * @return array */ protected function autocomplete($partialCommand, $index) { // @TODO Add more functionality by parsing the current buffer with readline_info() // @TODO Filter file system elements (if possible at all) $suggestions = array(); $availableCommands = $this->bootstrap->getObjectManager()->get('TYPO3\\FLOW3\\Cli\\CommandManager')->getAvailableCommands(); /** @var $command \TYPO3\FLOW3\Cli\Command */ foreach ($availableCommands as $command) { if ($command->isInternal() === FALSE) { $suggestions[] = $command->getCommandIdentifier(); } } return $suggestions; }
/** * Invokes custom PHP code directly after the package manager has been initialized. * * @param \TYPO3\FLOW3\Core\Bootstrap $bootstrap The current bootstrap * @return void */ public function boot(\TYPO3\FLOW3\Core\Bootstrap $bootstrap) { $bootstrap->registerRequestHandler(new \TYPO3\FLOW3\Cli\SlaveRequestHandler($bootstrap)); $bootstrap->registerRequestHandler(new \TYPO3\FLOW3\Cli\CommandRequestHandler($bootstrap)); $bootstrap->registerRequestHandler(new \TYPO3\FLOW3\Http\RequestHandler($bootstrap)); if ($bootstrap->getContext()->isTesting()) { $bootstrap->getEarlyInstance('TYPO3\\FLOW3\\Core\\ClassLoader')->setConsiderTestsNamespace(TRUE); $bootstrap->registerRequestHandler(new \TYPO3\FLOW3\Tests\FunctionalTestRequestHandler($bootstrap)); } $bootstrap->registerCompiletimeCommand('typo3.flow3:core:*'); $bootstrap->registerCompiletimeCommand('typo3.flow3:cache:flush'); $dispatcher = $bootstrap->getSignalSlotDispatcher(); $dispatcher->connect('TYPO3\\FLOW3\\Mvc\\Dispatcher', 'afterControllerInvocation', 'TYPO3\\FLOW3\\Persistence\\PersistenceManagerInterface', 'persistAll'); $dispatcher->connect('TYPO3\\FLOW3\\Cli\\SlaveRequestHandler', 'dispatchedCommandLineSlaveRequest', 'TYPO3\\FLOW3\\Persistence\\PersistenceManagerInterface', 'persistAll'); $dispatcher->connect('TYPO3\\FLOW3\\Core\\Bootstrap', 'bootstrapShuttingDown', 'TYPO3\\FLOW3\\Configuration\\ConfigurationManager', 'shutdown'); $dispatcher->connect('TYPO3\\FLOW3\\Core\\Bootstrap', 'bootstrapShuttingDown', 'TYPO3\\FLOW3\\Object\\ObjectManagerInterface', 'shutdown'); $dispatcher->connect('TYPO3\\FLOW3\\Core\\Bootstrap', 'bootstrapShuttingDown', 'TYPO3\\FLOW3\\Reflection\\ReflectionService', 'saveToCache'); $dispatcher->connect('TYPO3\\FLOW3\\Command\\CoreCommandController', 'finishedCompilationRun', 'TYPO3\\FLOW3\\Security\\Policy\\PolicyService', 'savePolicyCache'); $dispatcher->connect('TYPO3\\FLOW3\\Security\\Authentication\\AuthenticationProviderManager', 'authenticatedToken', 'TYPO3\\FLOW3\\Session\\SessionInterface', 'renewId'); $dispatcher->connect('TYPO3\\FLOW3\\Security\\Authentication\\AuthenticationProviderManager', 'loggedOut', 'TYPO3\\FLOW3\\Session\\SessionInterface', 'destroy'); $dispatcher->connect('TYPO3\\FLOW3\\Monitor\\FileMonitor', 'filesHaveChanged', 'TYPO3\\FLOW3\\Cache\\CacheManager', 'flushSystemCachesByChangedFiles'); $dispatcher->connect('TYPO3\\FLOW3\\Tests\\FunctionalTestCase', 'functionalTestTearDown', 'TYPO3\\FLOW3\\Mvc\\Routing\\Aspect\\RouterCachingAspect', 'flushCaches'); }
/** * Loads the states of available packages from the PackageStates.php file. * The result is stored in $this->packageStatesConfiguration. * * @return void */ protected function loadPackageStates() { $this->packageStatesConfiguration = file_exists($this->packageStatesPathAndFilename) ? include $this->packageStatesPathAndFilename : array(); if (!isset($this->packageStatesConfiguration['version']) || $this->packageStatesConfiguration['version'] < 2) { if (is_dir(FLOW3_PATH_PACKAGES . '.Shortcuts')) { Files::removeDirectoryRecursively(FLOW3_PATH_PACKAGES . '.Shortcuts'); } $this->packageStatesConfiguration = array(); } if ($this->packageStatesConfiguration === array() || !$this->bootstrap->getContext()->isProduction()) { $this->scanAvailablePackages(); } else { $this->registerPackages(); } }
/** * @param array<\TYPO3\FLOW3\Cli\Command> $commands * @return void */ protected function displayShortHelpForCommands(array $commands) { $commandsByPackagesAndControllers = $this->buildCommandsIndex($commands); foreach ($commandsByPackagesAndControllers as $packageKey => $commandControllers) { $this->outputLine(''); $this->outputLine('PACKAGE "%s":', array(strtoupper($packageKey))); $this->outputLine(str_repeat('-', self::MAXIMUM_LINE_LENGTH)); foreach ($commandControllers as $commands) { foreach ($commands as $command) { $description = wordwrap($command->getShortDescription(), self::MAXIMUM_LINE_LENGTH - 43, PHP_EOL . str_repeat(' ', 43), TRUE); $shortCommandIdentifier = $this->commandManager->getShortestIdentifierForCommand($command); $compileTimeSymbol = $this->bootstrap->isCompileTimeCommand($shortCommandIdentifier) ? '*' : ''; $this->outputLine('%-2s%-40s %s', array($compileTimeSymbol, $shortCommandIdentifier, $description)); } $this->outputLine(); } } }
/** * Refreeze a package * * Refreezes a currently frozen package: all precompiled information is removed * and file monitoring will consider the package exactly once, on the next * request. After that request, the package remains frozen again, just with the * updated data. * * By specifying <b>all</b> as a package key, all currently frozen packages are * refrozen (the default). * * @param string $packageKey Key of the package to refreeze, or 'all' * @return void * @see typo3.flow3:package:freeze * @see typo3.flow3:cache:flush */ public function refreezeCommand($packageKey = 'all') { if (!$this->bootstrap->getContext()->isDevelopment()) { $this->outputLine('Package freezing is only supported in Development context.'); $this->quit(3); } $packagesToRefreeze = array(); if ($packageKey === 'all') { foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) { if ($this->packageManager->isPackageFrozen($packageKey)) { $packagesToRefreeze[] = $packageKey; } } if ($packagesToRefreeze === array()) { $this->outputLine('Nothing to do, no packages were frozen.'); $this->quit(0); } } else { if ($packageKey === NULL) { $this->outputLine('You must specify a package to refreeze.'); $this->quit(1); } if (!$this->packageManager->isPackageAvailable($packageKey)) { $this->outputLine('Package "%s" is not available.', array($packageKey)); $this->quit(2); } if (!$this->packageManager->isPackageFrozen($packageKey)) { $this->outputLine('Package "%s" was not frozen.', array($packageKey)); $this->quit(0); } $packagesToRefreeze = array($packageKey); } foreach ($packagesToRefreeze as $packageKey) { $this->packageManager->refreezePackage($packageKey); $this->outputLine('Refroze package "%s".', array($packageKey)); } Scripts::executeCommand('typo3.flow3:cache:flush', $this->settings, FALSE); $this->sendAndExit(0); }
/** * Flush all caches * * The flush command flushes all caches (including code caches) which have been * registered with FLOW3's Cache Manager. It also removes any session data. * * If fatal errors caused by a package prevent the compile time bootstrap * from running, the removal of any temporary data can be forced by specifying * the option <b>--force</b>. * * This command does not remove the precompiled data provided by frozen * packages unless the <b>--force</b> option is used. * * @param boolean $force Force flushing of any temporary data * @return void * @see typo3.flow3:cache:warmup * @see typo3.flow3:package:freeze * @see typo3.flow3:package:refreeze */ public function flushCommand($force = FALSE) { // Internal note: the $force option is evaluated early in the FLOW3 // bootstrap in order to reliably flush the temporary data before any // other code can cause fatal errors. $currentSessionImplementation = $this->objectManager->getClassNameByObjectName('TYPO3\\FLOW3\\Session\\SessionInterface'); $result = $currentSessionImplementation::destroyAll($this->bootstrap); if ($result === NULL) { $sessionDestroyMessage = ' and removed all potentially existing session data.'; } elseif ($result > 0) { $sessionDestroyMessage = sprintf(' and removed data of %s.', $result === 1 ? 'the one existing session' : 'the ' . $result . ' existing sessions'); } else { $sessionDestroyMessage = '.'; } $this->cacheManager->flushCaches(); $this->outputLine('Flushed all caches for "' . $this->bootstrap->getContext() . '" context' . $sessionDestroyMessage); if ($this->lockManager->isSiteLocked()) { $this->lockManager->unlockSite(); } $frozenPackages = array(); foreach (array_keys($this->packageManager->getActivePackages()) as $packageKey) { if ($this->packageManager->isPackageFrozen($packageKey)) { $frozenPackages[] = $packageKey; } } if ($frozenPackages !== array()) { $this->outputFormatted(PHP_EOL . 'Please note that the following package' . (count($frozenPackages) === 1 ? ' is' : 's are') . ' currently frozen: ' . PHP_EOL); $this->outputFormatted(implode(PHP_EOL, $frozenPackages) . PHP_EOL, array(), 2); $message = 'As code and configuration changes in these packages are not detected, the application may respond '; $message .= 'unexpectedly if modifications were done anyway or the remaining code relies on these changes.' . PHP_EOL . PHP_EOL; $message .= 'You may call <b>package:refreeze all</b> in order to refresh frozen packages or use the <b>--force</b> '; $message .= 'option of this <b>cache:flush</b> command to flush caches if FLOW3 becomes unresponsive.' . PHP_EOL; $this->outputFormatted($message, array($frozenPackages)); } $this->sendAndExit(0); }
/** * Initializes this service. * * This method must be run only after all dependencies have been injected. * * @param \TYPO3\FLOW3\Core\Bootstrap $bootstrap * @return void */ public function initialize(\TYPO3\FLOW3\Core\Bootstrap $bootstrap) { $this->context = $bootstrap->getContext(); if ($this->context->isProduction() && $this->reflectionDataRuntimeCache->getBackend()->isFrozen()) { $this->classReflectionData = $this->reflectionDataRuntimeCache->get('__classNames'); $this->annotatedClasses = $this->reflectionDataRuntimeCache->get('__annotatedClasses'); $this->loadFromClassSchemaRuntimeCache = TRUE; } else { $this->loadClassReflectionCompiletimeCache(); } $this->annotationReader = new \Doctrine\Common\Annotations\AnnotationReader(); foreach ($this->settings['reflection']['ignoredTags'] as $tag) { \Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName($tag); } \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader(array($this->classLoader, 'loadClass')); }
/** * @return string */ public function render() { return implode("\n", array('window.T3Configuration = {};', 'window.T3Configuration.Schema = ' . json_encode($this->contentTypeManager->getFullConfiguration()) . ';', 'window.T3Configuration.UserInterface = ' . json_encode($this->settings['userInterface']) . ';', 'window.T3Configuration.phoenixShouldCacheSchema = ' . json_encode($this->bootstrap->getContext()->isProduction()) . ';', 'window.T3Configuration.enableAloha = ' . json_encode($this->settings['enableAloha']) . ';', 'window.T3Configuration.contentTypeGroups = ' . json_encode($this->settings['contentTypeGroups']) . ';')); }
/** * Signals that the functional test case has been executed * * @return void * @FLOW3\Signal */ protected function emitFunctionalTestTearDown() { self::$bootstrap->getSignalSlotDispatcher()->dispatch(__CLASS__, 'functionalTestTearDown'); }
/** * Destroys (file) data from all active PHP sessions. * * @param \TYPO3\FLOW3\Core\Bootstrap $bootstrap * @return integer The number of session files which have been removed */ public static function destroyAll(Bootstrap $bootstrap) { $settings = $bootstrap->getObjectManager()->get('TYPO3\\FLOW3\\Configuration\\ConfigurationManager')->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'TYPO3.FLOW3'); if (empty($settings['session']['PhpSession']['savePath'])) { $sessionsPath = Files::concatenatePaths(array($bootstrap->getObjectManager()->get('TYPO3\\FLOW3\\Utility\\Environment')->getPathToTemporaryDirectory(), 'Sessions')); } else { $sessionsPath = $settings['session']['PhpSession']['savePath']; } if (is_dir($sessionsPath)) { $filenames = Files::readDirectoryRecursively($sessionsPath); if (count($filenames) > 0) { Files::emptyDirectoryRecursively($sessionsPath); } return count($filenames); } else { return 0; } }
/** * Emits a signal that a CLI slave request was dispatched. * * @return void * @FLOW3\Signal */ protected function emitDispatchedCommandLineSlaveRequest() { $this->bootstrap->getSignalSlotDispatcher()->dispatch(__CLASS__, 'dispatchedCommandLineSlaveRequest', array()); }
/** * Handles a command line request * * @return void */ public function handleRequest() { $sequence = $this->bootstrap->buildRuntimeSequence(); $sequence->invoke($this->bootstrap); }
/** * Initialize the resource management component, setting up stream wrappers, * publishing the public resources of all found packages, ... * * @param \TYPO3\FLOW3\Core\Bootstrap $bootstrap * @return void */ public static function initializeResources(Bootstrap $bootstrap) { $packageManager = $bootstrap->getEarlyInstance('TYPO3\\FLOW3\\Package\\PackageManagerInterface'); $resourceManager = $bootstrap->getObjectManager()->get('TYPO3\\FLOW3\\Resource\\ResourceManager'); $resourceManager->initialize(); $resourceManager->publishPublicPackageResources($packageManager->getActivePackages()); }