Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
74.07% covered (warning)
74.07%
40 / 54
33.33% covered (danger)
33.33%
3 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
InstanceStorage
74.07% covered (warning)
74.07%
40 / 54
33.33% covered (danger)
33.33%
3 / 9
20.46
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 createInstance
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 createFromImplementation
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
2.00
 loadUnchanged
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 has
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 getQueryServiceName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doLoadMultiple
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
4.37
 doSave
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 doDelete
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder;
6
7use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
8use Drupal\Core\Entity\EntityInterface;
9use Drupal\Core\Entity\EntityStorageBase;
10use Drupal\Core\Entity\EntityStorageInterface;
11use Drupal\Core\Entity\EntityTypeInterface;
12use Drupal\Core\Session\AccountInterface;
13use Drupal\Core\State\StateInterface;
14use Drupal\display_builder\Entity\Instance;
15use Symfony\Component\DependencyInjection\ContainerInterface;
16
17/**
18 * Base class for content entity storage handlers.
19 */
20class InstanceStorage extends EntityStorageBase implements EntityStorageInterface {
21
22  private const STORAGE_PREFIX = 'display_builder_';
23
24  private const STORAGE_INDEX = 'display_builder_index';
25
26  /**
27   * State API.
28   */
29  protected StateInterface $state;
30
31  /**
32   * Current user.
33   */
34  protected AccountInterface $currentUser;
35
36  /**
37   * {@inheritdoc}
38   */
39  public function __construct(EntityTypeInterface $entity_type, MemoryCacheInterface $memory_cache, StateInterface $state, AccountInterface $current_user) {
40    $this->state = $state;
41    $this->currentUser = $current_user;
42    parent::__construct($entity_type, $memory_cache);
43  }
44
45  /**
46   * {@inheritdoc}
47   */
48  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
49    return new static(
50      $entity_type,
51      $container->get('entity.memory_cache'),
52      $container->get('state'),
53      $container->get('current_user')
54    );
55  }
56
57  /**
58   * {@inheritdoc}
59   */
60  public function createFromImplementation(DisplayBuildableInterface $implementation): EntityInterface {
61    $data = $implementation->getInitialSources();
62    $present = new HistoryStep(
63      $data,
64      Instance::getUniqId($data),
65      'Initialization of the display builder.',
66      \time(),
67      (int) $this->currentUser->id(),
68    );
69    $data = [
70      'id' => $implementation->getInstanceId(),
71      'profileId' => $implementation->getProfile()->id(),
72      'contexts' => $implementation->getInitialContext(),
73      'present' => $present,
74    ];
75
76    /** @var \Drupal\display_builder\InstanceInterface $instance */
77    $instance = $this->create($data);
78
79    // If we get the data directly from config or content, the data is
80    // considered as already saved.
81    // If we convert it from other tools, or import it from other places, the
82    // user needs to save it themselves after retrieval.
83    if ($implementation->getSources()) {
84      $instance->setSave($implementation->getSources());
85    }
86
87    return $instance;
88  }
89
90  /**
91   * {@inheritdoc}
92   */
93  public function loadUnchanged($id) {
94    $this->state->resetCache();
95
96    return parent::loadUnchanged($id);
97  }
98
99  /**
100   * {@inheritdoc}
101   */
102  protected function has($id, EntityInterface $entity) {
103    if ($entity->isNew()) {
104      return FALSE;
105    }
106
107    return (bool) $this->state->get(self::STORAGE_PREFIX . $id, NULL);
108  }
109
110  /**
111   * {@inheritdoc}
112   */
113  protected function getQueryServiceName() {
114    return 'entity.query.null';
115  }
116
117  /**
118   * {@inheritdoc}
119   */
120  protected function doLoadMultiple(?array $ids = NULL) {
121    $entities = [];
122
123    if ($ids === NULL) {
124      $ids = \array_keys($this->state->get(self::STORAGE_INDEX, []));
125    }
126
127    foreach ($ids as $id) {
128      if ($data = $this->state->get(self::STORAGE_PREFIX . $id, NULL)) {
129        $entities[$id] = Instance::create($data);
130      }
131    }
132
133    return $entities;
134  }
135
136  /**
137   * {@inheritdoc}
138   */
139  protected function doSave($id, EntityInterface $entity): bool|int {
140    /** @var \Drupal\display_builder\InstanceInterface $entity */
141
142    $display_builder_list = $this->state->get(self::STORAGE_INDEX, []);
143
144    if (!isset($display_builder_list[$entity->id()])) {
145      $display_builder_list[$entity->id()] = '';
146    }
147
148    $this->state->set(self::STORAGE_INDEX, $display_builder_list);
149    $this->state->set(self::STORAGE_PREFIX . $entity->id(), $entity->toArray());
150    $this->state->set(self::STORAGE_PREFIX . $entity->id() . '_hash', $entity->getCurrent()->hash ?? '');
151
152    return TRUE;
153  }
154
155  /**
156   * {@inheritdoc}
157   */
158  protected function doDelete($entities): void {
159    foreach ($entities as $entity) {
160      $id = (string) $entity->id();
161      $display_builder_list = $this->state->get(self::STORAGE_INDEX, []);
162      unset($display_builder_list[$id]);
163
164      $this->state->set(self::STORAGE_INDEX, $display_builder_list);
165      $this->state->delete(self::STORAGE_PREFIX . $id);
166      $this->state->delete(self::STORAGE_PREFIX . $id . '_hash');
167    }
168  }
169
170}