Mercurial > hg > isophonics-drupal-site
comparison core/modules/layout_builder/src/Controller/LayoutBuilderController.php @ 18:af1871eacc83
Update to Drupal core 8.7.1
author | Chris Cannam |
---|---|
date | Thu, 09 May 2019 15:33:08 +0100 |
parents | 129ea1e6d783 |
children |
comparison
equal
deleted
inserted
replaced
17:129ea1e6d783 | 18:af1871eacc83 |
---|---|
1 <?php | 1 <?php |
2 | 2 |
3 namespace Drupal\layout_builder\Controller; | 3 namespace Drupal\layout_builder\Controller; |
4 | 4 |
5 use Drupal\Core\Ajax\AjaxHelperTrait; | |
6 use Drupal\Core\DependencyInjection\ContainerInjectionInterface; | |
7 use Drupal\Core\Messenger\MessengerInterface; | |
8 use Drupal\Core\Plugin\PluginFormInterface; | |
9 use Drupal\Core\StringTranslation\StringTranslationTrait; | 5 use Drupal\Core\StringTranslation\StringTranslationTrait; |
10 use Drupal\Core\Url; | |
11 use Drupal\layout_builder\Context\LayoutBuilderContextTrait; | |
12 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface; | |
13 use Drupal\layout_builder\OverridesSectionStorageInterface; | |
14 use Drupal\layout_builder\Section; | |
15 use Drupal\layout_builder\SectionStorageInterface; | 6 use Drupal\layout_builder\SectionStorageInterface; |
16 use Symfony\Component\DependencyInjection\ContainerInterface; | |
17 use Symfony\Component\HttpFoundation\RedirectResponse; | |
18 | 7 |
19 /** | 8 /** |
20 * Defines a controller to provide the Layout Builder admin UI. | 9 * Defines a controller to provide the Layout Builder admin UI. |
21 * | 10 * |
22 * @internal | 11 * @internal |
12 * Controller classes are internal. | |
23 */ | 13 */ |
24 class LayoutBuilderController implements ContainerInjectionInterface { | 14 class LayoutBuilderController { |
25 | 15 |
26 use LayoutBuilderContextTrait; | |
27 use StringTranslationTrait; | 16 use StringTranslationTrait; |
28 use AjaxHelperTrait; | |
29 | |
30 /** | |
31 * The layout tempstore repository. | |
32 * | |
33 * @var \Drupal\layout_builder\LayoutTempstoreRepositoryInterface | |
34 */ | |
35 protected $layoutTempstoreRepository; | |
36 | |
37 /** | |
38 * The messenger service. | |
39 * | |
40 * @var \Drupal\Core\Messenger\MessengerInterface | |
41 */ | |
42 protected $messenger; | |
43 | |
44 /** | |
45 * LayoutBuilderController constructor. | |
46 * | |
47 * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository | |
48 * The layout tempstore repository. | |
49 * @param \Drupal\Core\Messenger\MessengerInterface $messenger | |
50 * The messenger service. | |
51 */ | |
52 public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, MessengerInterface $messenger) { | |
53 $this->layoutTempstoreRepository = $layout_tempstore_repository; | |
54 $this->messenger = $messenger; | |
55 } | |
56 | |
57 /** | |
58 * {@inheritdoc} | |
59 */ | |
60 public static function create(ContainerInterface $container) { | |
61 return new static( | |
62 $container->get('layout_builder.tempstore_repository'), | |
63 $container->get('messenger') | |
64 ); | |
65 } | |
66 | 17 |
67 /** | 18 /** |
68 * Provides a title callback. | 19 * Provides a title callback. |
69 * | 20 * |
70 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | 21 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage |
80 /** | 31 /** |
81 * Renders the Layout UI. | 32 * Renders the Layout UI. |
82 * | 33 * |
83 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | 34 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage |
84 * The section storage. | 35 * The section storage. |
85 * @param bool $is_rebuilding | |
86 * (optional) Indicates if the layout is rebuilding, defaults to FALSE. | |
87 * | 36 * |
88 * @return array | 37 * @return array |
89 * A render array. | 38 * A render array. |
90 */ | 39 */ |
91 public function layout(SectionStorageInterface $section_storage, $is_rebuilding = FALSE) { | 40 public function layout(SectionStorageInterface $section_storage) { |
92 $this->prepareLayout($section_storage, $is_rebuilding); | |
93 | |
94 $output = []; | |
95 if ($this->isAjax()) { | |
96 $output['status_messages'] = [ | |
97 '#type' => 'status_messages', | |
98 ]; | |
99 } | |
100 $count = 0; | |
101 for ($i = 0; $i < $section_storage->count(); $i++) { | |
102 $output[] = $this->buildAddSectionLink($section_storage, $count); | |
103 $output[] = $this->buildAdministrativeSection($section_storage, $count); | |
104 $count++; | |
105 } | |
106 $output[] = $this->buildAddSectionLink($section_storage, $count); | |
107 $output['#attached']['library'][] = 'layout_builder/drupal.layout_builder'; | |
108 $output['#type'] = 'container'; | |
109 $output['#attributes']['id'] = 'layout-builder'; | |
110 // Mark this UI as uncacheable. | |
111 $output['#cache']['max-age'] = 0; | |
112 return $output; | |
113 } | |
114 | |
115 /** | |
116 * Prepares a layout for use in the UI. | |
117 * | |
118 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | |
119 * The section storage. | |
120 * @param bool $is_rebuilding | |
121 * Indicates if the layout is rebuilding. | |
122 */ | |
123 protected function prepareLayout(SectionStorageInterface $section_storage, $is_rebuilding) { | |
124 // If the layout has pending changes, add a warning. | |
125 if ($this->layoutTempstoreRepository->has($section_storage)) { | |
126 $this->messenger->addWarning($this->t('You have unsaved changes.')); | |
127 } | |
128 | |
129 // Only add sections if the layout is new and empty. | |
130 if (!$is_rebuilding && $section_storage->count() === 0) { | |
131 $sections = []; | |
132 // If this is an empty override, copy the sections from the corresponding | |
133 // default. | |
134 if ($section_storage instanceof OverridesSectionStorageInterface) { | |
135 $sections = $section_storage->getDefaultSectionStorage()->getSections(); | |
136 } | |
137 | |
138 // For an empty layout, begin with a single section of one column. | |
139 if (!$sections) { | |
140 $sections[] = new Section('layout_onecol'); | |
141 } | |
142 | |
143 foreach ($sections as $section) { | |
144 $section_storage->appendSection($section); | |
145 } | |
146 $this->layoutTempstoreRepository->set($section_storage); | |
147 } | |
148 } | |
149 | |
150 /** | |
151 * Builds a link to add a new section at a given delta. | |
152 * | |
153 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | |
154 * The section storage. | |
155 * @param int $delta | |
156 * The delta of the section to splice. | |
157 * | |
158 * @return array | |
159 * A render array for a link. | |
160 */ | |
161 protected function buildAddSectionLink(SectionStorageInterface $section_storage, $delta) { | |
162 $storage_type = $section_storage->getStorageType(); | |
163 $storage_id = $section_storage->getStorageId(); | |
164 return [ | 41 return [ |
165 'link' => [ | 42 '#type' => 'layout_builder', |
166 '#type' => 'link', | 43 '#section_storage' => $section_storage, |
167 '#title' => $this->t('Add Section'), | |
168 '#url' => Url::fromRoute('layout_builder.choose_section', | |
169 [ | |
170 'section_storage_type' => $storage_type, | |
171 'section_storage' => $storage_id, | |
172 'delta' => $delta, | |
173 ], | |
174 [ | |
175 'attributes' => [ | |
176 'class' => ['use-ajax', 'new-section__link'], | |
177 'data-dialog-type' => 'dialog', | |
178 'data-dialog-renderer' => 'off_canvas', | |
179 ], | |
180 ] | |
181 ), | |
182 ], | |
183 '#type' => 'container', | |
184 '#attributes' => [ | |
185 'class' => ['new-section'], | |
186 ], | |
187 ]; | 44 ]; |
188 } | 45 } |
189 | 46 |
190 /** | |
191 * Builds the render array for the layout section while editing. | |
192 * | |
193 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | |
194 * The section storage. | |
195 * @param int $delta | |
196 * The delta of the section. | |
197 * | |
198 * @return array | |
199 * The render array for a given section. | |
200 */ | |
201 protected function buildAdministrativeSection(SectionStorageInterface $section_storage, $delta) { | |
202 $storage_type = $section_storage->getStorageType(); | |
203 $storage_id = $section_storage->getStorageId(); | |
204 $section = $section_storage->getSection($delta); | |
205 | |
206 $layout = $section->getLayout(); | |
207 $build = $section->toRenderArray($this->getAvailableContexts($section_storage), TRUE); | |
208 $layout_definition = $layout->getPluginDefinition(); | |
209 | |
210 foreach ($layout_definition->getRegions() as $region => $info) { | |
211 if (!empty($build[$region])) { | |
212 foreach ($build[$region] as $uuid => $block) { | |
213 $build[$region][$uuid]['#attributes']['class'][] = 'draggable'; | |
214 $build[$region][$uuid]['#attributes']['data-layout-block-uuid'] = $uuid; | |
215 $build[$region][$uuid]['#contextual_links'] = [ | |
216 'layout_builder_block' => [ | |
217 'route_parameters' => [ | |
218 'section_storage_type' => $storage_type, | |
219 'section_storage' => $storage_id, | |
220 'delta' => $delta, | |
221 'region' => $region, | |
222 'uuid' => $uuid, | |
223 ], | |
224 ], | |
225 ]; | |
226 } | |
227 } | |
228 | |
229 $build[$region]['layout_builder_add_block']['link'] = [ | |
230 '#type' => 'link', | |
231 '#title' => $this->t('Add Block'), | |
232 '#url' => Url::fromRoute('layout_builder.choose_block', | |
233 [ | |
234 'section_storage_type' => $storage_type, | |
235 'section_storage' => $storage_id, | |
236 'delta' => $delta, | |
237 'region' => $region, | |
238 ], | |
239 [ | |
240 'attributes' => [ | |
241 'class' => ['use-ajax', 'new-block__link'], | |
242 'data-dialog-type' => 'dialog', | |
243 'data-dialog-renderer' => 'off_canvas', | |
244 ], | |
245 ] | |
246 ), | |
247 ]; | |
248 $build[$region]['layout_builder_add_block']['#type'] = 'container'; | |
249 $build[$region]['layout_builder_add_block']['#attributes'] = ['class' => ['new-block']]; | |
250 $build[$region]['layout_builder_add_block']['#weight'] = 1000; | |
251 $build[$region]['#attributes']['data-region'] = $region; | |
252 $build[$region]['#attributes']['class'][] = 'layout-builder--layout__region'; | |
253 } | |
254 | |
255 $build['#attributes']['data-layout-update-url'] = Url::fromRoute('layout_builder.move_block', [ | |
256 'section_storage_type' => $storage_type, | |
257 'section_storage' => $storage_id, | |
258 ])->toString(); | |
259 $build['#attributes']['data-layout-delta'] = $delta; | |
260 $build['#attributes']['class'][] = 'layout-builder--layout'; | |
261 | |
262 return [ | |
263 '#type' => 'container', | |
264 '#attributes' => [ | |
265 'class' => ['layout-section'], | |
266 ], | |
267 'configure' => [ | |
268 '#type' => 'link', | |
269 '#title' => $this->t('Configure section'), | |
270 '#access' => $layout instanceof PluginFormInterface, | |
271 '#url' => Url::fromRoute('layout_builder.configure_section', [ | |
272 'section_storage_type' => $storage_type, | |
273 'section_storage' => $storage_id, | |
274 'delta' => $delta, | |
275 ]), | |
276 '#attributes' => [ | |
277 'class' => ['use-ajax', 'configure-section'], | |
278 'data-dialog-type' => 'dialog', | |
279 'data-dialog-renderer' => 'off_canvas', | |
280 ], | |
281 ], | |
282 'remove' => [ | |
283 '#type' => 'link', | |
284 '#title' => $this->t('Remove section <span class="visually-hidden">@section</span>', ['@section' => $delta + 1]), | |
285 '#url' => Url::fromRoute('layout_builder.remove_section', [ | |
286 'section_storage_type' => $storage_type, | |
287 'section_storage' => $storage_id, | |
288 'delta' => $delta, | |
289 ]), | |
290 '#attributes' => [ | |
291 'class' => ['use-ajax', 'remove-section'], | |
292 'data-dialog-type' => 'dialog', | |
293 'data-dialog-renderer' => 'off_canvas', | |
294 ], | |
295 ], | |
296 'layout-section' => $build, | |
297 ]; | |
298 } | |
299 | |
300 /** | |
301 * Saves the layout. | |
302 * | |
303 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | |
304 * The section storage. | |
305 * | |
306 * @return \Symfony\Component\HttpFoundation\RedirectResponse | |
307 * A redirect response. | |
308 */ | |
309 public function saveLayout(SectionStorageInterface $section_storage) { | |
310 $section_storage->save(); | |
311 $this->layoutTempstoreRepository->delete($section_storage); | |
312 | |
313 if ($section_storage instanceof OverridesSectionStorageInterface) { | |
314 $this->messenger->addMessage($this->t('The layout override has been saved.')); | |
315 } | |
316 else { | |
317 $this->messenger->addMessage($this->t('The layout has been saved.')); | |
318 } | |
319 | |
320 return new RedirectResponse($section_storage->getRedirectUrl()->setAbsolute()->toString()); | |
321 } | |
322 | |
323 /** | |
324 * Cancels the layout. | |
325 * | |
326 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage | |
327 * The section storage. | |
328 * | |
329 * @return \Symfony\Component\HttpFoundation\RedirectResponse | |
330 * A redirect response. | |
331 */ | |
332 public function cancelLayout(SectionStorageInterface $section_storage) { | |
333 $this->layoutTempstoreRepository->delete($section_storage); | |
334 | |
335 $this->messenger->addMessage($this->t('The changes to the layout have been discarded.')); | |
336 | |
337 return new RedirectResponse($section_storage->getRedirectUrl()->setAbsolute()->toString()); | |
338 } | |
339 | |
340 } | 47 } |