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

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 $class;
  22.     private $file;
  23.     private $factory;
  24.     private $shared true;
  25.     private $deprecation = [];
  26.     private $properties = [];
  27.     private $calls = [];
  28.     private $instanceof = [];
  29.     private $autoconfigured false;
  30.     private $configurator;
  31.     private $tags = [];
  32.     private $public false;
  33.     private $synthetic false;
  34.     private $abstract false;
  35.     private $lazy false;
  36.     private $decoratedService;
  37.     private $autowired false;
  38.     private $changes = [];
  39.     private $bindings = [];
  40.     private $errors = [];
  41.     protected $arguments = [];
  42.     private static $defaultDeprecationTemplate 'The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.';
  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 An array of changes for this Definition
  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 $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) && false !== strpos($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, (int) $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 The service class
  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('Cannot replace arguments if none have been configured yet.');
  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].'$index, \count($this->arguments) - 1));
  235.         }
  236.         if (!\array_key_exists($index$this->arguments)) {
  237.             throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist.'$index));
  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 The array of arguments
  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 The argument value
  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.'$index));
  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.                 break;
  323.             }
  324.         }
  325.         return $this;
  326.     }
  327.     /**
  328.      * Check if the current definition has a given method to call after service initialization.
  329.      *
  330.      * @return bool
  331.      */
  332.     public function hasMethodCall(string $method)
  333.     {
  334.         foreach ($this->calls as $call) {
  335.             if ($call[0] === $method) {
  336.                 return true;
  337.             }
  338.         }
  339.         return false;
  340.     }
  341.     /**
  342.      * Gets the methods to call after service initialization.
  343.      *
  344.      * @return array An array of method calls
  345.      */
  346.     public function getMethodCalls()
  347.     {
  348.         return $this->calls;
  349.     }
  350.     /**
  351.      * Sets the definition templates to conditionally apply on the current definition, keyed by parent interface/class.
  352.      *
  353.      * @param ChildDefinition[] $instanceof
  354.      *
  355.      * @return $this
  356.      */
  357.     public function setInstanceofConditionals(array $instanceof)
  358.     {
  359.         $this->instanceof $instanceof;
  360.         return $this;
  361.     }
  362.     /**
  363.      * Gets the definition templates to conditionally apply on the current definition, keyed by parent interface/class.
  364.      *
  365.      * @return ChildDefinition[]
  366.      */
  367.     public function getInstanceofConditionals()
  368.     {
  369.         return $this->instanceof;
  370.     }
  371.     /**
  372.      * Sets whether or not instanceof conditionals should be prepended with a global set.
  373.      *
  374.      * @return $this
  375.      */
  376.     public function setAutoconfigured(bool $autoconfigured)
  377.     {
  378.         $this->changes['autoconfigured'] = true;
  379.         $this->autoconfigured $autoconfigured;
  380.         return $this;
  381.     }
  382.     /**
  383.      * @return bool
  384.      */
  385.     public function isAutoconfigured()
  386.     {
  387.         return $this->autoconfigured;
  388.     }
  389.     /**
  390.      * Sets tags for this definition.
  391.      *
  392.      * @return $this
  393.      */
  394.     public function setTags(array $tags)
  395.     {
  396.         $this->tags $tags;
  397.         return $this;
  398.     }
  399.     /**
  400.      * Returns all tags.
  401.      *
  402.      * @return array An array of tags
  403.      */
  404.     public function getTags()
  405.     {
  406.         return $this->tags;
  407.     }
  408.     /**
  409.      * Gets a tag by name.
  410.      *
  411.      * @return array An array of attributes
  412.      */
  413.     public function getTag(string $name)
  414.     {
  415.         return isset($this->tags[$name]) ? $this->tags[$name] : [];
  416.     }
  417.     /**
  418.      * Adds a tag for this definition.
  419.      *
  420.      * @return $this
  421.      */
  422.     public function addTag(string $name, array $attributes = [])
  423.     {
  424.         $this->tags[$name][] = $attributes;
  425.         return $this;
  426.     }
  427.     /**
  428.      * Whether this definition has a tag with the given name.
  429.      *
  430.      * @return bool
  431.      */
  432.     public function hasTag(string $name)
  433.     {
  434.         return isset($this->tags[$name]);
  435.     }
  436.     /**
  437.      * Clears all tags for a given name.
  438.      *
  439.      * @return $this
  440.      */
  441.     public function clearTag(string $name)
  442.     {
  443.         unset($this->tags[$name]);
  444.         return $this;
  445.     }
  446.     /**
  447.      * Clears the tags for this definition.
  448.      *
  449.      * @return $this
  450.      */
  451.     public function clearTags()
  452.     {
  453.         $this->tags = [];
  454.         return $this;
  455.     }
  456.     /**
  457.      * Sets a file to require before creating the service.
  458.      *
  459.      * @return $this
  460.      */
  461.     public function setFile(?string $file)
  462.     {
  463.         $this->changes['file'] = true;
  464.         $this->file $file;
  465.         return $this;
  466.     }
  467.     /**
  468.      * Gets the file to require before creating the service.
  469.      *
  470.      * @return string|null The full pathname to include
  471.      */
  472.     public function getFile()
  473.     {
  474.         return $this->file;
  475.     }
  476.     /**
  477.      * Sets if the service must be shared or not.
  478.      *
  479.      * @return $this
  480.      */
  481.     public function setShared(bool $shared)
  482.     {
  483.         $this->changes['shared'] = true;
  484.         $this->shared $shared;
  485.         return $this;
  486.     }
  487.     /**
  488.      * Whether this service is shared.
  489.      *
  490.      * @return bool
  491.      */
  492.     public function isShared()
  493.     {
  494.         return $this->shared;
  495.     }
  496.     /**
  497.      * Sets the visibility of this service.
  498.      *
  499.      * @return $this
  500.      */
  501.     public function setPublic(bool $boolean)
  502.     {
  503.         $this->changes['public'] = true;
  504.         $this->public $boolean;
  505.         return $this;
  506.     }
  507.     /**
  508.      * Whether this service is public facing.
  509.      *
  510.      * @return bool
  511.      */
  512.     public function isPublic()
  513.     {
  514.         return $this->public;
  515.     }
  516.     /**
  517.      * Sets if this service is private.
  518.      *
  519.      * @return $this
  520.      *
  521.      * @deprecated since Symfony 5.2, use setPublic() instead
  522.      */
  523.     public function setPrivate(bool $boolean)
  524.     {
  525.         trigger_deprecation('symfony/dependency-injection''5.2''The "%s()" method is deprecated, use "setPublic()" instead.'__METHOD__);
  526.         return $this->setPublic(!$boolean);
  527.     }
  528.     /**
  529.      * Whether this service is private.
  530.      *
  531.      * @return bool
  532.      */
  533.     public function isPrivate()
  534.     {
  535.         return !$this->public;
  536.     }
  537.     /**
  538.      * Sets the lazy flag of this service.
  539.      *
  540.      * @return $this
  541.      */
  542.     public function setLazy(bool $lazy)
  543.     {
  544.         $this->changes['lazy'] = true;
  545.         $this->lazy $lazy;
  546.         return $this;
  547.     }
  548.     /**
  549.      * Whether this service is lazy.
  550.      *
  551.      * @return bool
  552.      */
  553.     public function isLazy()
  554.     {
  555.         return $this->lazy;
  556.     }
  557.     /**
  558.      * Sets whether this definition is synthetic, that is not constructed by the
  559.      * container, but dynamically injected.
  560.      *
  561.      * @return $this
  562.      */
  563.     public function setSynthetic(bool $boolean)
  564.     {
  565.         $this->synthetic $boolean;
  566.         if (!isset($this->changes['public'])) {
  567.             $this->setPublic(true);
  568.         }
  569.         return $this;
  570.     }
  571.     /**
  572.      * Whether this definition is synthetic, that is not constructed by the
  573.      * container, but dynamically injected.
  574.      *
  575.      * @return bool
  576.      */
  577.     public function isSynthetic()
  578.     {
  579.         return $this->synthetic;
  580.     }
  581.     /**
  582.      * Whether this definition is abstract, that means it merely serves as a
  583.      * template for other definitions.
  584.      *
  585.      * @return $this
  586.      */
  587.     public function setAbstract(bool $boolean)
  588.     {
  589.         $this->abstract $boolean;
  590.         return $this;
  591.     }
  592.     /**
  593.      * Whether this definition is abstract, that means it merely serves as a
  594.      * template for other definitions.
  595.      *
  596.      * @return bool
  597.      */
  598.     public function isAbstract()
  599.     {
  600.         return $this->abstract;
  601.     }
  602.     /**
  603.      * Whether this definition is deprecated, that means it should not be called
  604.      * anymore.
  605.      *
  606.      * @param string $package The name of the composer package that is triggering the deprecation
  607.      * @param string $version The version of the package that introduced the deprecation
  608.      * @param string $message The deprecation message to use
  609.      *
  610.      * @return $this
  611.      *
  612.      * @throws InvalidArgumentException when the message template is invalid
  613.      */
  614.     public function setDeprecated(/* string $package, string $version, string $message */)
  615.     {
  616.         $args = \func_get_args();
  617.         if (\func_num_args() < 3) {
  618.             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__);
  619.             $status $args[0] ?? true;
  620.             if (!$status) {
  621.                 trigger_deprecation('symfony/dependency-injection''5.1''Passing a null message to un-deprecate a node is deprecated.');
  622.             }
  623.             $message = (string) ($args[1] ?? null);
  624.             $package $version '';
  625.         } else {
  626.             $status true;
  627.             $package = (string) $args[0];
  628.             $version = (string) $args[1];
  629.             $message = (string) $args[2];
  630.         }
  631.         if ('' !== $message) {
  632.             if (preg_match('#[\r\n]|\*/#'$message)) {
  633.                 throw new InvalidArgumentException('Invalid characters found in deprecation template.');
  634.             }
  635.             if (false === strpos($message'%service_id%')) {
  636.                 throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
  637.             }
  638.         }
  639.         $this->changes['deprecated'] = true;
  640.         $this->deprecation $status ? ['package' => $package'version' => $version'message' => $message ?: self::$defaultDeprecationTemplate] : [];
  641.         return $this;
  642.     }
  643.     /**
  644.      * Whether this definition is deprecated, that means it should not be called
  645.      * anymore.
  646.      *
  647.      * @return bool
  648.      */
  649.     public function isDeprecated()
  650.     {
  651.         return (bool) $this->deprecation;
  652.     }
  653.     /**
  654.      * Message to use if this definition is deprecated.
  655.      *
  656.      * @deprecated since Symfony 5.1, use "getDeprecation()" instead.
  657.      *
  658.      * @param string $id Service id relying on this definition
  659.      *
  660.      * @return string
  661.      */
  662.     public function getDeprecationMessage(string $id)
  663.     {
  664.         trigger_deprecation('symfony/dependency-injection''5.1''The "%s()" method is deprecated, use "getDeprecation()" instead.'__METHOD__);
  665.         return $this->getDeprecation($id)['message'];
  666.     }
  667.     /**
  668.      * @param string $id Service id relying on this definition
  669.      */
  670.     public function getDeprecation(string $id): array
  671.     {
  672.         return [
  673.             'package' => $this->deprecation['package'],
  674.             'version' => $this->deprecation['version'],
  675.             'message' => str_replace('%service_id%'$id$this->deprecation['message']),
  676.         ];
  677.     }
  678.     /**
  679.      * Sets a configurator to call after the service is fully initialized.
  680.      *
  681.      * @param string|array|Reference $configurator A PHP function, reference or an array containing a class/Reference and a method to call
  682.      *
  683.      * @return $this
  684.      */
  685.     public function setConfigurator($configurator)
  686.     {
  687.         $this->changes['configurator'] = true;
  688.         if (\is_string($configurator) && false !== strpos($configurator'::')) {
  689.             $configurator explode('::'$configurator2);
  690.         } elseif ($configurator instanceof Reference) {
  691.             $configurator = [$configurator'__invoke'];
  692.         }
  693.         $this->configurator $configurator;
  694.         return $this;
  695.     }
  696.     /**
  697.      * Gets the configurator to call after the service is fully initialized.
  698.      *
  699.      * @return callable|array|null
  700.      */
  701.     public function getConfigurator()
  702.     {
  703.         return $this->configurator;
  704.     }
  705.     /**
  706.      * Is the definition autowired?
  707.      *
  708.      * @return bool
  709.      */
  710.     public function isAutowired()
  711.     {
  712.         return $this->autowired;
  713.     }
  714.     /**
  715.      * Enables/disables autowiring.
  716.      *
  717.      * @return $this
  718.      */
  719.     public function setAutowired(bool $autowired)
  720.     {
  721.         $this->changes['autowired'] = true;
  722.         $this->autowired $autowired;
  723.         return $this;
  724.     }
  725.     /**
  726.      * Gets bindings.
  727.      *
  728.      * @return array|BoundArgument[]
  729.      */
  730.     public function getBindings()
  731.     {
  732.         return $this->bindings;
  733.     }
  734.     /**
  735.      * Sets bindings.
  736.      *
  737.      * Bindings map $named or FQCN arguments to values that should be
  738.      * injected in the matching parameters (of the constructor, of methods
  739.      * called and of controller actions).
  740.      *
  741.      * @return $this
  742.      */
  743.     public function setBindings(array $bindings)
  744.     {
  745.         foreach ($bindings as $key => $binding) {
  746.             if (strpos($key'$') && $key !== $k preg_replace('/[ \t]*\$/'' $'$key)) {
  747.                 unset($bindings[$key]);
  748.                 $bindings[$key $k] = $binding;
  749.             }
  750.             if (!$binding instanceof BoundArgument) {
  751.                 $bindings[$key] = new BoundArgument($binding);
  752.             }
  753.         }
  754.         $this->bindings $bindings;
  755.         return $this;
  756.     }
  757.     /**
  758.      * Add an error that occurred when building this Definition.
  759.      *
  760.      * @param string|\Closure|self $error
  761.      *
  762.      * @return $this
  763.      */
  764.     public function addError($error)
  765.     {
  766.         if ($error instanceof self) {
  767.             $this->errors array_merge($this->errors$error->errors);
  768.         } else {
  769.             $this->errors[] = $error;
  770.         }
  771.         return $this;
  772.     }
  773.     /**
  774.      * Returns any errors that occurred while building this Definition.
  775.      *
  776.      * @return array
  777.      */
  778.     public function getErrors()
  779.     {
  780.         foreach ($this->errors as $i => $error) {
  781.             if ($error instanceof \Closure) {
  782.                 $this->errors[$i] = (string) $error();
  783.             } elseif (!\is_string($error)) {
  784.                 $this->errors[$i] = (string) $error;
  785.             }
  786.         }
  787.         return $this->errors;
  788.     }
  789.     public function hasErrors(): bool
  790.     {
  791.         return (bool) $this->errors;
  792.     }
  793. }