Verified Commit 92e703a6 authored by Dave Long's avatar Dave Long
Browse files

Issue #3108020 by bonrita, Cyberwolf, sagarchauhan, znerol, borisson_: Support...

Issue #3108020 by bonrita, Cyberwolf, sagarchauhan, znerol, borisson_: Support ServiceClosureArgument in \Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper::dumpValue
parent f1a52222
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -459,6 +459,13 @@ protected function resolveServicesAndParameters($arguments) {

          continue;
        }
        elseif ($type == 'service_closure') {
          $arguments[$key] = function () use ($argument) {
            return $this->get($argument->id, $argument->invalidBehavior);
          };

          continue;
        }
        // Check for collection.
        elseif ($type == 'collection') {
          $value = $argument->value;
+27 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
namespace Drupal\Component\DependencyInjection\Dumper;

use Drupal\Component\Utility\Crypt;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
@@ -427,6 +428,13 @@ protected function dumpValue($value) {
    elseif ($value instanceof Expression) {
      throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
    }
    elseif ($value instanceof ServiceClosureArgument) {
      $reference = $value->getValues();
      /** @var \Symfony\Component\DependencyInjection\Reference $reference */
      $reference = reset($reference);

      return $this->getServiceClosureCall((string) $reference, $reference->getInvalidBehavior());
    }
    elseif (is_object($value)) {
      // Drupal specific: Instantiated objects have a _serviceId parameter.
      if (isset($value->_serviceId)) {
@@ -525,4 +533,23 @@ protected function supportsMachineFormat() {
    return TRUE;
  }

  /**
   * Gets a service closure reference in a suitable PHP array format.
   *
   * @param string $id
   *   The ID of the service to get a reference for.
   * @param int $invalid_behavior
   *   (optional) The invalid behavior of the service.
   *
   * @return string|object
   *   A suitable representation of the service closure reference.
   */
  protected function getServiceClosureCall(string $id, int $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
    return (object) [
      'type' => 'service_closure',
      'id' => $id,
      'invalidBehavior' => $invalid_behavior,
    ];
  }

}
+7 −0
Original line number Diff line number Diff line
@@ -165,6 +165,13 @@ protected function resolveServicesAndParameters($arguments) {

          continue;
        }
        elseif ($type == 'service_closure') {
          $arguments[$key] = function () use ($argument) {
            return $this->get($argument->id, $argument->invalidBehavior);
          };

          continue;
        }
        elseif ($type == 'raw') {
          $arguments[$key] = $argument->value;

+34 −0
Original line number Diff line number Diff line
@@ -593,6 +593,21 @@ public function testResolveServicesAndParametersForOptionalServiceDependencies()
    $this->assertNull($service->getSomeOtherService(), 'other service was NULL was expected.');
  }

  /**
   * Tests that services wrapped in a closure work correctly.
   *
   * @covers ::get
   * @covers ::createService
   * @covers ::resolveServicesAndParameters
   */
  public function testResolveServicesAndParametersForServiceReferencedViaServiceClosure() {
    $service = $this->container->get('service_within_service_closure');
    $other_service = $this->container->get('other.service');
    $factory_function = $service->getSomeOtherService();
    $this->assertInstanceOf(\Closure::class, $factory_function);
    $this->assertEquals($other_service, call_user_func($factory_function));
  }

  /**
   * Tests that an invalid argument throw an Exception.
   *
@@ -845,6 +860,14 @@ protected function getMockContainerDefinition() {

    ];

    $services['service_within_service_closure'] = [
      'class' => '\Drupal\Tests\Component\DependencyInjection\MockService',
      'arguments' => $this->getCollection([
        $this->getServiceClosureCall('other.service', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE),
        $this->getParameterCall('some_private_config'),
      ]),
    ];

    $services['factory_service'] = [
      'class' => '\Drupal\service_container\ServiceContainer\ControllerInterface',
      'factory' => [
@@ -981,6 +1004,17 @@ protected function getServiceCall($id, $invalid_behavior = ContainerInterface::E
    ];
  }

  /**
   * Helper function to return a service closure definition.
   */
  protected function getServiceClosureCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
    return (object) [
      'type' => 'service_closure',
      'id' => $id,
      'invalidBehavior' => $invalid_behavior,
    ];
  }

  /**
   * Helper function to return a parameter definition.
   */
+32 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
  use Prophecy\PhpUnit\ProphecyTrait;
  use Prophecy\Prophet;
  use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
  use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  use Symfony\Component\DependencyInjection\Definition;
  use Symfony\Component\DependencyInjection\Reference;
  use Symfony\Component\DependencyInjection\Parameter;
@@ -205,6 +206,7 @@ public function getParametersDataProvider() {
     * @covers ::getPrivateServiceCall
     * @covers ::getReferenceCall
     * @covers ::getServiceCall
     * @covers ::getServiceClosureCall
     * @covers ::getParameterCall
     *
     * @dataProvider getDefinitionsDataProvider
@@ -305,6 +307,25 @@ public static function getDefinitionsDataProvider() {
        ]),
      ] + $base_service_definition;

      // Test a service closure.
      $service_definitions[] = [
        'arguments' => [
          'foo',
          [
            'alias-1' => new ServiceClosureArgument(new Reference('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE)),
            'alias-2' => new ServiceClosureArgument(new Reference('bar', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)),
          ],
        ],
        'arguments_count' => 2,
        'arguments_expected' => static::getCollection([
          'foo',
          static::getCollection([
            'alias-1' => static::getServiceClosureCall('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE),
            'alias-2' => static::getServiceClosureCall('bar', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE),
          ]),
        ]),
      ] + $base_service_definition;

      // Test a private non-shared service, denoted by having a Definition.
      $private_definition_object = new Definition('\stdClass');
      $private_definition_object->setPublic(FALSE);
@@ -458,6 +479,17 @@ protected static function getServiceCall($id, $invalid_behavior = ContainerInter
      ];
    }

    /**
     * Helper function to return a service closure definition.
     */
    protected static function getServiceClosureCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
      return (object) [
        'type' => 'service_closure',
        'id' => $id,
        'invalidBehavior' => $invalid_behavior,
      ];
    }

    /**
     * Tests that references to aliases work correctly.
     *