Commit 2d8630fb authored by catch's avatar catch
Browse files

Issue #3258654 by alexpott: Deprecate feed.bridge.reader and move it to the Aggregator module

(cherry picked from commit fbb54d81)
parent 37f42e8f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1443,6 +1443,7 @@ services:
      - [setContainer, ['@service_container']]
      - [setStandalone, ['\Laminas\Feed\Reader\StandaloneExtensionManager']]
    arguments: ['feed.reader.']
    deprecated: The "%service_id%" service is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Use \Laminas\Feed\Reader\StandaloneExtensionManager or create your own service. See https://www.drupal.org/node/3258656
  feed.bridge.writer:
    class: Drupal\Component\Bridge\ZfExtensionManagerSfContainer
    calls:
+7 −0
Original line number Diff line number Diff line
@@ -7,8 +7,15 @@
use Laminas\Feed\Reader\ExtensionManagerInterface as ReaderManagerInterface;
use Laminas\Feed\Writer\ExtensionManagerInterface as WriterManagerInterface;

@trigger_error(__NAMESPACE__ . '\ZfExtensionManagerSfContainer is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. The class has moved to \Drupal\aggregator\ZfExtensionManagerSfContainer. See https://www.drupal.org/node/3258656', E_USER_DEPRECATED);

/**
 * Defines a bridge between the Laminas service manager to Symfony container.
 *
 * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. The class has
 *   moved to \Drupal\aggregator\ZfExtensionManagerSfContainer.
 *
 * @see https://www.drupal.org/node/3258656
 */
class ZfExtensionManagerSfContainer implements ReaderManagerInterface, WriterManagerInterface, ContainerAwareInterface {

+6 −0
Original line number Diff line number Diff line
@@ -14,3 +14,9 @@ services:
  logger.channel.aggregator:
    parent: logger.channel_base
    arguments: ['aggregator']
  feed.bridge.reader:
    class: Drupal\aggregator\ZfExtensionManagerSfContainer
    calls:
      - [setContainer, ['@service_container']]
      - [setStandalone, ['\Laminas\Feed\Reader\StandaloneExtensionManager']]
    arguments: ['feed.reader.']
+130 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\aggregator;

use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Laminas\Feed\Reader\ExtensionManagerInterface as ReaderManagerInterface;
use Laminas\Feed\Writer\ExtensionManagerInterface as WriterManagerInterface;

/**
 * Defines a bridge between the Laminas service manager to Symfony container.
 */
class ZfExtensionManagerSfContainer implements ReaderManagerInterface, WriterManagerInterface, ContainerAwareInterface {

  /**
   * A map of characters to be replaced through strtr.
   *
   * This property is based on Laminas service manager.
   *
   * @link https://github.com/laminas/laminas-servicemanager for the canonical source repository
   * @copyright Copyright (c) 2019, Laminas Foundation. (https://getlaminas.org/)
   * @license https://github.com/laminas/laminas-servicemanager/blob/master/LICENSE.md
   *
   * @var array
   *
   * @see \Drupal\Component\Bridge\ZfExtensionManagerSfContainer::canonicalizeName().
   * @see https://github.com/laminas/laminas-servicemanager/blob/2.7.11/src/ServiceManager.php#L114
   */
  protected $canonicalNamesReplacements = ['-' => '', '_' => '', ' ' => '', '\\' => '', '/' => ''];

  /**
   * The prefix to be used when retrieving plugins from the container.
   *
   * @var string
   */
  protected $prefix = '';

  /**
   * The service container.
   *
   * @var \Symfony\Component\DependencyInjection\ContainerInterface
   */
  protected $container;

  /**
   * A local cache of computed canonical names.
   *
   * @var string[]
   */
  protected $canonicalNames;

  /**
   * @var \Laminas\Feed\Reader\ExtensionManagerInterface|\Laminas\Feed\Writer\ExtensionManagerInterface
   */
  protected $standalone;

  /**
   * Constructs a ZfExtensionManagerSfContainer object.
   *
   * @param string $prefix
   *   The prefix to be used when retrieving plugins from the container.
   */
  public function __construct($prefix = '') {
    $this->prefix = $prefix;
  }

  /**
   * {@inheritdoc}
   */
  public function get($extension) {
    if ($this->standalone && $this->standalone->has($extension)) {
      return $this->standalone->get($extension);
    }
    return $this->container->get($this->prefix . $this->canonicalizeName($extension));
  }

  /**
   * {@inheritdoc}
   */
  public function has($extension) {
    if ($this->standalone && $this->standalone->has($extension)) {
      return TRUE;
    }
    return $this->container->has($this->prefix . $this->canonicalizeName($extension));
  }

  /**
   * Canonicalize the extension name to a service name.
   *
   * This method is based on Laminas service manager.
   *
   * @link https://github.com/laminas/laminas-servicemanager for the canonical source repository
   * @copyright Copyright (c) 2019, Laminas Foundation. (https://getlaminas.org/)
   * @license https://github.com/laminas/laminas-servicemanager/blob/master/LICENSE.md
   *
   * @param string $name
   *   The extension name.
   *
   * @return string
   *   The service name, without the prefix.
   *
   * @see https://github.com/laminas/laminas-servicemanager/blob/2.7.11/src/ServiceManager.php#L900
   */
  protected function canonicalizeName($name) {
    if (isset($this->canonicalNames[$name])) {
      return $this->canonicalNames[$name];
    }
    // This is just for performance instead of using str_replace().
    return $this->canonicalNames[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements));
  }

