Pull merge.
[yaffs-website] / web / core / lib / Drupal / Core / DependencyInjection / DependencySerializationTrait.php
1 <?php
2
3 namespace Drupal\Core\DependencyInjection;
4
5 use Drupal\Core\Entity\EntityStorageInterface;
6 use Symfony\Component\DependencyInjection\ContainerInterface;
7
8 /**
9  * Provides dependency injection friendly methods for serialization.
10  */
11 trait DependencySerializationTrait {
12
13   /**
14    * An array of service IDs keyed by property name used for serialization.
15    *
16    * @var array
17    */
18   protected $_serviceIds = [];
19
20   /**
21    * An array of entity type IDs keyed by the property name of their storages.
22    *
23    * @var array
24    */
25   protected $_entityStorages = [];
26
27   /**
28    * {@inheritdoc}
29    */
30   public function __sleep() {
31     $this->_serviceIds = [];
32     $vars = get_object_vars($this);
33     foreach ($vars as $key => $value) {
34       if (is_object($value) && isset($value->_serviceId)) {
35         // If a class member was instantiated by the dependency injection
36         // container, only store its ID so it can be used to get a fresh object
37         // on unserialization.
38         $this->_serviceIds[$key] = $value->_serviceId;
39         unset($vars[$key]);
40       }
41       // Special case the container, which might not have a service ID.
42       elseif ($value instanceof ContainerInterface) {
43         $this->_serviceIds[$key] = 'service_container';
44         unset($vars[$key]);
45       }
46       elseif ($value instanceof EntityStorageInterface) {
47         // If a class member is an entity storage, only store the entity type ID
48         // the storage is for so it can be used to get a fresh object on
49         // unserialization. By doing this we prevent possible memory leaks when
50         // the storage is serialized when it contains a static cache of entity
51         // objects and additionally we ensure that we'll not have multiple
52         // storage objects for the same entity type and therefore prevent
53         // returning different references for the same entity.
54         $this->_entityStorages[$key] = $value->getEntityTypeId();
55         unset($vars[$key]);
56       }
57     }
58
59     return array_keys($vars);
60   }
61
62   /**
63    * {@inheritdoc}
64    */
65   public function __wakeup() {
66     // Tests in isolation potentially unserialize in the parent process.
67     $phpunit_bootstrap = isset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
68     if ($phpunit_bootstrap && !\Drupal::hasContainer()) {
69       return;
70     }
71     $container = \Drupal::getContainer();
72     foreach ($this->_serviceIds as $key => $service_id) {
73       // In rare cases, when test data is serialized in the parent process,
74       // there is a service container but it doesn't contain all expected
75       // services. To avoid fatal errors during the wrap-up of failing tests, we
76       // check for this case, too.
77       if ($phpunit_bootstrap && !$container->has($service_id)) {
78         continue;
79       }
80       $this->$key = $container->get($service_id);
81     }
82     $this->_serviceIds = [];
83
84     // In rare cases, when test data is serialized in the parent process, there
85     // is a service container but it doesn't contain all expected services. To
86     // avoid fatal errors during the wrap-up of failing tests, we check for this
87     // case, too.
88     if ($this->_entityStorages && (!$phpunit_bootstrap || $container->has('entity_type.manager'))) {
89       /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
90       $entity_type_manager = $container->get('entity_type.manager');
91       foreach ($this->_entityStorages as $key => $entity_type_id) {
92         $this->$key = $entity_type_manager->getStorage($entity_type_id);
93       }
94     }
95     $this->_entityStorages = [];
96   }
97
98 }