This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Registers additional validators.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class DoctrineValidationPass implements CompilerPassInterface
{
private $managerType;
/**
* @param string $managerType
*/
public function __construct($managerType)
{
$this->managerType = $managerType;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$this->updateValidatorMappingFiles($container, 'xml', 'xml');
$this->updateValidatorMappingFiles($container, 'yaml', 'yml');
}
/**
* Gets the validation mapping files for the format and extends them with
* files matching a doctrine search pattern (Resources/config/validation.orm.xml).
*
* @param ContainerBuilder $container
* @param string $mapping
* @param string $extension
*/
private function updateValidatorMappingFiles(ContainerBuilder $container, $mapping, $extension)
{
if (!$container->hasParameter('validator.mapping.loader.'.$mapping.'_files_loader.mapping_files')) {
return;
}
$files = $container->getParameter('validator.mapping.loader.'.$mapping.'_files_loader.mapping_files');
$validationPath = 'Resources/config/validation.'.$this->managerType.'.'.$extension;
foreach ($container->getParameter('kernel.bundles') as $bundle) {
$reflection = new \ReflectionClass($bundle);
if (is_file($file = \dirname($reflection->getFileName()).'/'.$validationPath)) {
$files[] = $file;
$container->addResource(new FileResource($file));
}
}
$container->setParameter('validator.mapping.loader.'.$mapping.'_files_loader.mapping_files', $files);
}
}

View File

@@ -0,0 +1,161 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers event listeners and subscribers to the available doctrine connections.
*
* @author Jeremy Mikola <jmikola@gmail.com>
* @author Alexander <iam.asm89@gmail.com>
* @author David Maicher <mail@dmaicher.de>
*/
class RegisterEventListenersAndSubscribersPass implements CompilerPassInterface
{
private $connections;
private $eventManagers;
private $managerTemplate;
private $tagPrefix;
/**
* @param string $connections Parameter ID for connections
* @param string $managerTemplate sprintf() template for generating the event
* manager's service ID for a connection name
* @param string $tagPrefix Tag prefix for listeners and subscribers
*/
public function __construct($connections, $managerTemplate, $tagPrefix)
{
$this->connections = $connections;
$this->managerTemplate = $managerTemplate;
$this->tagPrefix = $tagPrefix;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasParameter($this->connections)) {
return;
}
$this->connections = $container->getParameter($this->connections);
$this->addTaggedSubscribers($container);
$this->addTaggedListeners($container);
}
private function addTaggedSubscribers(ContainerBuilder $container)
{
$subscriberTag = $this->tagPrefix.'.event_subscriber';
$taggedSubscribers = $this->findAndSortTags($subscriberTag, $container);
foreach ($taggedSubscribers as $taggedSubscriber) {
$id = $taggedSubscriber[0];
$taggedSubscriberDef = $container->getDefinition($id);
if ($taggedSubscriberDef->isAbstract()) {
throw new InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event subscriber.', $id));
}
$tag = $taggedSubscriber[1];
$connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections);
foreach ($connections as $con) {
if (!isset($this->connections[$con])) {
throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections))));
}
$this->getEventManagerDef($container, $con)->addMethodCall('addEventSubscriber', array(new Reference($id)));
}
}
}
private function addTaggedListeners(ContainerBuilder $container)
{
$listenerTag = $this->tagPrefix.'.event_listener';
$taggedListeners = $this->findAndSortTags($listenerTag, $container);
foreach ($taggedListeners as $taggedListener) {
$id = $taggedListener[0];
$taggedListenerDef = $container->getDefinition($taggedListener[0]);
if ($taggedListenerDef->isAbstract()) {
throw new InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event listener.', $id));
}
$tag = $taggedListener[1];
if (!isset($tag['event'])) {
throw new InvalidArgumentException(sprintf('Doctrine event listener "%s" must specify the "event" attribute.', $id));
}
$connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections);
foreach ($connections as $con) {
if (!isset($this->connections[$con])) {
throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections))));
}
if ($lazy = !empty($tag['lazy'])) {
$taggedListenerDef->setPublic(true);
}
// we add one call per event per service so we have the correct order
$this->getEventManagerDef($container, $con)->addMethodCall('addEventListener', array(array($tag['event']), $lazy ? $id : new Reference($id)));
}
}
}
private function getEventManagerDef(ContainerBuilder $container, $name)
{
if (!isset($this->eventManagers[$name])) {
$this->eventManagers[$name] = $container->getDefinition(sprintf($this->managerTemplate, $name));
}
return $this->eventManagers[$name];
}
/**
* Finds and orders all service tags with the given name by their priority.
*
* The order of additions must be respected for services having the same priority,
* and knowing that the \SplPriorityQueue class does not respect the FIFO method,
* we should not use this class.
*
* @see https://bugs.php.net/bug.php?id=53710
* @see https://bugs.php.net/bug.php?id=60926
*
* @param string $tagName
* @param ContainerBuilder $container
*
* @return array
*/
private function findAndSortTags($tagName, ContainerBuilder $container)
{
$sortedTags = array();
foreach ($container->findTaggedServiceIds($tagName) as $serviceId => $tags) {
foreach ($tags as $attributes) {
$priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
$sortedTags[$priority][] = array($serviceId, $attributes);
}
}
if ($sortedTags) {
krsort($sortedTags);
$sortedTags = \call_user_func_array('array_merge', $sortedTags);
}
return $sortedTags;
}
}