  /**
   * {@inheritdoc}
   */
  public function setContainer(ContainerInterface $container = NULL) {
    $this->container = $container;
  }

  /**
   * @param $class
   *   The class to set as standalone.
   */
  public function setStandalone($class) {
    if (!is_subclass_of($class, ReaderManagerInterface::class) && !is_subclass_of($class, WriterManagerInterface::class)) {
      throw new \RuntimeException("$class must implement Laminas\Feed\Reader\ExtensionManagerInterface or Laminas\Feed\Writer\ExtensionManagerInterface");
    }
    $this->standalone = new $class();
  }

}
+156 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\aggregator\Unit;

use Drupal\aggregator\ZfExtensionManagerSfContainer;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Laminas\Feed\Reader\Extension\Atom\Entry;
use Laminas\Feed\Reader\StandaloneExtensionManager;

/**
 * @coversDefaultClass \Drupal\aggregator\ZfExtensionManagerSfContainer
 * @group aggregator
 */
class ZfExtensionManagerSfContainerTest extends UnitTestCase {

  /**
   * @covers ::setContainer
   * @covers ::setStandalone
   * @covers ::get
   */
  public function testGet() {
    $service = new \stdClass();
    $service->value = 'my_value';
    $container = new ContainerBuilder();
    $container->set('foo', $service);
    $bridge = new ZfExtensionManagerSfContainer();
    $bridge->setContainer($container);
    $this->assertEquals($service, $bridge->get('foo'));
    $bridge->setStandalone(StandaloneExtensionManager::class);
    $this->assertInstanceOf(Entry::class, $bridge->get('Atom\Entry'));
    // Ensure that the standalone service is checked before the container.
    $container->set('atomentry', $service);
    $this->assertInstanceOf(Entry::class, $bridge->get('Atom\Entry'));
  }

  /**
   * @covers ::setContainer
   * @covers ::setStandalone
   * @covers ::has
   */
  public function testHas() {
    $service = new \stdClass();
    $service->value = 'my_value';
    $container = new ContainerBuilder();
    $container->set('foo', $service);
    $bridge = new ZfExtensionManagerSfContainer();
    $bridge->setContainer($container);
    $this->assertTrue($bridge->has('foo'));
    $this->assertFalse($bridge->has('bar'));
    $this->assertFalse($bridge->has('Atom\Entry'));
    $bridge->setStandalone(StandaloneExtensionManager::class);
    $this->assertTrue($bridge->has('Atom\Entry'));
  }

  /**
   * @covers ::setStandalone
   */
  public function testSetStandaloneException() {
    $this->expectException(\RuntimeException::class);
    $this->expectExceptionMessage('Drupal\Tests\aggregator\Unit\ZfExtensionManagerSfContainerTest must implement Laminas\Feed\Reader\ExtensionManagerInterface or Laminas\Feed\Writer\ExtensionManagerInterface');
    $bridge = new ZfExtensionManagerSfContainer();
    $bridge->setStandalone(static::class);
  }

  /**
   * @covers ::get
   */
  public function testGetContainerException() {
    $this->expectException(ServiceNotFoundException::class);
    $this->expectExceptionMessage('You have requested a non-existent service "test.foo".');
    $container = new ContainerBuilder();
    $bridge = new ZfExtensionManagerSfContainer('test.');
    $bridge->setContainer($container);
    $bridge->setStandalone(StandaloneExtensionManager::class);
    $bridge->get('foo');
  }

  /**
   * @covers ::__construct
   * @covers ::has
   * @covers ::get
   */
  public function testPrefix() {
    $service = new \stdClass();
    $service->value = 'my_value';
    $container = new ContainerBuilder();
    $container->set('foo.bar', $service);
    $bridge = new ZfExtensionManagerSfContainer('foo.');
    $bridge->setContainer($container);
    $this->assertTrue($bridge->has('bar'));
    $this->assertFalse($bridge->has('baz'));
    $this->assertEquals($service, $bridge->get('bar'));
  }

  /**
   * @covers ::canonicalizeName
   * @dataProvider canonicalizeNameProvider
   */
  public function testCanonicalizeName($name, $canonical_name) {
    $service = new \stdClass();
    $service->value = 'my_value';
    $container = new ContainerBuilder();
    $container->set($canonical_name, $service);
    $bridge = new ZfExtensionManagerSfContainer();
    $bridge->setContainer($container);
    $this->assertTrue($bridge->has($name));
    $this->assertEquals($service, $bridge->get($name));
  }

  /**
   * Data provider for testReverseProxyEnabled.
   *
   * Replacements:
   *   array('-' => '', '_' => '', ' ' => '', '\\' => '', '/' => '')
   */
  public function canonicalizeNameProvider() {
    return [
      [
        'foobar',
        'foobar',
      ],
      [
        'foo-bar',
        'foobar',
      ],
      [
        'foo_bar',
        'foobar',
      ],
      [
        'foo bar',
        'foobar',
      ],
      [
        'foo\\bar',
        'foobar',
      ],
      [
        'foo/bar',
        'foobar',
      ],
      // There is also a strtolower in canonicalizeName.
      [
        'Foo/bAr',
        'foobar',
      ],
      [
        'foo/-_\\ bar',
        'foobar',
      ],
    ];
  }

}
Loading