Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / lib / Drupal / Core / Entity / KeyValueStore / KeyValueEntityStorage.php
1 <?php
2
3 namespace Drupal\Core\Entity\KeyValueStore;
4
5 use Drupal\Component\Uuid\UuidInterface;
6 use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
7 use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
8 use Drupal\Core\Entity\FieldableEntityInterface;
9 use Drupal\Core\Entity\EntityInterface;
10 use Drupal\Core\Entity\EntityMalformedException;
11 use Drupal\Core\Entity\EntityStorageBase;
12 use Drupal\Core\Entity\EntityTypeInterface;
13 use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
14 use Drupal\Core\Language\LanguageManagerInterface;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16
17 /**
18  * Provides a key value backend for entities.
19  *
20  * @todo Entities that depend on auto-incrementing serial IDs need to explicitly
21  *   provide an ID until a generic wrapper around the functionality provided by
22  *   \Drupal\Core\Database\Connection::nextId() is added and used.
23  * @todo Revisions are currently not supported.
24  */
25 class KeyValueEntityStorage extends EntityStorageBase {
26
27   /**
28    * Length limit of the entity ID.
29    */
30   const MAX_ID_LENGTH = 128;
31
32   /**
33    * The key value store.
34    *
35    * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
36    */
37   protected $keyValueStore;
38
39   /**
40    * The UUID service.
41    *
42    * @var \Drupal\Component\Uuid\UuidInterface
43    */
44   protected $uuidService;
45
46   /**
47    * The language manager.
48    *
49    * @var \Drupal\Core\Language\LanguageManagerInterface
50    */
51   protected $languageManager;
52
53   /**
54    * Constructs a new KeyValueEntityStorage.
55    *
56    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
57    *   The entity type.
58    * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $key_value_store
59    *   The key value store.
60    * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
61    *   The UUID service.
62    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
63    *   The language manager.
64    * @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
65    *   The memory cache.
66    */
67   public function __construct(EntityTypeInterface $entity_type, KeyValueStoreInterface $key_value_store, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, MemoryCacheInterface $memory_cache = NULL) {
68     parent::__construct($entity_type, $memory_cache);
69     $this->keyValueStore = $key_value_store;
70     $this->uuidService = $uuid_service;
71     $this->languageManager = $language_manager;
72
73     // Check if the entity type supports UUIDs.
74     $this->uuidKey = $this->entityType->getKey('uuid');
75   }
76
77   /**
78    * {@inheritdoc}
79    */
80   public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
81     return new static(
82       $entity_type,
83       $container->get('keyvalue')->get('entity_storage__' . $entity_type->id()),
84       $container->get('uuid'),
85       $container->get('language_manager'),
86       $container->get('entity.memory_cache')
87     );
88   }
89
90   /**
91    * {@inheritdoc}
92    */
93   public function doCreate(array $values = []) {
94     // Set default language to site default if not provided.
95     $values += [$this->getEntityType()->getKey('langcode') => $this->languageManager->getDefaultLanguage()->getId()];
96     $entity = new $this->entityClass($values, $this->entityTypeId);
97
98     // @todo This is handled by ContentEntityStorageBase, which assumes
99     //   FieldableEntityInterface. The current approach in
100     //   https://www.drupal.org/node/1867228 improves this but does not solve it
101     //   completely.
102     if ($entity instanceof FieldableEntityInterface) {
103       foreach ($entity as $name => $field) {
104         if (isset($values[$name])) {
105           $entity->$name = $values[$name];
106         }
107         elseif (!array_key_exists($name, $values)) {
108           $entity->get($name)->applyDefaultValue();
109         }
110         unset($values[$name]);
111       }
112     }
113
114     return $entity;
115   }
116
117   /**
118    * {@inheritdoc}
119    */
120   public function doLoadMultiple(array $ids = NULL) {
121     if (empty($ids)) {
122       $entities = $this->keyValueStore->getAll();
123     }
124     else {
125       $entities = $this->keyValueStore->getMultiple($ids);
126     }
127     return $this->mapFromStorageRecords($entities);
128   }
129
130   /**
131    * {@inheritdoc}
132    */
133   public function loadRevision($revision_id) {
134     return NULL;
135   }
136
137   /**
138    * {@inheritdoc}
139    */
140   public function deleteRevision($revision_id) {
141     return NULL;
142   }
143
144   /**
145    * {@inheritdoc}
146    */
147   public function doDelete($entities) {
148     $entity_ids = array_keys($entities);
149     $this->keyValueStore->deleteMultiple($entity_ids);
150   }
151
152   /**
153    * {@inheritdoc}
154    */
155   public function save(EntityInterface $entity) {
156     $id = $entity->id();
157     if ($id === NULL || $id === '') {
158       throw new EntityMalformedException('The entity does not have an ID.');
159     }
160
161     // Check the entity ID length.
162     // @todo This is not config-specific, but serial IDs will likely never hit
163     //   this limit. Consider renaming the exception class.
164     if (strlen($entity->id()) > static::MAX_ID_LENGTH) {
165       throw new ConfigEntityIdLengthException("Entity ID {$entity->id()} exceeds maximum allowed length of " . static::MAX_ID_LENGTH . ' characters.');
166     }
167     return parent::save($entity);
168   }
169
170   /**
171    * {@inheritdoc}
172    */
173   protected function doSave($id, EntityInterface $entity) {
174     $is_new = $entity->isNew();
175
176     // Save the entity data in the key value store.
177     $this->keyValueStore->set($entity->id(), $entity->toArray());
178
179     // If this is a rename, delete the original entity.
180     if ($this->has($id, $entity) && $id !== $entity->id()) {
181       $this->keyValueStore->delete($id);
182     }
183
184     return $is_new ? SAVED_NEW : SAVED_UPDATED;
185   }
186
187   /**
188    * {@inheritdoc}
189    */
190   protected function has($id, EntityInterface $entity) {
191     return $this->keyValueStore->has($id);
192   }
193
194   /**
195    * {@inheritdoc}
196    */
197   public function hasData() {
198     return (bool) $this->keyValueStore->getAll();
199   }
200
201   /**
202    * {@inheritdoc}
203    */
204   protected function getQueryServiceName() {
205     return 'entity.query.keyvalue';
206   }
207
208 }