/** * @test */ public function parentContextIsConnectedRecursively() { $context = new ApplicationContext('Production/Foo/Bar'); $parentContext = $context->getParent(); $this->assertSame('Production/Foo', (string) $parentContext); $rootContext = $parentContext->getParent(); $this->assertSame('Production', (string) $rootContext); }
/** * @test */ public function saveConfigurationCacheSavesTheCurrentConfigurationAsPhpCode() { vfsStream::setup('Flow'); mkdir(vfsStream::url('Flow/Configuration')); $temporaryDirectoryPath = vfsStream::url('Flow/TemporaryDirectory') . '/'; $includeCachedConfigurationsPathAndFilename = vfsStream::url('Flow/Configuration/IncludeCachedConfigurations.php'); $mockConfigurations = array(ConfigurationManager::CONFIGURATION_TYPE_ROUTES => array('routes'), ConfigurationManager::CONFIGURATION_TYPE_CACHES => array('caches'), ConfigurationManager::CONFIGURATION_TYPE_SETTINGS => array('settings' => array('foo' => 'bar'))); $mockEnvironment = $this->getMock('TYPO3\\Flow\\Utility\\Environment', array('getPathToTemporaryDirectory'), array(), '', FALSE); $mockEnvironment->expects($this->once())->method('getPathToTemporaryDirectory')->will($this->returnValue($temporaryDirectoryPath)); $configurationManager = $this->getAccessibleMock('TYPO3\\Flow\\Configuration\\ConfigurationManager', array('postProcessConfiguration'), array(), '', FALSE); $configurationManager->injectEnvironment($mockEnvironment); $configurationManager->_set('includeCachedConfigurationsPathAndFilename', $includeCachedConfigurationsPathAndFilename); $this->mockContext->expects($this->any())->method('__toString')->will($this->returnValue('FooContext')); $configurationManager->_set('context', $this->mockContext); $configurationManager->_set('configurations', $mockConfigurations); $configurationManager->_call('saveConfigurationCache'); $expectedInclusionCode = <<<EOD <?php if (FLOW_PATH_ROOT !== 'XXX' || !file_exists('vfs://Flow/TemporaryDirectory/Configuration/FooContextConfigurations.php')) { \tunlink(__FILE__); \treturn array(); } return require 'vfs://Flow/TemporaryDirectory/Configuration/FooContextConfigurations.php'; EOD; $expectedInclusionCode = str_replace('XXX', FLOW_PATH_ROOT, $expectedInclusionCode); $this->assertTrue(file_exists($temporaryDirectoryPath . 'Configuration')); $this->assertStringEqualsFile($includeCachedConfigurationsPathAndFilename, $expectedInclusionCode); $this->assertFileExists($temporaryDirectoryPath . 'Configuration/FooContextConfigurations.php'); $this->assertSame($mockConfigurations, require $temporaryDirectoryPath . 'Configuration/FooContextConfigurations.php'); }
/** * @test */ public function saveConfigurationCacheSavesTheCurrentConfigurationAsPhpCode() { vfsStream::setup('Flow'); mkdir(vfsStream::url('Flow/Configuration')); $temporaryDirectoryPath = vfsStream::url('Flow/TemporaryDirectory') . '/'; $includeCachedConfigurationsPathAndFilename = vfsStream::url('Flow/Configuration/IncludeCachedConfigurations.php'); $mockConfigurations = array(ConfigurationManager::CONFIGURATION_TYPE_ROUTES => array('routes'), ConfigurationManager::CONFIGURATION_TYPE_CACHES => array('caches'), ConfigurationManager::CONFIGURATION_TYPE_SETTINGS => array('settings' => array('foo' => 'bar'))); $configurationManager = $this->getAccessibleMock(\TYPO3\Flow\Configuration\ConfigurationManager::class, array('postProcessConfiguration'), array(), '', false); $configurationManager->setTemporaryDirectoryPath($temporaryDirectoryPath); $configurationManager->_set('includeCachedConfigurationsPathAndFilename', $includeCachedConfigurationsPathAndFilename); $this->mockContext->expects($this->any())->method('__toString')->will($this->returnValue('FooContext')); $configurationManager->_set('context', $this->mockContext); $configurationManager->_set('configurations', $mockConfigurations); $configurationManager->_set('configurationTypes', [ConfigurationManager::CONFIGURATION_TYPE_ROUTES => array('processingType' => ConfigurationManager::CONFIGURATION_PROCESSING_TYPE_ROUTES, 'allowSplitSource' => false), ConfigurationManager::CONFIGURATION_TYPE_CACHES => array('processingType' => ConfigurationManager::CONFIGURATION_PROCESSING_TYPE_DEFAULT, 'allowSplitSource' => false), ConfigurationManager::CONFIGURATION_TYPE_SETTINGS => array('processingType' => ConfigurationManager::CONFIGURATION_PROCESSING_TYPE_DEFAULT, 'allowSplitSource' => false)]); $configurationManager->_call('saveConfigurationCache'); $expectedInclusionCode = <<<EOD <?php if (FLOW_PATH_ROOT !== 'XXX' || !file_exists('vfs://Flow/TemporaryDirectory/Configuration/FooContextConfigurations.php')) { \t@unlink(__FILE__); \treturn array(); } return require 'vfs://Flow/TemporaryDirectory/Configuration/FooContextConfigurations.php'; EOD; $expectedInclusionCode = str_replace('XXX', FLOW_PATH_ROOT, $expectedInclusionCode); $this->assertTrue(file_exists($temporaryDirectoryPath . 'Configuration')); $this->assertStringEqualsFile($includeCachedConfigurationsPathAndFilename, $expectedInclusionCode); $this->assertFileExists($temporaryDirectoryPath . 'Configuration/FooContextConfigurations.php'); $this->assertSame($mockConfigurations, require $temporaryDirectoryPath . 'Configuration/FooContextConfigurations.php'); }
/** * @test */ public function initializeFlushesCachesInDevelopmentContextIfRoutingSettingsWhereNotStoredPreviously() { $this->mockApplicationContext->expects($this->atLeastOnce())->method('isDevelopment')->will($this->returnValue(true)); $this->mockRouteCache->expects($this->atLeastOnce())->method('get')->with('routingSettings')->will($this->returnValue(false)); $this->mockRouteCache->expects($this->once())->method('flush'); $this->mockResolveCache->expects($this->once())->method('flush'); $this->routerCachingService->_call('initializeObject'); }
/** * @test */ public function unfreezePackageEmitsPackageStatesUpdatedSignal() { $this->mockApplicationContext->expects($this->atLeastOnce())->method('isDevelopment')->will($this->returnValue(true)); $this->packageManager->createPackage('Some.Package', null, null, null, ['name' => 'some/package', 'type' => 'typo3-flow-package']); $this->packageManager->freezePackage('Some.Package'); $this->mockDispatcher->expects($this->once())->method('dispatch')->with(PackageManager::class, 'packageStatesUpdated'); $this->packageManager->unfreezePackage('Some.Package'); }
/** * @test */ public function unfreezePackageEmitsPackageStatesUpdatedSignal() { $this->mockApplicationContext->expects($this->atLeastOnce())->method('isDevelopment')->will($this->returnValue(TRUE)); $this->packageManager->createPackage('Some.Package'); $this->packageManager->freezePackage('Some.Package'); $this->mockDispatcher->expects($this->once())->method('dispatch')->with('TYPO3\\Flow\\Package\\PackageManager', 'packageStatesUpdated'); $this->packageManager->unfreezePackage('Some.Package'); }
/** * Returns the form definitions for the step * * @param \TYPO3\Form\Core\Model\FormDefinition $formDefinition * @return void */ protected function buildForm(\TYPO3\Form\Core\Model\FormDefinition $formDefinition) { $page1 = $formDefinition->createPage('page1'); $page1->setRenderingOption('header', 'Setup complete'); $congratulations = $page1->createElement('congratulationsSection', 'TYPO3.Form:Section'); $congratulations->setLabel('Congratulations'); $success = $congratulations->createElement('success', 'TYPO3.Form:StaticText'); $success->setProperty('text', 'You have successfully installed Neos! If you need help getting started, please refer to the Neos documentation.'); $success->setProperty('elementClassAttribute', 'alert alert-success'); $docs = $congratulations->createElement('docsLink', 'TYPO3.Setup:LinkElement'); $docs->setLabel('Read the documentation'); $docs->setProperty('href', 'https://neos.readthedocs.org/'); $docs->setProperty('target', '_blank'); $contextEnv = \TYPO3\Flow\Core\Bootstrap::getEnvironmentConfigurationSetting('FLOW_CONTEXT') ?: 'Development'; $applicationContext = new ApplicationContext($contextEnv); if (!$applicationContext->isProduction()) { $context = $page1->createElement('contextSection', 'TYPO3.Form:Section'); $context->setLabel('Define application context'); $contextInfo = $context->createElement('contextInfo', 'TYPO3.Form:StaticText'); $contextInfo->setProperty('text', 'Your Neos installation is currently not running in "Production" context. If you want to experience Neos with its full speed, you should now change your FLOW_CONTEXT environment variable to "Production".'); $contextDocs = $context->createElement('contextDocsLink', 'TYPO3.Setup:LinkElement'); $contextDocs->setLabel('Read about application contexts'); $contextDocs->setProperty('href', 'http://flowframework.readthedocs.org/en/stable/TheDefinitiveGuide/PartIII/Bootstrapping.html#the-typo3-flow-application-context'); $contextDocs->setProperty('target', '_blank'); } $frontend = $page1->createElement('frontendSection', 'TYPO3.Form:Section'); $frontend->setLabel('View the site'); $link = $frontend->createElement('link', 'TYPO3.Setup:LinkElement'); $link->setLabel('Go to the frontend'); $link->setProperty('href', '/'); $link->setProperty('elementClassAttribute', 'btn btn-large btn-primary'); $backend = $page1->createElement('backendSection', 'TYPO3.Form:Section'); $backend->setLabel('Start editing'); $backendLink = $backend->createElement('backendLink', 'TYPO3.Setup:LinkElement'); $backendLink->setLabel('Go to the backend'); $backendLink->setProperty('href', '/neos'); $backendLink->setProperty('elementClassAttribute', 'btn btn-large btn-primary'); $loggedOut = $page1->createElement('loggedOut', 'TYPO3.Form:StaticText'); $loggedOut->setProperty('text', 'You have automatically been logged out for security reasons since this is the final step. Refresh the page to log in again if you missed something.'); $loggedOut->setProperty('elementClassAttribute', 'alert alert-info'); }
/** * Builds a boot sequence starting all modules necessary for the runtime state. * This includes all of the "essentials" sequence. * * @return \TYPO3\Flow\Core\Booting\Sequence * @api */ public function buildRuntimeSequence() { $sequence = $this->buildEssentialsSequence('runtime'); $sequence->addStep(new Step('typo3.flow:objectmanagement:proxyclasses', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeProxyClasses')), 'typo3.flow:systemlogger'); $sequence->addStep(new Step('typo3.flow:classloader:cache', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeClassLoaderClassesCache')), 'typo3.flow:objectmanagement:proxyclasses'); $sequence->addStep(new Step('typo3.flow:objectmanagement:runtime', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeObjectManager')), 'typo3.flow:classloader:cache'); if (!$this->context->isProduction()) { $sequence->addStep(new Step('typo3.flow:systemfilemonitor', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeSystemFileMonitor')), 'typo3.flow:objectmanagement:runtime'); $sequence->addStep(new Step('typo3.flow:objectmanagement:recompile', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'recompileClasses')), 'typo3.flow:systemfilemonitor'); } $sequence->addStep(new Step('typo3.flow:reflectionservice', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeReflectionService')), 'typo3.flow:objectmanagement:runtime'); $sequence->addStep(new Step('typo3.flow:resources', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeResources')), 'typo3.flow:reflectionservice'); $sequence->addStep(new Step('typo3.flow:session', array(\TYPO3\Flow\Core\Booting\Scripts::class, 'initializeSession')), 'typo3.flow:resources'); return $sequence; }
/** * Exports the internal reflection data into the ReflectionData cache * * This method is triggered by a signal which is connected to the bootstrap's * shutdown sequence. * * If the reflection data has previously been loaded from the runtime cache, * saving it is omitted as changes are not expected. * * In Production context the whole cache is written at once and then frozen in * order to be consistent. Frozen cache data in Development is only produced for * classes contained in frozen packages. * * @return void * @throws Exception if no cache has been injected */ public function saveToCache() { if ($this->hasFrozenCacheInProduction()) { return; } if (!$this->initialized) { $this->initialize(); } if ($this->loadFromClassSchemaRuntimeCache === true) { return; } if (!$this->reflectionDataCompiletimeCache instanceof FrontendInterface) { throw new Exception('A cache must be injected before initializing the Reflection Service.', 1232044697); } if ($this->updatedReflectionData !== []) { $this->updateReflectionData(); } if ($this->context->isProduction()) { $this->saveProductionData(); return; } $this->saveDevelopmentData(); }
/** * Loads special configuration defined in the specified packages and merges them with * those potentially existing in the global configuration folders. The result is stored * in the configuration manager's configuration registry and can be retrieved with the * getConfiguration() method. * * @param string $configurationType The kind of configuration to load - must be one of the CONFIGURATION_TYPE_* constants * @param array $packages An array of Package objects (indexed by package key) to consider * @throws Exception\InvalidConfigurationTypeException * @throws Exception\InvalidConfigurationException * @return void */ protected function loadConfiguration($configurationType, array $packages) { $this->cacheNeedsUpdate = true; $configurationProcessingType = $this->resolveConfigurationProcessingType($configurationType); $allowSplitSource = $this->isSplitSourceAllowedForConfigurationType($configurationType); switch ($configurationProcessingType) { case self::CONFIGURATION_PROCESSING_TYPE_SETTINGS: // Make sure that the Flow package is the first item of the packages array: if (isset($packages['TYPO3.Flow'])) { $flowPackage = $packages['TYPO3.Flow']; unset($packages['TYPO3.Flow']); $packages = array_merge(array('TYPO3.Flow' => $flowPackage), $packages); unset($flowPackage); } $settings = array(); /** @var $package PackageInterface */ foreach ($packages as $packageKey => $package) { if (Arrays::getValueByPath($settings, $packageKey) === null) { $settings = Arrays::setValueByPath($settings, $packageKey, array()); } $settings = Arrays::arrayMergeRecursiveOverrule($settings, $this->configurationSource->load($package->getConfigurationPath() . $configurationType, $allowSplitSource)); } $settings = Arrays::arrayMergeRecursiveOverrule($settings, $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $configurationType, $allowSplitSource)); foreach ($this->orderedListOfContextNames as $contextName) { /** @var $package PackageInterface */ foreach ($packages as $package) { $settings = Arrays::arrayMergeRecursiveOverrule($settings, $this->configurationSource->load($package->getConfigurationPath() . $contextName . '/' . $configurationType, $allowSplitSource)); } $settings = Arrays::arrayMergeRecursiveOverrule($settings, $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $contextName . '/' . $configurationType, $allowSplitSource)); } if ($this->configurations[$configurationType] !== array()) { $this->configurations[$configurationType] = Arrays::arrayMergeRecursiveOverrule($this->configurations[$configurationType], $settings); } else { $this->configurations[$configurationType] = $settings; } $this->configurations[$configurationType]['TYPO3']['Flow']['core']['context'] = (string) $this->context; break; case self::CONFIGURATION_PROCESSING_TYPE_OBJECTS: $this->configurations[$configurationType] = array(); /** @var $package PackageInterface */ foreach ($packages as $packageKey => $package) { $configuration = $this->configurationSource->load($package->getConfigurationPath() . $configurationType); $configuration = Arrays::arrayMergeRecursiveOverrule($configuration, $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $configurationType)); foreach ($this->orderedListOfContextNames as $contextName) { $configuration = Arrays::arrayMergeRecursiveOverrule($configuration, $this->configurationSource->load($package->getConfigurationPath() . $contextName . '/' . $configurationType)); $configuration = Arrays::arrayMergeRecursiveOverrule($configuration, $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $contextName . '/' . $configurationType)); } $this->configurations[$configurationType][$packageKey] = $configuration; } break; case self::CONFIGURATION_PROCESSING_TYPE_POLICY: if ($this->context->isTesting()) { $testingPolicyPathAndFilename = $this->environment->getPathToTemporaryDirectory() . 'Policy'; if ($this->configurationSource->has($testingPolicyPathAndFilename)) { $this->configurations[$configurationType] = $this->configurationSource->load($testingPolicyPathAndFilename); break; } } $this->configurations[$configurationType] = array(); /** @var $package PackageInterface */ foreach ($packages as $package) { $packagePolicyConfiguration = $this->configurationSource->load($package->getConfigurationPath() . $configurationType, $allowSplitSource); $this->validatePolicyConfiguration($packagePolicyConfiguration, $package); $this->configurations[$configurationType] = $this->mergePolicyConfiguration($this->configurations[$configurationType], $packagePolicyConfiguration); } $this->configurations[$configurationType] = $this->mergePolicyConfiguration($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $configurationType, $allowSplitSource)); foreach ($this->orderedListOfContextNames as $contextName) { /** @var $package PackageInterface */ foreach ($packages as $package) { $packagePolicyConfiguration = $this->configurationSource->load($package->getConfigurationPath() . $contextName . '/' . $configurationType, $allowSplitSource); $this->validatePolicyConfiguration($packagePolicyConfiguration, $package); $this->configurations[$configurationType] = $this->mergePolicyConfiguration($this->configurations[$configurationType], $packagePolicyConfiguration); } $this->configurations[$configurationType] = $this->mergePolicyConfiguration($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $contextName . '/' . $configurationType, $allowSplitSource)); } break; case self::CONFIGURATION_PROCESSING_TYPE_DEFAULT: $this->configurations[$configurationType] = array(); /** @var $package PackageInterface */ foreach ($packages as $package) { $this->configurations[$configurationType] = Arrays::arrayMergeRecursiveOverrule($this->configurations[$configurationType], $this->configurationSource->load($package->getConfigurationPath() . $configurationType, $allowSplitSource)); } $this->configurations[$configurationType] = Arrays::arrayMergeRecursiveOverrule($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $configurationType, $allowSplitSource)); foreach ($this->orderedListOfContextNames as $contextName) { /** @var $package PackageInterface */ foreach ($packages as $package) { $this->configurations[$configurationType] = Arrays::arrayMergeRecursiveOverrule($this->configurations[$configurationType], $this->configurationSource->load($package->getConfigurationPath() . $contextName . '/' . $configurationType, $allowSplitSource)); } $this->configurations[$configurationType] = Arrays::arrayMergeRecursiveOverrule($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $contextName . '/' . $configurationType, $allowSplitSource)); } break; case self::CONFIGURATION_PROCESSING_TYPE_ROUTES: // load main routes $this->configurations[$configurationType] = array(); foreach (array_reverse($this->orderedListOfContextNames) as $contextName) { $this->configurations[$configurationType] = array_merge($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $contextName . '/' . $configurationType)); } $this->configurations[$configurationType] = array_merge($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $configurationType)); // Merge routes with SubRoutes recursively $this->mergeRoutesWithSubRoutes($this->configurations[$configurationType]); break; case self::CONFIGURATION_PROCESSING_TYPE_APPEND: $this->configurations[$configurationType] = array(); /** @var $package PackageInterface */ foreach ($packages as $package) { $this->configurations[$configurationType] = array_merge($this->configurations[$configurationType], $this->configurationSource->load($package->getConfigurationPath() . $configurationType, $allowSplitSource)); } $this->configurations[$configurationType] = array_merge($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $configurationType, $allowSplitSource)); foreach ($this->orderedListOfContextNames as $contextName) { foreach ($packages as $package) { $this->configurations[$configurationType] = array_merge($this->configurations[$configurationType], $this->configurationSource->load($package->getConfigurationPath() . $contextName . '/' . $configurationType, $allowSplitSource)); } $this->configurations[$configurationType] = array_merge($this->configurations[$configurationType], $this->configurationSource->load(FLOW_PATH_CONFIGURATION . $contextName . '/' . $configurationType, $allowSplitSource)); } break; default: throw new Exception\InvalidConfigurationTypeException('Configuration type "' . $configurationType . '" cannot be loaded with loadConfiguration().', 1251450613); } $this->postProcessConfiguration($this->configurations[$configurationType]); }
/** * Exports the internal reflection data into the ReflectionData cache * * This method is triggered by a signal which is connected to the bootstrap's * shutdown sequence. * * If the reflection data has previously been loaded from the runtime cache, * saving it is omitted as changes are not expected. * * In Production context the whole cache is written at once and then frozen in * order to be consistent. Frozen cache data in Development is only produced for * classes contained in frozen packages. * * @return void * @throws \TYPO3\Flow\Reflection\Exception if no cache has been injected */ public function saveToCache() { if (!$this->initialized) { $this->initialize(); } if ($this->loadFromClassSchemaRuntimeCache === TRUE) { return; } if (!$this->reflectionDataCompiletimeCache instanceof FrontendInterface) { throw new Exception('A cache must be injected before initializing the Reflection Service.', 1232044697); } if (count($this->updatedReflectionData) > 0) { $this->log(sprintf('Found %s classes whose reflection data was not cached previously.', count($this->updatedReflectionData)), LOG_DEBUG); foreach (array_keys($this->updatedReflectionData) as $className) { $this->statusCache->set(str_replace('\\', '_', $className), ''); } $data = array(); $propertyNames = array('classReflectionData', 'classSchemata', 'annotatedClasses', 'classesByMethodAnnotations'); foreach ($propertyNames as $propertyName) { $data[$propertyName] = $this->{$propertyName}; } $this->reflectionDataCompiletimeCache->set('ReflectionData', $data); } if ($this->context->isProduction()) { $this->reflectionDataRuntimeCache->flush(); $classNames = array(); foreach ($this->classReflectionData as $className => $reflectionData) { $classNames[$className] = TRUE; $this->reflectionDataRuntimeCache->set(str_replace('\\', '_', $className), $reflectionData); if (isset($this->classSchemata[$className])) { $this->classSchemataRuntimeCache->set(str_replace('\\', '_', $className), $this->classSchemata[$className]); } } $this->reflectionDataRuntimeCache->set('__classNames', $classNames); $this->reflectionDataRuntimeCache->set('__annotatedClasses', $this->annotatedClasses); $this->reflectionDataRuntimeCache->getBackend()->freeze(); $this->classSchemataRuntimeCache->getBackend()->freeze(); $this->log(sprintf('Built and froze reflection runtime caches (%s classes).', count($this->classReflectionData)), LOG_INFO); } elseif ($this->context->isDevelopment()) { foreach (array_keys($this->packageManager->getFrozenPackages()) as $packageKey) { $pathAndFilename = $this->getPrecompiledReflectionStoragePath() . $packageKey . '.dat'; if (!file_exists($pathAndFilename)) { $this->log(sprintf('Rebuilding precompiled reflection data for frozen package %s.', $packageKey), LOG_INFO); $this->freezePackageReflection($packageKey); } } } }