X-Git-Url: http://aleph1.co.uk/gitweb/?a=blobdiff_plain;f=web%2Fcore%2Flib%2FDrupal%2FCore%2FDependencyInjection%2FDependencySerializationTrait.php;h=b151a3b837e83dfc315b787bc0b24e6b93565b05;hb=refs%2Fheads%2Fd864;hp=7f3cb5d6f98c29a16cede65edb5668e7ec636436;hpb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;p=yaffs-website diff --git a/web/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php b/web/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php index 7f3cb5d6f..b151a3b83 100644 --- a/web/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php +++ b/web/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php @@ -2,6 +2,7 @@ namespace Drupal\Core\DependencyInjection; +use Drupal\Core\Entity\EntityStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -16,6 +17,13 @@ trait DependencySerializationTrait { */ protected $_serviceIds = []; + /** + * An array of entity type IDs keyed by the property name of their storages. + * + * @var array + */ + protected $_entityStorages = []; + /** * {@inheritdoc} */ @@ -35,6 +43,17 @@ trait DependencySerializationTrait { $this->_serviceIds[$key] = 'service_container'; unset($vars[$key]); } + elseif ($value instanceof EntityStorageInterface) { + // If a class member is an entity storage, only store the entity type ID + // the storage is for so it can be used to get a fresh object on + // unserialization. By doing this we prevent possible memory leaks when + // the storage is serialized when it contains a static cache of entity + // objects and additionally we ensure that we'll not have multiple + // storage objects for the same entity type and therefore prevent + // returning different references for the same entity. + $this->_entityStorages[$key] = $value->getEntityTypeId(); + unset($vars[$key]); + } } return array_keys($vars); @@ -45,14 +64,35 @@ trait DependencySerializationTrait { */ public function __wakeup() { // Tests in isolation potentially unserialize in the parent process. - if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP']) && !\Drupal::hasContainer()) { + $phpunit_bootstrap = isset($GLOBALS['__PHPUNIT_BOOTSTRAP']); + if ($phpunit_bootstrap && !\Drupal::hasContainer()) { return; } $container = \Drupal::getContainer(); foreach ($this->_serviceIds as $key => $service_id) { + // In rare cases, when test data is serialized in the parent process, + // there is a service container but it doesn't contain all expected + // services. To avoid fatal errors during the wrap-up of failing tests, we + // check for this case, too. + if ($phpunit_bootstrap && !$container->has($service_id)) { + continue; + } $this->$key = $container->get($service_id); } $this->_serviceIds = []; + + // In rare cases, when test data is serialized in the parent process, there + // is a service container but it doesn't contain all expected services. To + // avoid fatal errors during the wrap-up of failing tests, we check for this + // case, too. + if ($this->_entityStorages && (!$phpunit_bootstrap || $container->has('entity_type.manager'))) { + /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ + $entity_type_manager = $container->get('entity_type.manager'); + foreach ($this->_entityStorages as $key => $entity_type_id) { + $this->$key = $entity_type_manager->getStorage($entity_type_id); + } + } + $this->_entityStorages = []; } }