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

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