Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 98 |
|
0.00% |
0 / 16 |
CRAP | |
0.00% |
0 / 1 |
DisplayBuilderItemList | |
0.00% |
0 / 98 |
|
0.00% |
0 / 16 |
870 | |
0.00% |
0 / 1 |
getPrefix | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getContextRequirement | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getBuilderUrl | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
checkInstanceId | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
getUrlFromInstanceId | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
getDisplayUrlFromInstanceId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getProfile | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
getInstanceId | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
getSources | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
saveSources | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
initInstanceIfMissing | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getInitialSources | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
getInitialContext | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
entityTypeManager | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getEntityViewDisplay | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
42 | |||
getInstance | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Drupal\display_builder_entity_view\Field; |
6 | |
7 | use Drupal\Core\Entity\EntityTypeManagerInterface; |
8 | use Drupal\Core\Field\MapFieldItemList; |
9 | use Drupal\Core\Plugin\Context\Context; |
10 | use Drupal\Core\Plugin\Context\ContextDefinition; |
11 | use Drupal\Core\Plugin\Context\EntityContext; |
12 | use Drupal\Core\Url; |
13 | use Drupal\display_builder\DisplayBuildableInterface; |
14 | use Drupal\display_builder\InstanceInterface; |
15 | use Drupal\display_builder\ProfileInterface; |
16 | use Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface; |
17 | use Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface; |
18 | use Drupal\ui_patterns\Plugin\Context\RequirementsContext; |
19 | |
20 | /** |
21 | * Defines an item list class for layout section fields. |
22 | * |
23 | * @internal |
24 | * Plugin classes are internal. |
25 | * |
26 | * @see \Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem |
27 | * |
28 | * phpcs:disable DrupalPractice.Objects.GlobalDrupal.GlobalDrupal |
29 | */ |
30 | final class DisplayBuilderItemList extends MapFieldItemList implements DisplayBuildableInterface { |
31 | |
32 | /** |
33 | * The entity type manager. |
34 | */ |
35 | protected ?EntityTypeManagerInterface $entityTypeManager; |
36 | |
37 | /** |
38 | * The loaded display builder instance. |
39 | */ |
40 | protected ?InstanceInterface $instance; |
41 | |
42 | /** |
43 | * {@inheritdoc} |
44 | */ |
45 | public static function getPrefix(): string { |
46 | return 'entity_override__'; |
47 | } |
48 | |
49 | /** |
50 | * {@inheritdoc} |
51 | */ |
52 | public static function getContextRequirement(): string { |
53 | return 'content'; |
54 | } |
55 | |
56 | /** |
57 | * {@inheritdoc} |
58 | */ |
59 | public function getBuilderUrl(): Url { |
60 | \assert(\is_string($this->getName())); |
61 | $entity = $this->getEntity(); |
62 | $entity_view = self::getEntityViewDisplay( |
63 | $entity->getEntityTypeId(), |
64 | $entity->bundle(), |
65 | $this->getName(), |
66 | ); |
67 | $entity_type_id = $entity_view->getTargetEntityTypeId(); |
68 | $parameters = [ |
69 | $entity_type_id => $entity->id(), |
70 | 'view_mode_name' => $entity_view->getMode(), |
71 | ]; |
72 | |
73 | return Url::fromRoute("entity.{$entity_type_id}.display_builder.{$entity_view->getMode()}", $parameters); |
74 | } |
75 | |
76 | /** |
77 | * {@inheritdoc} |
78 | */ |
79 | public static function checkInstanceId(string $instance_id): ?array { |
80 | if (!\str_starts_with($instance_id, self::getPrefix())) { |
81 | return NULL; |
82 | } |
83 | [, $entity_type_id, $entity_id, $field_name] = \explode('__', $instance_id); |
84 | |
85 | return [ |
86 | 'entity_type_id' => $entity_type_id, |
87 | 'entity_id' => $entity_id, |
88 | 'field_name' => $field_name, |
89 | ]; |
90 | } |
91 | |
92 | /** |
93 | * {@inheritdoc} |
94 | */ |
95 | public static function getUrlFromInstanceId(string $instance_id): Url { |
96 | [, $entity_type_id, $entity_id, $field_name] = \explode('__', $instance_id); |
97 | |
98 | $entity = \Drupal::entityTypeManager()->getStorage($entity_type_id)->load($entity_id); |
99 | $display = self::getEntityViewDisplay($entity_type_id, $entity->bundle(), $field_name); |
100 | $params = [ |
101 | $entity_type_id => $entity_id, |
102 | 'view_mode_name' => $display->getMode(), |
103 | ]; |
104 | |
105 | $route_name = \sprintf('entity.%s.display_builder.%s', $entity_type_id, $display->getMode()); |
106 | |
107 | return Url::fromRoute($route_name, $params); |
108 | } |
109 | |
110 | /** |
111 | * {@inheritdoc} |
112 | */ |
113 | public static function getDisplayUrlFromInstanceId(string $instance_id): Url { |
114 | return Url::fromRoute('<front>'); |
115 | } |
116 | |
117 | /** |
118 | * {@inheritdoc} |
119 | */ |
120 | public function getProfile(): ?ProfileInterface { |
121 | \assert(\is_string($this->getName())); |
122 | $entity = $this->getEntity(); |
123 | |
124 | $entity_view = self::getEntityViewDisplay( |
125 | $entity->getEntityTypeId(), |
126 | $entity->bundle(), |
127 | $this->getName(), |
128 | ); |
129 | \assert($entity_view instanceof DisplayBuilderOverridableInterface); |
130 | |
131 | return $entity_view->getDisplayBuilderOverrideProfile(); |
132 | } |
133 | |
134 | /** |
135 | * {@inheritdoc} |
136 | */ |
137 | public function getInstanceId(): ?string { |
138 | // Usually an entity is new if no ID exists for it yet. |
139 | if ($this->getEntity()->isNew()) { |
140 | return NULL; |
141 | } |
142 | |
143 | $entity = $this->getEntity(); |
144 | |
145 | return \sprintf('%s%s__%s__%s', |
146 | self::getPrefix(), |
147 | $entity->getEntityTypeId(), |
148 | $entity->id(), |
149 | $this->getName() |
150 | ); |
151 | } |
152 | |
153 | /** |
154 | * {@inheritdoc} |
155 | */ |
156 | public function getSources(): array { |
157 | $data = []; |
158 | |
159 | foreach ($this->list as $offset => $item) { |
160 | $data[$offset] = $item->getValue(); |
161 | } |
162 | |
163 | return $data; |
164 | } |
165 | |
166 | /** |
167 | * {@inheritdoc} |
168 | */ |
169 | public function saveSources(): void { |
170 | $data = $this->getInstance()->getCurrentState(); |
171 | $this->list = []; |
172 | |
173 | foreach ($data as $offset => $item) { |
174 | $this->list[$offset] = $this->createItem($offset, $item); |
175 | } |
176 | $this->getEntity()->save(); |
177 | } |
178 | |
179 | /** |
180 | * {@inheritdoc} |
181 | */ |
182 | public function initInstanceIfMissing(): void { |
183 | /** @var \Drupal\display_builder\InstanceStorage $storage */ |
184 | $storage = $this->entityTypeManager()->getStorage('display_builder_instance'); |
185 | |
186 | /** @var \Drupal\display_builder\InstanceInterface $instance */ |
187 | $instance = $storage->load($this->getInstanceId()); |
188 | |
189 | if (!$instance) { |
190 | $instance = $storage->createFromImplementation($this); |
191 | $instance->save(); |
192 | } |
193 | } |
194 | |
195 | /** |
196 | * {@inheritdoc} |
197 | */ |
198 | public function getInitialSources(): array { |
199 | $sources = $this->getSources(); |
200 | $entity = $this->getEntity(); |
201 | |
202 | if (\count($sources) === 0) { |
203 | \assert(\is_string($this->getName())); |
204 | $display = self::getEntityViewDisplay($entity->getEntityTypeId(), $entity->bundle(), $this->getName()); |
205 | |
206 | if ($display->getProfile() !== NULL) { |
207 | $sources = $display->getSources(); |
208 | } |
209 | } |
210 | |
211 | return $sources; |
212 | } |
213 | |
214 | /** |
215 | * {@inheritdoc} |
216 | */ |
217 | public function getInitialContext(): array { |
218 | $entity = $this->getEntity(); |
219 | $bundle = $entity->bundle(); |
220 | \assert(\is_string($this->getName())); |
221 | |
222 | $view_mode = self::getEntityViewDisplay($entity->getEntityTypeId(), $bundle, $this->getName())->getMode(); |
223 | $contexts = [ |
224 | 'entity' => EntityContext::fromEntity($entity), |
225 | 'bundle' => new Context(ContextDefinition::create('string'), $bundle), |
226 | 'view_mode' => new Context(ContextDefinition::create('string'), $view_mode), |
227 | ]; |
228 | |
229 | return RequirementsContext::addToContext([self::getContextRequirement()], $contexts); |
230 | } |
231 | |
232 | /** |
233 | * Get the entity type manager. |
234 | * |
235 | * @return \Drupal\Core\Entity\EntityTypeManagerInterface |
236 | * The entity type manager. |
237 | */ |
238 | protected function entityTypeManager(): EntityTypeManagerInterface { |
239 | return $this->entityTypeManager ??= \Drupal::service('entity_type.manager'); |
240 | } |
241 | |
242 | /** |
243 | * Get entity view display entity. |
244 | * |
245 | * @param string $entity_type_id |
246 | * Entity type ID. |
247 | * @param string $bundle |
248 | * Entity's bundle which support fields. |
249 | * @param string $fieldName |
250 | * Field name of the display. |
251 | * |
252 | * @return \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface|null |
253 | * The corresponding entity view display. |
254 | */ |
255 | private static function getEntityViewDisplay(string $entity_type_id, string $bundle, string $fieldName): ?DisplayBuilderEntityDisplayInterface { |
256 | /** @var \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface[] $displays */ |
257 | $displays = \Drupal::entityTypeManager()->getStorage('entity_view_display')->loadByProperties([ |
258 | 'targetEntityType' => $entity_type_id, |
259 | ]); |
260 | |
261 | foreach ($displays as $display) { |
262 | if ($display instanceof DisplayBuilderOverridableInterface |
263 | && $display->getDisplayBuilderOverrideField() === $fieldName |
264 | && $display->getTargetEntityTypeId() |
265 | && $display->getTargetBundle() === $bundle |
266 | ) { |
267 | return $display; |
268 | } |
269 | } |
270 | |
271 | return NULL; |
272 | } |
273 | |
274 | /** |
275 | * Gets the Display Builder instance. |
276 | * |
277 | * @return \Drupal\display_builder\InstanceInterface|null |
278 | * A display builder instance. |
279 | */ |
280 | private function getInstance(): ?InstanceInterface { |
281 | if (!isset($this->instance)) { |
282 | /** @var \Drupal\display_builder\InstanceInterface|null $instance */ |
283 | $instance = $this->entityTypeManager()->getStorage('display_builder_instance')->load($this->getInstanceId()); |
284 | $this->instance = $instance; |
285 | } |
286 | |
287 | return $this->instance; |
288 | } |
289 | |
290 | } |