Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
[yaffs-website] / web / core / modules / layout_builder / src / Plugin / SectionStorage / OverridesSectionStorage.php
1 <?php
2
3 namespace Drupal\layout_builder\Plugin\SectionStorage;
4
5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\Entity\EntityFieldManagerInterface;
7 use Drupal\Core\Entity\EntityTypeInterface;
8 use Drupal\Core\Entity\EntityTypeManagerInterface;
9 use Drupal\Core\Entity\FieldableEntityInterface;
10 use Drupal\Core\Field\FieldItemListInterface;
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\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
16 use Drupal\layout_builder\OverridesSectionStorageInterface;
17 use Drupal\layout_builder\SectionListInterface;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
19 use Symfony\Component\Routing\RouteCollection;
20
21 /**
22  * Defines the 'overrides' section storage type.
23  *
24  * @SectionStorage(
25  *   id = "overrides",
26  * )
27  *
28  * @internal
29  *   Layout Builder is currently experimental and should only be leveraged by
30  *   experimental modules and development releases of contributed modules.
31  *   See https://www.drupal.org/core/experimental for more information.
32  */
33 class OverridesSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, OverridesSectionStorageInterface {
34
35   /**
36    * The entity type manager.
37    *
38    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
39    */
40   protected $entityTypeManager;
41
42   /**
43    * The entity field manager.
44    *
45    * @var \Drupal\Core\Entity\EntityFieldManagerInterface
46    */
47   protected $entityFieldManager;
48
49   /**
50    * {@inheritdoc}
51    *
52    * @var \Drupal\layout_builder\SectionListInterface|\Drupal\Core\Field\FieldItemListInterface
53    */
54   protected $sectionList;
55
56   /**
57    * {@inheritdoc}
58    */
59   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
60     parent::__construct($configuration, $plugin_id, $plugin_definition);
61
62     $this->entityTypeManager = $entity_type_manager;
63     $this->entityFieldManager = $entity_field_manager;
64   }
65
66   /**
67    * {@inheritdoc}
68    */
69   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
70     return new static(
71       $configuration,
72       $plugin_id,
73       $plugin_definition,
74       $container->get('entity_type.manager'),
75       $container->get('entity_field.manager')
76     );
77   }
78
79   /**
80    * {@inheritdoc}
81    */
82   public function setSectionList(SectionListInterface $section_list) {
83     if (!$section_list instanceof FieldItemListInterface) {
84       throw new \InvalidArgumentException('Overrides expect a field-based section list');
85     }
86
87     return parent::setSectionList($section_list);
88   }
89
90   /**
91    * Gets the entity storing the overrides.
92    *
93    * @return \Drupal\Core\Entity\FieldableEntityInterface
94    *   The entity storing the overrides.
95    */
96   protected function getEntity() {
97     return $this->getSectionList()->getEntity();
98   }
99
100   /**
101    * {@inheritdoc}
102    */
103   public function getStorageId() {
104     $entity = $this->getEntity();
105     return $entity->getEntityTypeId() . '.' . $entity->id();
106   }
107
108   /**
109    * {@inheritdoc}
110    */
111   public function extractIdFromRoute($value, $definition, $name, array $defaults) {
112     if (strpos($value, '.') !== FALSE) {
113       return $value;
114     }
115
116     if (isset($defaults['entity_type_id']) && !empty($defaults[$defaults['entity_type_id']])) {
117       $entity_type_id = $defaults['entity_type_id'];
118       $entity_id = $defaults[$entity_type_id];
119       return $entity_type_id . '.' . $entity_id;
120     }
121   }
122
123   /**
124    * {@inheritdoc}
125    */
126   public function getSectionListFromId($id) {
127     if (strpos($id, '.') !== FALSE) {
128       list($entity_type_id, $entity_id) = explode('.', $id, 2);
129       $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($entity_id);
130       if ($entity instanceof FieldableEntityInterface && $entity->hasField('layout_builder__layout')) {
131         return $entity->get('layout_builder__layout');
132       }
133     }
134     throw new \InvalidArgumentException(sprintf('The "%s" ID for the "%s" section storage type is invalid', $id, $this->getStorageType()));
135   }
136
137   /**
138    * {@inheritdoc}
139    */
140   public function buildRoutes(RouteCollection $collection) {
141     foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
142       $defaults = [];
143       $defaults['entity_type_id'] = $entity_type_id;
144
145       $requirements = [];
146       if ($this->hasIntegerId($entity_type)) {
147         $requirements[$entity_type_id] = '\d+';
148       }
149
150       $options = [];
151       // Ensure that upcasting is run in the correct order.
152       $options['parameters']['section_storage'] = [];
153       $options['parameters'][$entity_type_id]['type'] = 'entity:' . $entity_type_id;
154
155       $template = $entity_type->getLinkTemplate('canonical') . '/layout';
156       $this->buildLayoutRoutes($collection, $this->getPluginDefinition(), $template, $defaults, $requirements, $options, $entity_type_id);
157     }
158   }
159
160   /**
161    * Determines if this entity type's ID is stored as an integer.
162    *
163    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
164    *   An entity type.
165    *
166    * @return bool
167    *   TRUE if this entity type's ID key is always an integer, FALSE otherwise.
168    */
169   protected function hasIntegerId(EntityTypeInterface $entity_type) {
170     $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type->id());
171     return $field_storage_definitions[$entity_type->getKey('id')]->getType() === 'integer';
172   }
173
174   /**
175    * Returns an array of relevant entity types.
176    *
177    * @return \Drupal\Core\Entity\EntityTypeInterface[]
178    *   An array of entity types.
179    */
180   protected function getEntityTypes() {
181     return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
182       return $entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasViewBuilderClass() && $entity_type->hasLinkTemplate('canonical');
183     });
184   }
185
186   /**
187    * {@inheritdoc}
188    */
189   public function getDefaultSectionStorage() {
190     // @todo Expand to work for all view modes in
191     //   https://www.drupal.org/node/2907413.
192     return LayoutBuilderEntityViewDisplay::collectRenderDisplay($this->getEntity(), 'full');
193   }
194
195   /**
196    * {@inheritdoc}
197    */
198   public function getRedirectUrl() {
199     return $this->getEntity()->toUrl('canonical');
200   }
201
202   /**
203    * {@inheritdoc}
204    */
205   public function getLayoutBuilderUrl($rel = 'view') {
206     $entity = $this->getEntity();
207     $route_parameters[$entity->getEntityTypeId()] = $entity->id();
208     return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getEntity()->getEntityTypeId()}.$rel", $route_parameters);
209   }
210
211   /**
212    * {@inheritdoc}
213    */
214   public function getContexts() {
215     $entity = $this->getEntity();
216     $contexts['layout_builder.entity'] = EntityContext::fromEntity($entity);
217     return $contexts;
218   }
219
220   /**
221    * {@inheritdoc}
222    */
223   public function label() {
224     return $this->getEntity()->label();
225   }
226
227   /**
228    * {@inheritdoc}
229    */
230   public function save() {
231     return $this->getEntity()->save();
232   }
233
234   /**
235    * {@inheritdoc}
236    */
237   public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
238     $default_section_storage = $this->getDefaultSectionStorage();
239     $result = AccessResult::allowedIf($default_section_storage->isLayoutBuilderEnabled())->addCacheableDependency($default_section_storage);
240     return $return_as_object ? $result : $result->isAllowed();
241   }
242
243 }