View File

@@ -0,0 +1,241 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Base class for the doctrine bundles to provide a compiler pass class that
* helps to register doctrine mappings.
*
* The compiler pass is meant to register the mappings with the metadata
* chain driver corresponding to one of the object managers.
*
* For concrete implementations that are easy to use, see the
* RegisterXyMappingsPass classes in the DoctrineBundle resp.
* DoctrineMongodbBundle, DoctrineCouchdbBundle and DoctrinePhpcrBundle.
*
* @author David Buchmann <david@liip.ch>
*/
abstract class RegisterMappingsPass implements CompilerPassInterface
{
/**
* DI object for the driver to use, either a service definition for a
* private service or a reference for a public service.
*
* @var Definition|Reference
*/
protected $driver;
/**
* List of namespaces handled by the driver.
*
* @var string[]
*/
protected $namespaces;
/**
* List of potential container parameters that hold the object manager name
* to register the mappings with the correct metadata driver, for example
* array('acme.manager', 'doctrine.default_entity_manager').
*
* @var string[]
*/
protected $managerParameters;
/**
* Naming pattern of the metadata chain driver service ids, for example
* 'doctrine.orm.%s_metadata_driver'.
*
* @var string
*/
protected $driverPattern;
/**
* A name for a parameter in the container. If set, this compiler pass will
* only do anything if the parameter is present. (But regardless of the
* value of that parameter.
*
* @var string|false
*/
protected $enabledParameter;
/**
* Naming pattern for the configuration service id, for example
* 'doctrine.orm.%s_configuration'.
*
* @var string
*/
private $configurationPattern;
/**
* Method name to call on the configuration service. This depends on the
* Doctrine implementation. For example addEntityNamespace.
*
* @var string
*/
private $registerAliasMethodName;
/**
* Map of alias to namespace.
*
* @var string[]
*/
private $aliasMap;
/**
* The $managerParameters is an ordered list of container parameters that could provide the
* name of the manager to register these namespaces and alias on. The first non-empty name
* is used, the others skipped.
*
* The $aliasMap parameter can be used to define bundle namespace shortcuts like the
* DoctrineBundle provides automatically for objects in the default Entity/Document folder.
*
* @param Definition|Reference $driver Driver DI definition or reference
* @param string[] $namespaces List of namespaces handled by $driver
* @param string[] $managerParameters list of container parameters that could
* hold the manager name
* @param string $driverPattern Pattern for the metadata driver service name
* @param string|false $enabledParameter Service container parameter that must be
* present to enable the mapping. Set to false
* to not do any check, optional.
* @param string $configurationPattern Pattern for the Configuration service name
* @param string $registerAliasMethodName Name of Configuration class method to
* register alias
* @param string[] $aliasMap Map of alias to namespace
*/
public function __construct($driver, array $namespaces, array $managerParameters, $driverPattern, $enabledParameter = false, $configurationPattern = '', $registerAliasMethodName = '', array $aliasMap = array())
{
$this->driver = $driver;
$this->namespaces = $namespaces;
$this->managerParameters = $managerParameters;
$this->driverPattern = $driverPattern;
$this->enabledParameter = $enabledParameter;
if (\count($aliasMap) && (!$configurationPattern || !$registerAliasMethodName)) {
throw new \InvalidArgumentException('configurationPattern and registerAliasMethodName are required to register namespace alias');
}
$this->configurationPattern = $configurationPattern;
$this->registerAliasMethodName = $registerAliasMethodName;
$this->aliasMap = $aliasMap;
}
/**
* Register mappings and alias with the metadata drivers.
*/
public function process(ContainerBuilder $container)
{
if (!$this->enabled($container)) {
return;
}
$mappingDriverDef = $this->getDriver($container);
$chainDriverDefService = $this->getChainDriverServiceName($container);
// Definition for a Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain
$chainDriverDef = $container->getDefinition($chainDriverDefService);
foreach ($this->namespaces as $namespace) {
$chainDriverDef->addMethodCall('addDriver', array($mappingDriverDef, $namespace));
}
if (!\count($this->aliasMap)) {
return;
}
$configurationServiceName = $this->getConfigurationServiceName($container);
// Definition of the Doctrine\...\Configuration class specific to the Doctrine flavour.
$configurationServiceDefinition = $container->getDefinition($configurationServiceName);
foreach ($this->aliasMap as $alias => $namespace) {
$configurationServiceDefinition->addMethodCall($this->registerAliasMethodName, array($alias, $namespace));
}
}
/**
* Get the service name of the metadata chain driver that the mappings
* should be registered with.
*
* @return string The name of the chain driver service
*
* @throws ParameterNotFoundException if non of the managerParameters has a
* non-empty value
*/
protected function getChainDriverServiceName(ContainerBuilder $container)
{
return sprintf($this->driverPattern, $this->getManagerName($container));
}
/**
* Create the service definition for the metadata driver.
*
* @param ContainerBuilder $container Passed on in case an extending class
* needs access to the container
*
* @return Definition|Reference the metadata driver to add to all chain drivers
*/
protected function getDriver(ContainerBuilder $container)
{
return $this->driver;
}
/**
* Get the service name from the pattern and the configured manager name.
*
* @return string a service definition name
*
* @throws ParameterNotFoundException if none of the managerParameters has a
* non-empty value
*/
private function getConfigurationServiceName(ContainerBuilder $container)
{
return sprintf($this->configurationPattern, $this->getManagerName($container));
}
/**
* Determine the manager name.
*
* The default implementation loops over the managerParameters and returns
* the first non-empty parameter.
*
* @return string The name of the active manager
*
* @throws ParameterNotFoundException if none of the managerParameters is found in the container
*/
private function getManagerName(ContainerBuilder $container)
{
foreach ($this->managerParameters as $param) {
if ($container->hasParameter($param)) {
$name = $container->getParameter($param);
if ($name) {
return $name;
}
}
}
throw new ParameterNotFoundException('Could not determine the Doctrine manager. Either Doctrine is not configured or a bundle is misconfigured.');
}
/**
* Determine whether this mapping should be activated or not. This allows
* to take this decision with the container builder available.
*
* This default implementation checks if the class has the enabledParameter
* configured and if so if that parameter is present in the container.
*
* @return bool whether this compiler pass really should register the mappings
*/
protected function enabled(ContainerBuilder $container)
{
return !$this->enabledParameter || $container->hasParameter($this->enabledParameter);
}
}