Chris@0: _serviceIds = []; Chris@0: $vars = get_object_vars($this); Chris@0: foreach ($vars as $key => $value) { Chris@0: if (is_object($value) && isset($value->_serviceId)) { Chris@0: // If a class member was instantiated by the dependency injection Chris@0: // container, only store its ID so it can be used to get a fresh object Chris@0: // on unserialization. Chris@0: $this->_serviceIds[$key] = $value->_serviceId; Chris@0: unset($vars[$key]); Chris@0: } Chris@0: // Special case the container, which might not have a service ID. Chris@0: elseif ($value instanceof ContainerInterface) { Chris@0: $this->_serviceIds[$key] = 'service_container'; Chris@0: unset($vars[$key]); Chris@0: } Chris@16: elseif ($value instanceof EntityStorageInterface) { Chris@16: // If a class member is an entity storage, only store the entity type ID Chris@16: // the storage is for so it can be used to get a fresh object on Chris@16: // unserialization. By doing this we prevent possible memory leaks when Chris@16: // the storage is serialized when it contains a static cache of entity Chris@16: // objects and additionally we ensure that we'll not have multiple Chris@16: // storage objects for the same entity type and therefore prevent Chris@16: // returning different references for the same entity. Chris@16: $this->_entityStorages[$key] = $value->getEntityTypeId(); Chris@16: unset($vars[$key]); Chris@16: } Chris@0: } Chris@0: Chris@0: return array_keys($vars); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function __wakeup() { Chris@0: // Tests in isolation potentially unserialize in the parent process. Chris@0: $phpunit_bootstrap = isset($GLOBALS['__PHPUNIT_BOOTSTRAP']); Chris@0: if ($phpunit_bootstrap && !\Drupal::hasContainer()) { Chris@0: return; Chris@0: } Chris@0: $container = \Drupal::getContainer(); Chris@0: foreach ($this->_serviceIds as $key => $service_id) { Chris@0: // In rare cases, when test data is serialized in the parent process, Chris@0: // there is a service container but it doesn't contain all expected Chris@0: // services. To avoid fatal errors during the wrap-up of failing tests, we Chris@0: // check for this case, too. Chris@0: if ($phpunit_bootstrap && !$container->has($service_id)) { Chris@0: continue; Chris@0: } Chris@0: $this->$key = $container->get($service_id); Chris@0: } Chris@0: $this->_serviceIds = []; Chris@16: Chris@16: // In rare cases, when test data is serialized in the parent process, there Chris@16: // is a service container but it doesn't contain all expected services. To Chris@16: // avoid fatal errors during the wrap-up of failing tests, we check for this Chris@16: // case, too. Chris@16: if ($this->_entityStorages && (!$phpunit_bootstrap || $container->has('entity_type.manager'))) { Chris@16: /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ Chris@16: $entity_type_manager = $container->get('entity_type.manager'); Chris@16: foreach ($this->_entityStorages as $key => $entity_type_id) { Chris@16: $this->$key = $entity_type_manager->getStorage($entity_type_id); Chris@16: } Chris@16: } Chris@16: $this->_entityStorages = []; Chris@0: } Chris@0: Chris@0: }