Pull merge.
[yaffs-website] / web / core / modules / layout_builder / layout_builder.module
1 <?php
2
3 /**
4  * @file
5  * Provides hook implementations for Layout Builder.
6  */
7
8 use Drupal\Core\Entity\EntityInterface;
9 use Drupal\Core\Form\FormStateInterface;
10 use Drupal\Core\Routing\RouteMatchInterface;
11 use Drupal\Core\Url;
12 use Drupal\field\FieldConfigInterface;
13 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
14 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage;
15 use Drupal\layout_builder\Form\LayoutBuilderEntityViewDisplayForm;
16 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
17 use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
18 use Drupal\layout_builder\Plugin\Block\ExtraFieldBlock;
19 use Drupal\layout_builder\InlineBlockEntityOperations;
20 use Drupal\Core\Session\AccountInterface;
21 use Drupal\Core\Access\AccessResult;
22 use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
23
24 /**
25  * Implements hook_help().
26  */
27 function layout_builder_help($route_name, RouteMatchInterface $route_match) {
28   // Add help text to the Layout Builder UI.
29   if ($route_match->getRouteObject()->getOption('_layout_builder')) {
30     $output = '<p>' . t('This layout builder tool allows you to configure the layout of the main content area.') . '</p>';
31     if (\Drupal::currentUser()->hasPermission('administer blocks')) {
32       $output .= '<p>' . t('To manage other areas of the page, use the <a href="@block-ui">block administration page</a>.', ['@block-ui' => Url::fromRoute('block.admin_display')->toString()]) . '</p>';
33     }
34     else {
35       $output .= '<p>' . t('To manage other areas of the page, use the block administration page.') . '</p>';
36     }
37     return $output;
38   }
39
40   switch ($route_name) {
41     case 'help.page.layout_builder':
42       $output = '<h3>' . t('About') . '</h3>';
43       $output .= '<p>' . t('Layout Builder provides layout building utility.') . '</p>';
44       $output .= '<p>' . t('For more information, see the <a href=":layout-builder-documentation">online documentation for the Layout Builder module</a>.', [':layout-builder-documentation' => 'https://www.drupal.org/docs/8/core/modules/layout_builder']) . '</p>';
45       return $output;
46   }
47 }
48
49 /**
50  * Implements hook_entity_type_alter().
51  */
52 function layout_builder_entity_type_alter(array &$entity_types) {
53   /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
54   $entity_types['entity_view_display']
55     ->setClass(LayoutBuilderEntityViewDisplay::class)
56     ->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class)
57     ->setFormClass('edit', LayoutBuilderEntityViewDisplayForm::class);
58 }
59
60 /**
61  * Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm.
62  */
63 function layout_builder_form_entity_form_display_edit_form_alter(&$form, FormStateInterface $form_state) {
64   // Hides the Layout Builder field. It is rendered directly in
65   // \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::buildMultiple().
66   unset($form['fields'][OverridesSectionStorage::FIELD_NAME]);
67   $key = array_search(OverridesSectionStorage::FIELD_NAME, $form['#fields']);
68   if ($key !== FALSE) {
69     unset($form['#fields'][$key]);
70   }
71 }
72
73 /**
74  * Implements hook_field_config_insert().
75  */
76 function layout_builder_field_config_insert(FieldConfigInterface $field_config) {
77   // Clear the sample entity for this entity type and bundle.
78   $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
79   $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
80   \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
81 }
82
83 /**
84  * Implements hook_field_config_delete().
85  */
86 function layout_builder_field_config_delete(FieldConfigInterface $field_config) {
87   // Clear the sample entity for this entity type and bundle.
88   $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
89   $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
90   \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
91 }
92
93 /**
94  * Implements hook_entity_view_alter().
95  *
96  * ExtraFieldBlock block plugins add placeholders for each extra field which is
97  * configured to be displayed. Those placeholders are replaced by this hook.
98  * Modules that implement hook_entity_extra_field_info() use their
99  * implementations of hook_entity_view_alter() to add the rendered output of
100  * the extra fields they provide, so we cannot get the rendered output of extra
101  * fields before this point in the view process.
102  * layout_builder_module_implements_alter() moves this implementation of
103  * hook_entity_view_alter() to the end of the list.
104  *
105  * @see \Drupal\layout_builder\Plugin\Block\ExtraFieldBlock::build()
106  * @see layout_builder_module_implements_alter()
107  */
108 function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
109   if ($display instanceof LayoutEntityDisplayInterface) {
110     /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
111     $field_manager = \Drupal::service('entity_field.manager');
112     $extra_fields = $field_manager->getExtraFields($entity->getEntityTypeId(), $entity->bundle());
113     if (!empty($extra_fields['display'])) {
114       foreach ($extra_fields['display'] as $field_name => $extra_field) {
115         // If the extra field is not set replace with an empty array to avoid
116         // the placeholder text from being rendered.
117         $replacement = isset($build[$field_name]) ? $build[$field_name] : [];
118         ExtraFieldBlock::replaceFieldPlaceholder($build, $replacement, $field_name);
119         // After the rendered field in $build has been copied over to the
120         // ExtraFieldBlock block we must remove it from its original location or
121         // else it will be rendered twice.
122         unset($build[$field_name]);
123       }
124     }
125   }
126 }
127
128 /**
129  * Implements hook_builder_module_implements_alter().
130  */
131 function layout_builder_module_implements_alter(&$implementations, $hook) {
132   if ($hook === 'entity_view_alter') {
133     // Ensure that this module's implementation of hook_entity_view_alter() runs
134     // last so that other modules that use this hook to render extra fields will
135     // run before it.
136     $group = $implementations['layout_builder'];
137     unset($implementations['layout_builder']);
138     $implementations['layout_builder'] = $group;
139   }
140 }
141
142 /**
143  * Implements hook_entity_presave().
144  */
145 function layout_builder_entity_presave(EntityInterface $entity) {
146   if (\Drupal::moduleHandler()->moduleExists('block_content')) {
147     /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
148     $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
149     $entity_operations->handlePreSave($entity);
150   }
151 }
152
153 /**
154  * Implements hook_entity_delete().
155  */
156 function layout_builder_entity_delete(EntityInterface $entity) {
157   if (\Drupal::moduleHandler()->moduleExists('block_content')) {
158     /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
159     $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
160     $entity_operations->handleEntityDelete($entity);
161   }
162 }
163
164 /**
165  * Implements hook_cron().
166  */
167 function layout_builder_cron() {
168   if (\Drupal::moduleHandler()->moduleExists('block_content')) {
169     /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
170     $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
171     $entity_operations->removeUnused();
172   }
173 }
174
175 /**
176  * Implements hook_plugin_filter_TYPE_alter().
177  */
178 function layout_builder_plugin_filter_block_alter(array &$definitions, array $extra, $consumer) {
179   // @todo Determine the 'inline_block' blocks should be allowed outside
180   //   of layout_builder https://www.drupal.org/node/2979142.
181   if ($consumer !== 'layout_builder' || !isset($extra['list']) || $extra['list'] !== 'inline_blocks') {
182     foreach ($definitions as $id => $definition) {
183       if ($definition['id'] === 'inline_block') {
184         unset($definitions[$id]);
185       }
186     }
187   }
188 }
189
190 /**
191  * Implements hook_ENTITY_TYPE_access().
192  */
193 function layout_builder_block_content_access(EntityInterface $entity, $operation, AccountInterface $account) {
194   /** @var \Drupal\block_content\BlockContentInterface $entity */
195   if ($operation === 'view' || $entity->isReusable() || empty(\Drupal::service('inline_block.usage')->getUsage($entity->id()))) {
196     // If the operation is 'view' or this is reusable block or if this is
197     // non-reusable that isn't used by this module then don't alter the access.
198     return AccessResult::neutral();
199   }
200
201   if ($account->hasPermission('configure any layout')) {
202     return AccessResult::allowed();
203   }
204   return AccessResult::forbidden();
205 }
206
207 /**
208  * Implements hook_plugin_filter_TYPE__CONSUMER_alter().
209  */
210 function layout_builder_plugin_filter_block__block_ui_alter(array &$definitions, array $extra) {
211   foreach ($definitions as $id => $definition) {
212     // Filter out any layout_builder definition with required contexts.
213     if ($definition['provider'] === 'layout_builder' && !empty($definition['context'])) {
214       /** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
215       foreach ($definition['context'] as $context) {
216         if ($context->isRequired()) {
217           unset($definitions[$id]);
218           break;
219         }
220       }
221     }
222   }
223 }