Commit ef547682 authored by catch's avatar catch
Browse files

Issue #2531564 by neclimdul, andypost, chx, cburschka, Spokje, pdenooijer,...

Issue #2531564 by neclimdul, andypost, chx, cburschka, Spokje, pdenooijer, Charlie ChX Negyesi, znerol, dawehner, longwave, Fabianx, geek-merlin, catch, alexpott: Fix leaky and brittle container serialization solution
parent a3b4919b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ class Drupal {
  /**
   * The currently active container object, or NULL if not initialized yet.
   *
   * @var \Symfony\Component\DependencyInjection\ContainerInterface|null
   * @var \Drupal\Component\DependencyInjection\ContainerInterface|null
   */
  protected static $container;

@@ -150,7 +150,7 @@ public static function unsetContainer() {
  /**
   * Returns the currently active global container.
   *
   * @return \Symfony\Component\DependencyInjection\ContainerInterface
   * @return \Drupal\Component\DependencyInjection\ContainerInterface
   *
   * @throws \Drupal\Core\DependencyInjection\ContainerNotInitializedException
   */
+3 −5
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@

namespace Drupal\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -46,6 +45,8 @@
 */
class Container implements ContainerInterface, ResetInterface {

  use ServiceIdHashTrait;

  /**
   * The parameters of the container.
   *
@@ -536,10 +537,7 @@ protected function getParameterAlternatives($name) {
  }

  /**
   * Gets all defined service IDs.
   *
   * @return array
   *   An array of all defined service IDs.
   * {@inheritdoc}
   */
  public function getServiceIds() {
    return array_keys($this->serviceDefinitions + $this->services);
+42 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerInterface as BaseContainerInterface;

/**
 * The interface for Drupal service container classes.
 *
 * This interface extends Symfony's ContainerInterface and adds methods for
 * managing mappings of instantiated services to its IDs.
 */
interface ContainerInterface extends BaseContainerInterface {

  /**
   * Gets all defined service IDs.
   *
   * @return array
   *   An array of all defined service IDs.
   */
  public function getServiceIds();

  /**
   * Collect a mapping between service to ids.
   *
   * @return array
   *   Service ids keyed by a unique hash.
   */
  public function getServiceIdMappings(): array;

  /**
   * Generate a unique hash for a service object.
   *
   * @param object $object
   *   Object needing a unique hash.
   *
   * @return string
   *   A unique hash identifying the object.
   */
  public function generateServiceIdHash(object $object): string;

}
+1 −0
Original line number Diff line number Diff line
@@ -430,6 +430,7 @@ protected function dumpValue($value) {
    elseif (is_object($value)) {
      // Drupal specific: Instantiated objects have a _serviceId parameter.
      if (isset($value->_serviceId)) {
        @trigger_error('_serviceId is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. Use \Drupal\Core\DrupalKernelInterface::getServiceIdMapping() instead. See https://www.drupal.org/node/3292540', E_USER_DEPRECATED);
        return $this->getReferenceCall($value->_serviceId);
      }
      throw new RuntimeException('Unable to dump a service container if a parameter is an object without _serviceId.');
+37 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Component\DependencyInjection;

/**
 * A trait for service id hashing implementations.
 *
 * Handles delayed cache tag invalidations.
 */
trait ServiceIdHashTrait {

  /**
   * Implements \Drupal\Component\DependencyInjection\ContainerInterface::getServiceIdMappings()
   */
  public function getServiceIdMappings(): array {
    $mapping = [];
    foreach ($this->getServiceIds() as $service_id) {
      if ($this->initialized($service_id) && $service_id !== 'service_container') {
        $mapping[$this->generateServiceIdHash($this->get($service_id))] = $service_id;
      }
    }
    return $mapping;
  }

  /**
   * Implements \Drupal\Component\DependencyInjection\ContainerInterface::generateServiceIdHash()
   */
  public function generateServiceIdHash(object $object): string {
    // Include class name as an additional namespace for the hash since
    // spl_object_hash's return can be recycled. This still is not a 100%
    // guarantee to be unique but makes collisions incredibly difficult and even
    // then the interface would be preserved.
    // @see https://php.net/spl_object_hash#refsect1-function.spl-object-hash-notes
    return hash('sha256', get_class($object) . spl_object_hash($object));
  }

}
Loading