/** * Check if filters are properly assigned to resource. * * @param ContainerInterface $container Current container. * @param LibraryDefinitionInterface $definition Current definition. * @param ResourceInterface $resource Current resource. * @throws ConfigurationException */ private function checkFiltersAssignment(ContainerInterface $container, LibraryDefinitionInterface $definition, ResourceInterface $resource) { if ($this->options['check_filter_assignment']) { if (isset($resource->getOptions()['filters'])) { $filters = $resource->getOptions()['filters']; if (!is_array($filters)) { throw new ConfigurationException(sprintf('Expected array of filters for assigned for resource "%s" in definition "%s", "%s" given.', $resource->getSource(), $definition->getName(), gettype($filters))); } if ($resource instanceof ReferenceResource) { throw new ConfigurationException(sprintf('You can not assign filters for reference resource "%s" in definition "%s".', $resource->getSource(), $definition->getName())); } $filters = array_map(function ($filter) { return ltrim($filter, '?'); }, $filters); if (count($duplicates = array_unique(array_diff_assoc($filters, array_unique($filters)))) > 0) { throw new ConfigurationException(sprintf('Filters "%s" for resource "%s" in definition "%s" are used more than once.', implode('", "', $duplicates), $resource->getSource(), $definition->getName())); } } } }
/** * Checks for circular references within the definitions in ContainerInterface using recursive function and * pointer to processed definitions list. * * @param ContainerInterface $container Container to check. * @param LibraryDefinitionInterface $definition Library definition to process. * @param array $registeredReferences List of already processed definitions in path. * @throws CircularReferenceException If circular reference is detected. */ private function doCheckCircularReferences(ContainerInterface $container, LibraryDefinitionInterface $definition, array $registeredReferences) { /** * @var ResourceInterface $resource */ foreach ($resources = $definition->getResources() as $resource) { /** * @var ReferenceResource $resource */ if ($resource instanceof ReferenceResource) { if (array_key_exists($resource->getSource(), $registeredReferences)) { throw new CircularReferenceException(sprintf('Circular reference detected at definition "%s", dependency chain (path: [%s] => [%s]).', $resource->getSource(), implode('] => [', $registeredReferences), $resource->getSource())); } else { $newPath = $registeredReferences; $newPath[$resource->getSource()] = $resource->getSource(); $this->doCheckCircularReferences($container, $container->getLibraries()->getDefinition($resource->getSource()), $newPath); } } } }
/** * Process one single library definition resolving referenced dependencies. * * @param LibraryDefinitionInterface $definition Library definition to process. * @param ContainerInterface $container Container which is subject of process. * @param array $processedDefinitions List of already processed definitions. * @param int $count Number of processed definition for detecting circular references. * @throws CircularReferenceException If circular reference is detected. */ private function processDefinition(LibraryDefinitionInterface $definition, ContainerInterface $container, array &$processedDefinitions, &$count = 0) { $count++; if ($count > count($container->getLibraries()->getDefinitions())) { throw new CircularReferenceException('Circular reference detected.'); } /** * @var ResourceInterface $resource */ foreach ($resources = $definition->getResources() as $resource) { /** * @var ReferenceResource $resource */ if ($resource instanceof ReferenceResource) { if (!isset($processedDefinitions[$resource->getSource()])) { $this->processDefinition($container->getLibraries()->getDefinition($resource->getSource()), $container, $processedDefinitions, $count); } $definition->replaceResource($resource, array_filter($this->getReferencedResources($resource, $container), function (ResourceInterface $replacement) use($definition) { return !in_array($replacement, $definition->getResources()); })); } } $processedDefinitions[$definition->getName()] = $definition->getName(); }
/** * Check if definition name is valid. * * @param ContainerInterface $container Current container. * @param LibraryDefinitionInterface $definition Current definition. */ public function checkDefinitionName(ContainerInterface $container, LibraryDefinitionInterface $definition) { if (!ctype_alnum(str_replace(array('-', '_', '/'), '', $definition->getName()))) { throw new InvalidArgumentException(sprintf('Library definition name "%s" is not valid.', $definition->getName())); } }