vendor/symfony/dependency-injection/Definition.php line 713

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\Argument\BoundArgument;
  12. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  13. use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
  14. /**
  15.  * Definition represents a service definition.
  16.  *
  17.  * @author Fabien Potencier <fabien@symfony.com>
  18.  */
  19. class Definition
  20. {
  21.     private const DEFAULT_DEPRECATION_TEMPLATE 'The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.';
  22.     private $class;
  23.     private $file;
  24.     private $factory;
  25.     private $shared true;
  26.     private $deprecation = [];
  27.     private $properties = [];
  28.     private $calls = [];
  29.     private $instanceof = [];
  30.     private $autoconfigured false;
  31.     private $configurator;
  32.     private $tags = [];
  33.     private $public false;
  34.     private $synthetic false;
  35.     private $abstract false;
  36.     private $lazy false;
  37.     private $decoratedService;
  38.     private $autowired false;
  39.     private $changes = [];
  40.     private $bindings = [];
  41.     private $errors = [];
  42.     protected $arguments = [];
  43.     /**
  44.      * @internal
  45.      *
  46.      * Used to store the name of the inner id when using service decoration together with autowiring
  47.      */
  48.     public $innerServiceId;
  49.     /**
  50.      * @internal
  51.      *
  52.      * Used to store the behavior to follow when using service decoration and the decorated service is invalid
  53.      */
  54.     public $decorationOnInvalid;
  55.     public function __construct(?string $class null, array $arguments = [])
  56.     {
  57.         if (null !== $class) {
  58.             $this->setClass($class);
  59.         }
  60.         $this->arguments $arguments;
  61.     }
  62.     /**
  63.      * Returns all changes tracked for the Definition object.
  64.      *
  65.      * @return array
  66.      */
  67.     public function getChanges()
  68.     {
  69.         return $this->changes;
  70.     }
  71.     /**
  72.      * Sets the tracked changes for the Definition object.
  73.      *
  74.      * @param array $changes An array of changes for this Definition
  75.      *
  76.      * @return $this
  77.      */
  78.     public function setChanges(array $changes)
  79.     {
  80.         $this->changes $changes;
  81.         return $this;
  82.     }
  83.     /**
  84.      * Sets a factory.
  85.      *
  86.      * @param string|array|Reference|null $factory A PHP function, reference or an array containing a class/Reference and a method to call
  87.      *
  88.      * @return $this
  89.      */
  90.     public function setFactory($factory)
  91.     {
  92.         $this->changes['factory'] = true;
  93.         if (\is_string($factory) && str_contains($factory'::')) {
  94.             $factory explode('::'$factory2);
  95.         } elseif ($factory instanceof Reference) {
  96.             $factory = [$factory'__invoke'];
  97.         }
  98.         $this->factory $factory;
  99.         return $this;
  100.     }
  101.     /**
  102.      * Gets the factory.
  103.      *
  104.      * @return string|array|null The PHP function or an array containing a class/Reference and a method to call
  105.      */
  106.     public function getFactory()
  107.     {
  108.         return $this->factory;
  109.     }
  110.     /**
  111.      * Sets the service that this service is decorating.
  112.      *
  113.      * @param string|null $id        The decorated service id, use null to remove decoration
  114.      * @param string|null $renamedId The new decorated service id
  115.      *
  116.      * @return $this
  117.      *
  118.      * @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals
  119.      */
  120.     public function setDecoratedService(?string $id, ?string $renamedId nullint $priority 0int $invalidBehavior ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
  121.     {
  122.         if ($renamedId && $id === $renamedId) {
  123.             throw new InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.'$id));
  124.         }
  125.         $this->changes['decorated_service'] = true;
  126.         if (null === $id) {
  127.             $this->decoratedService null;
  128.         } else {
  129.             $this->decoratedService = [$id$renamedId$priority];
  130.             if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
  131.                 $this->decoratedService[] = $invalidBehavior;
  132.             }
  133.         }
  134.         return $this;
  135.     }
  136.     /**
  137.      * Gets the service that this service is decorating.
  138.      *
  139.      * @return array|null An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated
  140.      */
  141.     public function getDecoratedService()
  142.     {
  143.         return $this->decoratedService;
  144.     }
  145.     /**
  146.      * Sets the service class.
  147.      *
  148.      * @return $this
  149.      */
  150.     public function setClass(?string $class)
  151.     {
  152.         $this->changes['class'] = true;
  153.         $this->class $class;
  154.         return $this;
  155.     }
  156.     /**
  157.      * Gets the service class.
  158.      *
  159.      * @return string|null
  160.      */
  161.     public function getClass()
  162.     {
  163.         return $this->class;
  164.     }
  165.     /**
  166.      * Sets the arguments to pass to the service constructor/factory method.
  167.      *
  168.      * @return $this
  169.      */
  170.     public function setArguments(array $arguments)
  171.     {
  172.         $this->arguments $arguments;
  173.         return $this;
  174.     }
  175.     /**
  176.      * Sets the properties to define when creating the service.
  177.      *
  178.      * @return $this
  179.      */
  180.     public function setProperties(array $properties)
  181.     {
  182.         $this->properties $properties;
  183.         return $this;
  184.     }
  185.     /**
  186.      * Gets the properties to define when creating the service.
  187.      *
  188.      * @return array
  189.      */
  190.     public function getProperties()
  191.     {
  192.         return $this->properties;
  193.     }
  194.     /**
  195.      * Sets a specific property.
  196.      *
  197.      * @param mixed $value
  198.      *
  199.      * @return $this
  200.      */
  201.     public function setProperty(string $name$value)
  202.     {
  203.         $this->properties[$name] = $value;
  204.         return $this;
  205.     }
  206.     /**
  207.      * Adds an argument to pass to the service constructor/factory method.
  208.      *
  209.      * @param mixed $argument An argument
  210.      *
  211.      * @return $this
  212.      */
  213.     public function addArgument($argument)
  214.     {
  215.         $this->arguments[] = $argument;
  216.         return $this;
  217.     }
  218.     /**
  219.      * Replaces a specific argument.
  220.      *
  221.      * @param int|string $index
  222.      * @param mixed      $argument
  223.      *
  224.      * @return $this
  225.      *
  226.      * @throws OutOfBoundsException When the replaced argument does not exist
  227.      */
  228.     public function replaceArgument($index$argument)
  229.     {
  230.         if (=== \count($this->arguments)) {
  231.             throw new OutOfBoundsException(sprintf('Cannot replace arguments for class "%s" if none have been configured yet.'$this->class));
  232.         }
  233.         if (\is_int($index) && ($index || $index > \count($this->arguments) - 1)) {
  234.             throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d] of the arguments of class "%s".'$index, \count($this->arguments) - 1$this->class));
  235.         }
  236.         if (!\array_key_exists($index$this->arguments)) {
  237.             throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist in class "%s".'$index$this->class));
  238.         }
  239.         $this->arguments[$index] = $argument;
  240.         return $this;
  241.     }
  242.     /**
  243.      * Sets a specific argument.
  244.      *
  245.      * @param int|string $key
  246.      * @param mixed      $value
  247.      *
  248.      * @return $this
  249.      */
  250.     public function setArgument($key$value)
  251.     {
  252.         $this->arguments[$key] = $value;
  253.         return $this;
  254.     }
  255.     /**
  256.      * Gets the arguments to pass to the service constructor/factory method.
  257.      *
  258.      * @return array
  259.      */
  260.     public function getArguments()
  261.     {
  262.         return $this->arguments;
  263.     }
  264.     /**
  265.      * Gets an argument to pass to the service constructor/factory method.
  266.      *
  267.      * @param int|string $index
  268.      *
  269.      * @return mixed
  270.      *
  271.      * @throws OutOfBoundsException When the argument does not exist
  272.      */
  273.     public function getArgument($index)
  274.     {
  275.         if (!\array_key_exists($index$this->arguments)) {
  276.             throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist in class "%s".'$index$this->class));
  277.         }
  278.         return $this->arguments[$index];
  279.     }
  280.     /**
  281.      * Sets the methods to call after service initialization.
  282.      *
  283.      * @return $this
  284.      */
  285.     public function setMethodCalls(array $calls = [])
  286.     {
  287.         $this->calls = [];
  288.         foreach ($calls as $call) {
  289.             $this->addMethodCall($call[0], $call[1], $call[2] ?? false);
  290.         }
  291.         return $this;
  292.     }
  293.     /**
  294.      * Adds a method to call after service initialization.
  295.      *
  296.      * @param string $method       The method name to call
  297.      * @param array  $arguments    An array of arguments to pass to the method call
  298.      * @param bool   $returnsClone Whether the call returns the service instance or not
  299.      *
  300.      * @return $this
  301.      *
  302.      * @throws InvalidArgumentException on empty $method param
  303.      */
  304.     public function addMethodCall(string $method, array $arguments = [], bool $returnsClone false)
  305.     {
  306.         if (empty($method)) {
  307.             throw new InvalidArgumentException('Method name cannot be empty.');
  308.         }
  309.         $this->calls[] = $returnsClone ? [$method$argumentstrue] : [$method$arguments];
  310.         return $this;
  311.     }
  312.     /**
  313.      * Removes a method to call after service initialization.
  314.      *
  315.      * @return $this
  316.      */
  317.     public function removeMethodCall(string $method)
  318.     {
  319.         foreach ($this->calls as $i => $call) {
  320.             if ($call[0] === $method) {
  321.                 unset($this->calls[$i]);
  322.             }
  323.         }
  324.         return $this;
  325.     }
  326.     /**
  327.      * Check if the current definition has a given method to call after service initialization.
  328.      *
  329.      * @return bool
  330.      */
  331.     public function hasMethodCall(string $method)
  332.     {
  333.         foreach ($this->calls as $call) {
  334.             if ($call[0] === $method) {
  335.                 return true;
  336.             }
  337.         }
  338.         return false;
  339.     }
  340.     /**
  341.      * Gets the methods to call after service initialization.
  342.      *
  343.      * @return array
  344.      */
  345.     public function getMethodCalls()
  346.     {
  347.         return $this->calls;
  348.     }
  349.     /**
  350.      * Sets the definition templates to conditionally apply on the current definition, keyed by parent interface/class.
  351.      *
  352.      * @param ChildDefinition[] $instanceof
  353.      *
  354.      * @return $this
  355.      */
  356.     public function setInstanceofConditionals(array $instanceof)
  357.     {
  358.         $this->instanceof $instanceof;
  359.         return $this;
  360.     }
  361.     /**
  362.      * Gets the definition templates to conditionally apply on the current definition, keyed by parent interface/class.
  363.      *
  364.      * @return ChildDefinition[]
  365.      */
  366.     public function getInstanceofConditionals()
  367.     {
  368.         return $this->instanceof;
  369.     }
  370.     /**
  371.      * Sets whether or not instanceof conditionals should be prepended with a global set.
  372.      *
  373.      * @return $this
  374.      */
  375.     public function setAutoconfigured(bool $autoconfigured)
  376.     {
  377.         $this->changes['autoconfigured'] = true;
  378.         $this->autoconfigured $autoconfigured;
  379.         return $this;
  380.     }
  381.     /**
  382.      * @return bool
  383.      */
  384.     public function isAutoconfigured()
  385.     {
  386.         return $this->autoconfigured;
  387.     }
  388.     /**
  389.      * Sets tags for this definition.
  390.      *
  391.      * @return $this
  392.      */
  393.     public function setTags(array $tags)
  394.     {
  395.         $this->tags $tags;
  396.         return $this;
  397.     }
  398.     /**
  399.      * Returns all tags.
  400.      *
  401.      * @return array
  402.      */
  403.     public function getTags()
  404.     {
  405.         return $this->tags;
  406.     }
  407.     /**
  408.      * Gets a tag by name.
  409.      *
  410.      * @return array
  411.      */
  412.     public function getTag(string $name)
  413.     {
  414.         return $this->tags[$name] ?? [];
  415.     }
  416.     /**
  417.      * Adds a tag for this definition.
  418.      *
  419.      * @return $this
  420.      */
  421.     public function addTag(string $name, array $attributes = [])
  422.     {
  423.         $this->tags[$name][] = $attributes;
  424.         return $this;
  425.     }
  426.     /**
  427.      * Whether this definition has a tag with the given name.
  428.      *
  429.      * @return bool
  430.      */
  431.     public function hasTag(string $name)
  432.     {
  433.         return isset($this->tags[$name]);
  434.     }
  435.     /**
  436.      * Clears all tags for a given name.
  437.      *
  438.      * @return $this
  439.      */
  440.     public function clearTag(string $name)
  441.     {
  442.         unset($this->tags[$name]);
  443.         return $this;
  444.     }
  445.     /**
  446.      * Clears the tags for this definition.
  447.      *
  448.      * @return $this
  449.      */
  450.     public function clearTags()
  451.     {
  452.         $this->tags = [];
  453.         return $this;
  454.     }
  455.     /**
  456.      * Sets a file to require before creating the service.
  457.      *
  458.      * @return $this
  459.      */
  460.     public function setFile(?string $file)
  461.     {
  462.         $this->changes['file'] = true;
  463.         $this->file $file;
  464.         return $this;
  465.     }
  466.     /**
  467.      * Gets the file to require before creating the service.
  468.      *
  469.      * @return string|null
  470.      */
  471.     public function getFile()
  472.     {
  473.         return $this->file;
  474.     }
  475.     /**
  476.      * Sets if the service must be shared or not.
  477.      *
  478.      * @return $this
  479.      */
  480.     public function setShared(bool $shared)
  481.     {
  482.         $this->changes['shared'] = true;
  483.         $this->shared $shared;
  484.         return $this;
  485.     }
  486.     /**
  487.      * Whether this service is shared.
  488.      *
  489.      * @return bool
  490.      */
  491.     public function isShared()
  492.     {
  493.         return $this->shared;
  494.     }
  495.     /**
  496.      * Sets the visibility of this service.
  497.      *
  498.      * @return $this
  499.      */
  500.     public function setPublic(bool $boolean)
  501.     {
  502.         $this->changes['public'] = true;
  503.         $this->public $boolean;
  504.         return $this;
  505.     }
  506.     /**
  507.      * Whether this service is public facing.
  508.      *
  509.      * @return bool
  510.      */
  511.     public function isPublic()
  512.     {
  513.         return $this->public;
  514.     }
  515.     /**
  516.      * Sets if this service is private.
  517.      *
  518.      * @return $this
  519.      *
  520.      * @deprecated since Symfony 5.2, use setPublic() instead
  521.      */
  522.     public function setPrivate(bool $boolean)
  523.     {
  524.         trigger_deprecation('symfony/dependency-injection''5.2''The "%s()" method is deprecated, use "setPublic()" instead.'__METHOD__);
  525.         return $this->setPublic(!$boolean);
  526.     }
  527.     /**
  528.      * Whether this service is private.
  529.      *
  530.      * @return bool
  531.      */
  532.     public function isPrivate()
  533.     {
  534.         return !$this->public;
  535.     }
  536.     /**
  537.      * Sets the lazy flag of this service.
  538.      *
  539.      * @return $this
  540.      */
  541.     public function setLazy(bool $lazy)
  542.     {
  543.         $this->changes['lazy'] = true;
  544.         $this->lazy $lazy;
  545.         return $this;
  546.     }
  547.     /**
  548.      * Whether this service is lazy.
  549.      *
  550.      * @return bool
  551.      */
  552.     public function isLazy()
  553.     {
  554.         return $this->lazy;
  555.     }
  556.     /**
  557.      * Sets whether this definition is synthetic, that is not constructed by the
  558.      * container, but dynamically injected.
  559.      *
  560.      * @return $this
  561.      */
  562.     public function setSynthetic(bool $boolean)
  563.     {
  564.         $this->synthetic $boolean;
  565.         if (!isset($this->changes['public'])) {
  566.             $this->setPublic(true);
  567.         }
  568.         return $this;
  569.     }
  570.     /**
  571.      * Whether this definition is synthetic, that is not constructed by the
  572.      * container, but dynamically injected.
  573.      *
  574.      * @return bool
  575.      */
  576.     public function isSynthetic()
  577.     {
  578.         return $this->synthetic;
  579.     }
  580.     /**
  581.      * Whether this definition is abstract, that means it merely serves as a
  582.      * template for other definitions.
  583.      *
  584.      * @return $this
  585.      */
  586.     public function setAbstract(bool $boolean)
  587.     {
  588.         $this->abstract $boolean;
  589.         return $this;
  590.     }
  591.     /**
  592.      * Whether this definition is abstract, that means it merely serves as a
  593.      * template for other definitions.
  594.      *
  595.      * @return bool
  596.      */
  597.     public function isAbstract()
  598.     {
  599.         return $this->abstract;
  600.     }
  601.     /**
  602.      * Whether this definition is deprecated, that means it should not be called
  603.      * anymore.
  604.      *
  605.      * @param string $package The name of the composer package that is triggering the deprecation
  606.      * @param string $version The version of the package that introduced the deprecation
  607.      * @param string $message The deprecation message to use
  608.      *
  609.      * @return $this
  610.      *
  611.      * @throws InvalidArgumentException when the message template is invalid
  612.      */
  613.     public function setDeprecated(/* string $package, string $version, string $message */)
  614.     {
  615.         $args = \func_get_args();
  616.         if (\func_num_args() < 3) {
  617.             trigger_deprecation('symfony/dependency-injection''5.1''The signature of method "%s()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.'__METHOD__);
  618.             $status $args[0] ?? true;
  619.             if (!$status) {
  620.                 trigger_deprecation('symfony/dependency-injection''5.1''Passing a null message to un-deprecate a node is deprecated.');
  621.             }
  622.             $message = (string) ($args[1] ?? null);
  623.             $package $version '';
  624.         } else {
  625.             $status true;
  626.             $package = (string) $args[0];
  627.             $version = (string) $args[1];
  628.             $message = (string) $args[2];
  629.         }
  630.         if ('' !== $message) {
  631.             if (preg_match('#[\r\n]|\*/#'$message)) {
  632.                 throw new InvalidArgumentException('Invalid characters found in deprecation template.');
  633.             }
  634.             if (!str_contains($message'%service_id%')) {
  635.                 throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
  636.             }
  637.         }
  638.         $this->changes['deprecated'] = true;
  639.         $this->deprecation $status ? ['package' => $package'version' => $version'message' => $message ?: self::DEFAULT_DEPRECATION_TEMPLATE] : [];
  640.         return $this;
  641.     }
  642.     /**
  643.      * Whether this definition is deprecated, that means it should not be called
  644.      * anymore.
  645.      *
  646.      * @return bool
  647.      */
  648.     public function isDeprecated()
  649.     {
  650.         return (bool) $this->deprecation;
  651.     }
  652.     /**
  653.      * Message to use if this definition is deprecated.
  654.      *
  655.      * @deprecated since Symfony 5.1, use "getDeprecation()" instead.
  656.      *
  657.      * @param string $id Service id relying on this definition
  658.      *
  659.      * @return string
  660.      */
  661.     public function getDeprecationMessage(string $id)
  662.     {
  663.         trigger_deprecation('symfony/dependency-injection''5.1''The "%s()" method is deprecated, use "getDeprecation()" instead.'__METHOD__);
  664.         return $this->getDeprecation($id)['message'];
  665.     }
  666.     /**
  667.      * @param string $id Service id relying on this definition
  668.      */
  669.     public function getDeprecation(string $id): array
  670.     {
  671.         return [
  672.             'package' => $this->deprecation['package'],
  673.             'version' => $this->deprecation['version'],
  674.             'message' => str_replace('%service_id%'$id$this->deprecation['message']),
  675.         ];
  676.     }
  677.     /**
  678.      * Sets a configurator to call after the service is fully initialized.
  679.      *
  680.      * @param string|array|Reference|null $configurator A PHP function, reference or an array containing a class/Reference and a method to call
  681.      *
  682.      * @return $this
  683.      */
  684.     public function setConfigurator($configurator)
  685.     {
  686.         $this->changes['configurator'] = true;
  687.         if (\is_string($configurator) && str_contains($configurator'::')) {
  688.             $configurator explode('::'$configurator2);
  689.         } elseif ($configurator instanceof Reference) {
  690.             $configurator = [$configurator'__invoke'];
  691.         }
  692.         $this->configurator $configurator;
  693.         return $this;
  694.     }
  695.     /**
  696.      * Gets the configurator to call after the service is fully initialized.
  697.      *
  698.      * @return string|array|null
  699.      */
  700.     public function getConfigurator()
  701.     {
  702.         return $this->configurator;
  703.     }
  704.     /**
  705.      * Is the definition autowired?
  706.      *
  707.      * @return bool
  708.      */
  709.     public function isAutowired()
  710.     {
  711.         return $this->autowired;
  712.     }
  713.     /**
  714.      * Enables/disables autowiring.
  715.      *
  716.      * @return $this
  717.      */
  718.     public function setAutowired(bool $autowired)
  719.     {
  720.         $this->changes['autowired'] = true;
  721.         $this->autowired $autowired;
  722.         return $this;
  723.     }
  724.     /**
  725.      * Gets bindings.
  726.      *
  727.      * @return BoundArgument[]
  728.      */
  729.     public function getBindings()
  730.     {
  731.         return $this->bindings;
  732.     }
  733.     /**
  734.      * Sets bindings.
  735.      *
  736.      * Bindings map $named or FQCN arguments to values that should be
  737.      * injected in the matching parameters (of the constructor, of methods
  738.      * called and of controller actions).
  739.      *
  740.      * @return $this
  741.      */
  742.     public function setBindings(array $bindings)
  743.     {
  744.         foreach ($bindings as $key => $binding) {
  745.             if (strpos($key'$') && $key !== $k preg_replace('/[ \t]*\$/'' $'$key)) {
  746.                 unset($bindings[$key]);
  747.                 $bindings[$key $k] = $binding;
  748.             }
  749.             if (!$binding instanceof BoundArgument) {
  750.                 $bindings[$key] = new BoundArgument($binding);
  751.             }
  752.         }
  753.         $this->bindings $bindings;
  754.         return $this;
  755.     }
  756.     /**
  757.      * Add an error that occurred when building this Definition.
  758.      *
  759.      * @param string|\Closure|self $error
  760.      *
  761.      * @return $this
  762.      */
  763.     public function addError($error)
  764.     {
  765.         if ($error instanceof self) {
  766.             $this->errors array_merge($this->errors$error->errors);
  767.         } else {
  768.             $this->errors[] = $error;
  769.         }
  770.         return $this;
  771.     }
  772.     /**
  773.      * Returns any errors that occurred while building this Definition.
  774.      *
  775.      * @return array
  776.      */
  777.     public function getErrors()
  778.     {
  779.         foreach ($this->errors as $i => $error) {
  780.             if ($error instanceof \Closure) {
  781.                 $this->errors[$i] = (string) $error();
  782.             } elseif (!\is_string($error)) {
  783.                 $this->errors[$i] = (string) $error;
  784.             }
  785.         }
  786.         return $this->errors;
  787.     }
  788.     public function hasErrors(): bool
  789.     {
  790.         return (bool) $this->errors;
  791.     }
  792. }