[ static::class, 'configureMiddlewares' ], 'backend.routes' => [ static::class, 'configureBackendRoutes' ], 'backend.modules' => [ static::class, 'configureBackendModules' ], 'content.security.policies' => [ static::class, 'configureContentSecurityPolicies' ], 'icons' => [ static::class, 'configureIcons' ], 'fluid.namespaces' => [ static::class, 'configureFluidNamespaces' ], 'fluid.component.collections' => [ static::class, 'configureFluidComponentCollections' ], SetCollector::class => [ static::class, 'configureSetCollector' ], ]; } public static function configureFluidNamespaces(ContainerInterface $container, \ArrayObject $namespaces, ?string $path = null): \ArrayObject { $packageConfiguration = ($path ?? static::getPackagePath()) . 'Configuration/Fluid/Namespaces.php'; if (file_exists($packageConfiguration)) { $namespacesInPackage = self::requireFile($packageConfiguration); if (is_array($namespacesInPackage)) { $namespaces->exchangeArray(array_merge_recursive($namespaces->getArrayCopy(), $namespacesInPackage)); } } return $namespaces; } public static function configureFluidComponentCollections(ContainerInterface $container, \ArrayObject $componentCollections, ?string $path = null): \ArrayObject { $packageConfiguration = ($path ?? static::getPackagePath()) . 'Configuration/Fluid/ComponentCollections.php'; if (file_exists($packageConfiguration)) { $componentCollectionsInPackage = self::requireFile($packageConfiguration); if (is_array($componentCollectionsInPackage)) { $componentCollections->exchangeArray(array_replace_recursive($componentCollections->getArrayCopy(), $componentCollectionsInPackage)); } } return $componentCollections; } /** * @param string|null $path supplied when invoked internally through PseudoServiceProvider */ public static function configureMiddlewares(ContainerInterface $container, \ArrayObject $middlewares, ?string $path = null): \ArrayObject { $packageConfiguration = ($path ?? static::getPackagePath()) . 'Configuration/RequestMiddlewares.php'; if (file_exists($packageConfiguration)) { $middlewaresInPackage = self::requireFile($packageConfiguration); if (is_array($middlewaresInPackage)) { $middlewares->exchangeArray(array_replace_recursive($middlewares->getArrayCopy(), $middlewaresInPackage)); } } return $middlewares; } /** * @param string|null $path supplied when invoked internally through PseudoServiceProvider * @param string|null $packageName supplied when invoked internally through PseudoServiceProvider */ public static function configureBackendRoutes(ContainerInterface $container, \ArrayObject $routes, ?string $path = null, ?string $packageName = null): \ArrayObject { $path = $path ?? static::getPackagePath(); $packageName = $packageName ?? static::getPackageName(); $routesFileNameForPackage = $path . 'Configuration/Backend/Routes.php'; if (file_exists($routesFileNameForPackage)) { $definedRoutesInPackage = self::requireFile($routesFileNameForPackage); if (is_array($definedRoutesInPackage)) { array_walk($definedRoutesInPackage, static function (array &$options) use ($packageName, $path): void { // Add packageName and absolutePackagePath to all routes $options['packageName'] = $packageName; $options['absolutePackagePath'] = $path; }); $routes->exchangeArray(array_merge($routes->getArrayCopy(), $definedRoutesInPackage)); } } $routesFileNameForPackage = $path . 'Configuration/Backend/AjaxRoutes.php'; if (file_exists($routesFileNameForPackage)) { $definedRoutesInPackage = self::requireFile($routesFileNameForPackage); if (is_array($definedRoutesInPackage)) { foreach ($definedRoutesInPackage as $routeIdentifier => $routeOptions) { // prefix the route with "ajax_" as "namespace" $routeOptions['path'] = '/ajax' . $routeOptions['path']; $routeOptions['packageName'] = $packageName; $routeOptions['absolutePackagePath'] = $path; $routes['ajax_' . $routeIdentifier] = $routeOptions; $routes['ajax_' . $routeIdentifier]['ajax'] = true; } } } return $routes; } /** * @param string|null $path supplied when invoked internally through PseudoServiceProvider * @param string|null $packageName supplied when invoked internally through PseudoServiceProvider */ public static function configureBackendModules(ContainerInterface $container, \ArrayObject $modules, ?string $path = null, ?string $packageName = null): \ArrayObject { $path = $path ?? static::getPackagePath(); $packageName = $packageName ?? static::getPackageName(); $modulesFileNameForPackage = $path . 'Configuration/Backend/Modules.php'; if (file_exists($modulesFileNameForPackage)) { $definedModulesInPackage = self::requireFile($modulesFileNameForPackage); if (is_array($definedModulesInPackage)) { array_walk($definedModulesInPackage, static function (array &$module) use ($packageName, $path): void { // Add packageName and absolutePackagePath to all modules $module['packageName'] = $packageName; $module['absolutePackagePath'] = $path; }); $modules->exchangeArray(array_merge($modules->getArrayCopy(), $definedModulesInPackage)); } } return $modules; } /** * @param Map> $mutations * @return Map> */ public static function configureContentSecurityPolicies(ContainerInterface $container, Map $mutations, ?string $path = null, ?string $packageName = null): Map { $path = $path ?? static::getPackagePath(); $packageName = $packageName ?? static::getPackageName(); $fileName = $path . 'Configuration/ContentSecurityPolicies.php'; if (file_exists($fileName)) { /** @var Map $mutationsInPackage */ $mutationsInPackage = self::requireFile($fileName); foreach ($mutationsInPackage as $scope => $mutation) { if (!isset($mutations[$scope])) { $mutations[$scope] = new Map(); } $origin = new MutationOrigin(MutationOriginType::package, $packageName); $mutations[$scope][$origin] = $mutation; } } return $mutations; } public static function configureIcons(ContainerInterface $container, \ArrayObject $icons, ?string $path = null): \ArrayObject { $path = $path ?? static::getPackagePath(); $iconsFileNameForPackage = $path . 'Configuration/Icons.php'; if (file_exists($iconsFileNameForPackage)) { $definedIconsInPackage = self::requireFile($iconsFileNameForPackage); if (is_array($definedIconsInPackage)) { $icons->exchangeArray(array_merge($icons->getArrayCopy(), $definedIconsInPackage)); } } return $icons; } public static function configureSetCollector( ContainerInterface $container, SetCollector $setCollector, ?string $path = null, ?string $packageName = null, ): SetCollector { $path ??= static::getPackagePath(); $packageName ??= static::getPackageName(); $extensionKey = $container->get(PackageManager::class)->getPackage($packageName)->getPackageKey(); $setPath = $path . 'Configuration/Sets'; try { $finder = Finder::create() ->files() ->sortByName() ->depth(1) ->ignoreUnreadableDirs() ->name('config.yaml') ->in($setPath); } catch (\InvalidArgumentException) { // No such directory in this package return $setCollector; } $setProvider = $container->get(YamlSetDefinitionProvider::class); foreach ($finder as $fileInfo) { $errorMap = [ InvalidSettingsDefinitionsException::class => [ 'error' => SetError::invalidSettingsDefinitions, 'logLine' => 'Set {setName} invalidated {file} because of invalid settings.definitions.yaml: {reason}', ], InvalidCategoryDefinitionsException::class => [ 'error' => SetError::invalidCategoryDefinitions, 'logLine' => 'Set {setName} invalidated {file} because of invalid category in settings.definitions.yaml: {reason}', ], InvalidSettingsException::class => [ 'error' => SetError::invalidSettings, 'logLine' => 'Set {setName} invalidated {file} because of invalid settings.yaml: {reason}', ], InvalidSetRouteEnhancersException::class => [ 'error' => SetError::invalidRouteEnhancers, 'logLine' => 'Set {setName} invalidated {file} because of invalid route-enhancers.yaml: {reason}', ], InvalidSetException::class => [ 'error' => SetError::invalidSet, 'logLine' => 'Invalid set {setName} in {file}: {reason}', ], ]; try { $virtualSetPath = 'EXT:' . $extensionKey . '/Configuration/Sets/' . basename(dirname($fileInfo->getPathname())) . '/'; $setCollector->add($setProvider->get($fileInfo, $virtualSetPath)); } catch (InvalidSettingsDefinitionsException|InvalidCategoryDefinitionsException|InvalidSettingsException|InvalidSetRouteEnhancersException|InvalidSetException $e) { $errorDetails = $errorMap[get_class($e)]; $setCollector->addError( $errorDetails['error'], $e->getSetName(), $e->getMessage(), ); $logger = $container->get(LogManager::class)->getLogger(self::class); $logger->error($errorDetails['logLine'], [ 'file' => $fileInfo->getPathname(), 'setName' => $e->getSetName(), 'reason' => $e->getMessage(), ]); } } return $setCollector; } /** * Create an instance of a class. Supports auto injection of the logger. * * @param string $className name of the class to instantiate, must not be empty and not start with a backslash * @param array $constructorArguments Arguments for the constructor * @return mixed */ protected static function new(ContainerInterface $container, string $className, array $constructorArguments = []) { // Support $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'] (xclasses) and class alias maps $instance = GeneralUtility::makeInstanceForDi($className, ...$constructorArguments); if ($instance instanceof LoggerAwareInterface) { $instance->setLogger($container->get(LogManager::class)->getLogger($className)); } return $instance; } /** * Require a file in a safe scoped environment avoiding local variable clashes. */ protected static function requireFile(string $filename): mixed { return require $filename; } }