Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / web / core / modules / layout_builder / src / Plugin / SectionStorage / DefaultsSectionStorage.php
1 <?php
2
3 namespace Drupal\layout_builder\Plugin\SectionStorage;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Core\Access\AccessResult;
7 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
8 use Drupal\Core\Entity\EntityTypeInterface;
9 use Drupal\Core\Entity\EntityTypeManagerInterface;
10 use Drupal\Core\Entity\FieldableEntityInterface;
11 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
12 use Drupal\Core\Plugin\Context\EntityContext;
13 use Drupal\Core\Session\AccountInterface;
14 use Drupal\Core\Url;
15 use Drupal\field_ui\FieldUI;
16 use Drupal\layout_builder\DefaultsSectionStorageInterface;
17 use Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator;
18 use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
19 use Drupal\layout_builder\SectionListInterface;
20 use Symfony\Component\DependencyInjection\ContainerInterface;
21 use Symfony\Component\Routing\RouteCollection;
22
23 /**
24  * Defines the 'defaults' section storage type.
25  *
26  * @SectionStorage(
27  *   id = "defaults",
28  * )
29  *
30  * @internal
31  *   Layout Builder is currently experimental and should only be leveraged by
32  *   experimental modules and development releases of contributed modules.
33  *   See https://www.drupal.org/core/experimental for more information.
34  */
35 class DefaultsSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, DefaultsSectionStorageInterface, SectionStorageLocalTaskProviderInterface {
36
37   /**
38    * The entity type manager.
39    *
40    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
41    */
42   protected $entityTypeManager;
43
44   /**
45    * The entity type bundle info.
46    *
47    * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
48    */
49   protected $entityTypeBundleInfo;
50
51   /**
52    * {@inheritdoc}
53    *
54    * @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface
55    */
56   protected $sectionList;
57
58   /**
59    * The sample entity generator.
60    *
61    * @var \Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator
62    */
63   protected $sampleEntityGenerator;
64
65   /**
66    * {@inheritdoc}
67    */
68   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, LayoutBuilderSampleEntityGenerator $sample_entity_generator) {
69     parent::__construct($configuration, $plugin_id, $plugin_definition);
70
71     $this->entityTypeManager = $entity_type_manager;
72     $this->entityTypeBundleInfo = $entity_type_bundle_info;
73     $this->sampleEntityGenerator = $sample_entity_generator;
74   }
75
76   /**
77    * {@inheritdoc}
78    */
79   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
80     return new static(
81       $configuration,
82       $plugin_id,
83       $plugin_definition,
84       $container->get('entity_type.manager'),
85       $container->get('entity_type.bundle.info'),
86       $container->get('layout_builder.sample_entity_generator')
87     );
88   }
89
90   /**
91    * {@inheritdoc}
92    */
93   public function setSectionList(SectionListInterface $section_list) {
94     if (!$section_list instanceof LayoutEntityDisplayInterface) {
95       throw new \InvalidArgumentException('Defaults expect a display-based section list');
96     }
97
98     return parent::setSectionList($section_list);
99   }
100
101   /**
102    * Gets the entity storing the overrides.
103    *
104    * @return \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface
105    *   The entity storing the defaults.
106    */
107   protected function getDisplay() {
108     return $this->getSectionList();
109   }
110
111   /**
112    * {@inheritdoc}
113    */
114   public function getStorageId() {
115     return $this->getDisplay()->id();
116   }
117
118   /**
119    * {@inheritdoc}
120    */
121   public function getRedirectUrl() {
122     return Url::fromRoute("entity.entity_view_display.{$this->getDisplay()->getTargetEntityTypeId()}.view_mode", $this->getRouteParameters());
123   }
124
125   /**
126    * {@inheritdoc}
127    */
128   public function getLayoutBuilderUrl($rel = 'view') {
129     return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getDisplay()->getTargetEntityTypeId()}.$rel", $this->getRouteParameters());
130   }
131
132   /**
133    * Provides the route parameters needed to generate a URL for this object.
134    *
135    * @return mixed[]
136    *   An associative array of parameter names and values.
137    */
138   protected function getRouteParameters() {
139     $display = $this->getDisplay();
140     $entity_type = $this->entityTypeManager->getDefinition($display->getTargetEntityTypeId());
141     $route_parameters = FieldUI::getRouteBundleParameter($entity_type, $display->getTargetBundle());
142     $route_parameters['view_mode_name'] = $display->getMode();
143     return $route_parameters;
144   }
145
146   /**
147    * {@inheritdoc}
148    */
149   public function buildRoutes(RouteCollection $collection) {
150     foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
151       // Try to get the route from the current collection.
152       if (!$entity_route = $collection->get($entity_type->get('field_ui_base_route'))) {
153         continue;
154       }
155
156       $path = $entity_route->getPath() . '/display-layout/{view_mode_name}';
157
158       $defaults = [];
159       $defaults['entity_type_id'] = $entity_type_id;
160       // If the entity type has no bundles and it doesn't use {bundle} in its
161       // admin path, use the entity type.
162       if (strpos($path, '{bundle}') === FALSE) {
163         if (!$entity_type->hasKey('bundle')) {
164           $defaults['bundle'] = $entity_type_id;
165         }
166         else {
167           $defaults['bundle_key'] = $entity_type->getBundleEntityType();
168         }
169       }
170
171       $requirements = [];
172       $requirements['_field_ui_view_mode_access'] = 'administer ' . $entity_type_id . ' display';
173
174       $options = $entity_route->getOptions();
175       $options['_admin_route'] = FALSE;
176
177       $this->buildLayoutRoutes($collection, $this->getPluginDefinition(), $path, $defaults, $requirements, $options, $entity_type_id);
178
179       $route_names = [
180         "entity.entity_view_display.{$entity_type_id}.default",
181         "entity.entity_view_display.{$entity_type_id}.view_mode",
182       ];
183       foreach ($route_names as $route_name) {
184         if (!$route = $collection->get($route_name)) {
185           continue;
186         }
187
188         $route->addDefaults([
189           'section_storage_type' => $this->getStorageType(),
190           'section_storage' => '',
191         ] + $defaults);
192         $parameters['section_storage']['layout_builder_tempstore'] = TRUE;
193         $parameters = NestedArray::mergeDeep($parameters, $route->getOption('parameters') ?: []);
194         $route->setOption('parameters', $parameters);
195       }
196     }
197   }
198
199   /**
200    * {@inheritdoc}
201    */
202   public function buildLocalTasks($base_plugin_definition) {
203     $local_tasks = [];
204     foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
205       $local_tasks["layout_builder.defaults.$entity_type_id.view"] = $base_plugin_definition + [
206         'route_name' => "layout_builder.defaults.$entity_type_id.view",
207         'title' => $this->t('Manage layout'),
208         'base_route' => "layout_builder.defaults.$entity_type_id.view",
209       ];
210       $local_tasks["layout_builder.defaults.$entity_type_id.save"] = $base_plugin_definition + [
211         'route_name' => "layout_builder.defaults.$entity_type_id.save",
212         'title' => $this->t('Save Layout'),
213         'parent_id' => "layout_builder_ui:layout_builder.defaults.$entity_type_id.view",
214       ];
215       $local_tasks["layout_builder.defaults.$entity_type_id.cancel"] = $base_plugin_definition + [
216         'route_name' => "layout_builder.defaults.$entity_type_id.cancel",
217         'title' => $this->t('Cancel Layout'),
218         'weight' => 5,
219         'parent_id' => "layout_builder_ui:layout_builder.defaults.$entity_type_id.view",
220       ];
221     }
222     return $local_tasks;
223   }
224
225   /**
226    * Returns an array of relevant entity types.
227    *
228    * @return \Drupal\Core\Entity\EntityTypeInterface[]
229    *   An array of entity types.
230    */
231   protected function getEntityTypes() {
232     return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
233       return $entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasViewBuilderClass() && $entity_type->get('field_ui_base_route');
234     });
235   }
236
237   /**
238    * {@inheritdoc}
239    */
240   public function extractIdFromRoute($value, $definition, $name, array $defaults) {
241     if (is_string($value) && strpos($value, '.') !== FALSE) {
242       return $value;
243     }
244
245     // If a bundle is not provided but a value corresponding to the bundle key
246     // is, use that for the bundle value.
247     if (empty($defaults['bundle']) && isset($defaults['bundle_key']) && !empty($defaults[$defaults['bundle_key']])) {
248       $defaults['bundle'] = $defaults[$defaults['bundle_key']];
249     }
250
251     if (!empty($defaults['entity_type_id']) && !empty($defaults['bundle']) && !empty($defaults['view_mode_name'])) {
252       return $defaults['entity_type_id'] . '.' . $defaults['bundle'] . '.' . $defaults['view_mode_name'];
253     }
254   }
255
256   /**
257    * {@inheritdoc}
258    */
259   public function getSectionListFromId($id) {
260     if (strpos($id, '.') === FALSE) {
261       throw new \InvalidArgumentException(sprintf('The "%s" ID for the "%s" section storage type is invalid', $id, $this->getStorageType()));
262     }
263
264     $storage = $this->entityTypeManager->getStorage('entity_view_display');
265     // If the display does not exist, create a new one.
266     if (!$display = $storage->load($id)) {
267       list($entity_type_id, $bundle, $view_mode) = explode('.', $id, 3);
268       $display = $storage->create([
269         'targetEntityType' => $entity_type_id,
270         'bundle' => $bundle,
271         'mode' => $view_mode,
272         'status' => TRUE,
273       ]);
274     }
275     return $display;
276   }
277
278   /**
279    * {@inheritdoc}
280    */
281   public function getContexts() {
282     $display = $this->getDisplay();
283     $entity = $this->sampleEntityGenerator->get($display->getTargetEntityTypeId(), $display->getTargetBundle());
284
285     $contexts = [];
286     $contexts['layout_builder.entity'] = EntityContext::fromEntity($entity);
287     return $contexts;
288   }
289
290   /**
291    * {@inheritdoc}
292    */
293   public function label() {
294     return $this->getDisplay()->label();
295   }
296
297   /**
298    * {@inheritdoc}
299    */
300   public function save() {
301     return $this->getDisplay()->save();
302   }
303
304   /**
305    * {@inheritdoc}
306    */
307   public function isOverridable() {
308     return $this->getDisplay()->isOverridable();
309   }
310
311   /**
312    * {@inheritdoc}
313    */
314   public function setOverridable($overridable = TRUE) {
315     $this->getDisplay()->setOverridable($overridable);
316     return $this;
317   }
318
319   /**
320    * {@inheritdoc}
321    */
322   public function setThirdPartySetting($module, $key, $value) {
323     $this->getDisplay()->setThirdPartySetting($module, $key, $value);
324     return $this;
325   }
326
327   /**
328    * {@inheritdoc}
329    */
330   public function isLayoutBuilderEnabled() {
331     return $this->getDisplay()->isLayoutBuilderEnabled();
332   }
333
334   /**
335    * {@inheritdoc}
336    */
337   public function enableLayoutBuilder() {
338     $this->getDisplay()->enableLayoutBuilder();
339     return $this;
340   }
341
342   /**
343    * {@inheritdoc}
344    */
345   public function disableLayoutBuilder() {
346     $this->getDisplay()->disableLayoutBuilder();
347     return $this;
348   }
349
350   /**
351    * {@inheritdoc}
352    */
353   public function getThirdPartySetting($module, $key, $default = NULL) {
354     return $this->getDisplay()->getThirdPartySetting($module, $key, $default);
355   }
356
357   /**
358    * {@inheritdoc}
359    */
360   public function getThirdPartySettings($module) {
361     return $this->getDisplay()->getThirdPartySettings($module);
362   }
363
364   /**
365    * {@inheritdoc}
366    */
367   public function unsetThirdPartySetting($module, $key) {
368     $this->getDisplay()->unsetThirdPartySetting($module, $key);
369     return $this;
370   }
371
372   /**
373    * {@inheritdoc}
374    */
375   public function getThirdPartyProviders() {
376     return $this->getDisplay()->getThirdPartyProviders();
377   }
378
379   /**
380    * {@inheritdoc}
381    */
382   public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
383     $result = AccessResult::allowedIf($this->isLayoutBuilderEnabled());
384     return $return_as_object ? $result : $result->isAllowed();
385   }
386
387 }