Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\menu_ui;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Utility\NestedArray;
|
Chris@0
|
6 use Drupal\Core\Cache\CacheableMetadata;
|
Chris@0
|
7 use Drupal\Core\Entity\EntityForm;
|
Chris@0
|
8 use Drupal\Core\Form\FormStateInterface;
|
Chris@0
|
9 use Drupal\Core\Language\LanguageInterface;
|
Chris@0
|
10 use Drupal\Core\Link;
|
Chris@0
|
11 use Drupal\Core\Menu\MenuLinkManagerInterface;
|
Chris@0
|
12 use Drupal\Core\Menu\MenuLinkTreeElement;
|
Chris@0
|
13 use Drupal\Core\Menu\MenuLinkTreeInterface;
|
Chris@0
|
14 use Drupal\Core\Menu\MenuTreeParameters;
|
Chris@0
|
15 use Drupal\Core\Render\Element;
|
Chris@0
|
16 use Drupal\Core\Url;
|
Chris@0
|
17 use Drupal\Core\Utility\LinkGeneratorInterface;
|
Chris@18
|
18 use Drupal\menu_link_content\MenuLinkContentStorageInterface;
|
Chris@18
|
19 use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;
|
Chris@0
|
20 use Symfony\Component\DependencyInjection\ContainerInterface;
|
Chris@0
|
21
|
Chris@0
|
22 /**
|
Chris@0
|
23 * Base form for menu edit forms.
|
Chris@14
|
24 *
|
Chris@14
|
25 * @internal
|
Chris@0
|
26 */
|
Chris@0
|
27 class MenuForm extends EntityForm {
|
Chris@0
|
28
|
Chris@0
|
29 /**
|
Chris@0
|
30 * The menu link manager.
|
Chris@0
|
31 *
|
Chris@0
|
32 * @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
Chris@0
|
33 */
|
Chris@0
|
34 protected $menuLinkManager;
|
Chris@0
|
35
|
Chris@0
|
36 /**
|
Chris@0
|
37 * The menu tree service.
|
Chris@0
|
38 *
|
Chris@0
|
39 * @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
Chris@0
|
40 */
|
Chris@0
|
41 protected $menuTree;
|
Chris@0
|
42
|
Chris@0
|
43 /**
|
Chris@0
|
44 * The link generator.
|
Chris@0
|
45 *
|
Chris@0
|
46 * @var \Drupal\Core\Utility\LinkGeneratorInterface
|
Chris@0
|
47 */
|
Chris@0
|
48 protected $linkGenerator;
|
Chris@0
|
49
|
Chris@0
|
50 /**
|
Chris@18
|
51 * The menu_link_content storage handler.
|
Chris@18
|
52 *
|
Chris@18
|
53 * @var \Drupal\menu_link_content\MenuLinkContentStorageInterface
|
Chris@18
|
54 */
|
Chris@18
|
55 protected $menuLinkContentStorage;
|
Chris@18
|
56
|
Chris@18
|
57 /**
|
Chris@0
|
58 * The overview tree form.
|
Chris@0
|
59 *
|
Chris@0
|
60 * @var array
|
Chris@0
|
61 */
|
Chris@0
|
62 protected $overviewTreeForm = ['#tree' => TRUE];
|
Chris@0
|
63
|
Chris@0
|
64 /**
|
Chris@0
|
65 * Constructs a MenuForm object.
|
Chris@0
|
66 *
|
Chris@0
|
67 * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
Chris@0
|
68 * The menu link manager.
|
Chris@0
|
69 * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
|
Chris@0
|
70 * The menu tree service.
|
Chris@0
|
71 * @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
|
Chris@0
|
72 * The link generator.
|
Chris@18
|
73 * @param \Drupal\menu_link_content\MenuLinkContentStorageInterface $menu_link_content_storage
|
Chris@18
|
74 * The menu link content storage handler.
|
Chris@0
|
75 */
|
Chris@18
|
76 public function __construct(MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator, MenuLinkContentStorageInterface $menu_link_content_storage) {
|
Chris@0
|
77 $this->menuLinkManager = $menu_link_manager;
|
Chris@0
|
78 $this->menuTree = $menu_tree;
|
Chris@0
|
79 $this->linkGenerator = $link_generator;
|
Chris@18
|
80 $this->menuLinkContentStorage = $menu_link_content_storage;
|
Chris@0
|
81 }
|
Chris@0
|
82
|
Chris@0
|
83 /**
|
Chris@0
|
84 * {@inheritdoc}
|
Chris@0
|
85 */
|
Chris@0
|
86 public static function create(ContainerInterface $container) {
|
Chris@0
|
87 return new static(
|
Chris@0
|
88 $container->get('plugin.manager.menu.link'),
|
Chris@0
|
89 $container->get('menu.link_tree'),
|
Chris@18
|
90 $container->get('link_generator'),
|
Chris@18
|
91 $container->get('entity_type.manager')->getStorage('menu_link_content')
|
Chris@0
|
92 );
|
Chris@0
|
93 }
|
Chris@0
|
94
|
Chris@0
|
95 /**
|
Chris@0
|
96 * {@inheritdoc}
|
Chris@0
|
97 */
|
Chris@0
|
98 public function form(array $form, FormStateInterface $form_state) {
|
Chris@0
|
99 $menu = $this->entity;
|
Chris@0
|
100
|
Chris@0
|
101 if ($this->operation == 'edit') {
|
Chris@0
|
102 $form['#title'] = $this->t('Edit menu %label', ['%label' => $menu->label()]);
|
Chris@0
|
103 }
|
Chris@0
|
104
|
Chris@0
|
105 $form['label'] = [
|
Chris@0
|
106 '#type' => 'textfield',
|
Chris@0
|
107 '#title' => $this->t('Title'),
|
Chris@0
|
108 '#default_value' => $menu->label(),
|
Chris@0
|
109 '#required' => TRUE,
|
Chris@0
|
110 ];
|
Chris@0
|
111 $form['id'] = [
|
Chris@0
|
112 '#type' => 'machine_name',
|
Chris@0
|
113 '#title' => $this->t('Menu name'),
|
Chris@0
|
114 '#default_value' => $menu->id(),
|
Chris@0
|
115 '#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI,
|
Chris@0
|
116 '#description' => $this->t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'),
|
Chris@0
|
117 '#machine_name' => [
|
Chris@0
|
118 'exists' => [$this, 'menuNameExists'],
|
Chris@0
|
119 'source' => ['label'],
|
Chris@0
|
120 'replace_pattern' => '[^a-z0-9-]+',
|
Chris@0
|
121 'replace' => '-',
|
Chris@0
|
122 ],
|
Chris@0
|
123 // A menu's machine name cannot be changed.
|
Chris@0
|
124 '#disabled' => !$menu->isNew() || $menu->isLocked(),
|
Chris@0
|
125 ];
|
Chris@0
|
126 $form['description'] = [
|
Chris@0
|
127 '#type' => 'textfield',
|
Chris@0
|
128 '#title' => t('Administrative summary'),
|
Chris@0
|
129 '#maxlength' => 512,
|
Chris@0
|
130 '#default_value' => $menu->getDescription(),
|
Chris@0
|
131 ];
|
Chris@0
|
132
|
Chris@0
|
133 $form['langcode'] = [
|
Chris@0
|
134 '#type' => 'language_select',
|
Chris@0
|
135 '#title' => t('Menu language'),
|
Chris@0
|
136 '#languages' => LanguageInterface::STATE_ALL,
|
Chris@0
|
137 '#default_value' => $menu->language()->getId(),
|
Chris@0
|
138 ];
|
Chris@0
|
139
|
Chris@0
|
140 // Add menu links administration form for existing menus.
|
Chris@0
|
141 if (!$menu->isNew() || $menu->isLocked()) {
|
Chris@0
|
142 // Form API supports constructing and validating self-contained sections
|
Chris@0
|
143 // within forms, but does not allow handling the form section's submission
|
Chris@0
|
144 // equally separated yet. Therefore, we use a $form_state key to point to
|
Chris@0
|
145 // the parents of the form section.
|
Chris@0
|
146 // @see self::submitOverviewForm()
|
Chris@0
|
147 $form_state->set('menu_overview_form_parents', ['links']);
|
Chris@0
|
148 $form['links'] = [];
|
Chris@0
|
149 $form['links'] = $this->buildOverviewForm($form['links'], $form_state);
|
Chris@0
|
150 }
|
Chris@0
|
151
|
Chris@0
|
152 return parent::form($form, $form_state);
|
Chris@0
|
153 }
|
Chris@0
|
154
|
Chris@0
|
155 /**
|
Chris@0
|
156 * Returns whether a menu name already exists.
|
Chris@0
|
157 *
|
Chris@0
|
158 * @param string $value
|
Chris@0
|
159 * The name of the menu.
|
Chris@0
|
160 *
|
Chris@0
|
161 * @return bool
|
Chris@0
|
162 * Returns TRUE if the menu already exists, FALSE otherwise.
|
Chris@0
|
163 */
|
Chris@0
|
164 public function menuNameExists($value) {
|
Chris@0
|
165 // Check first to see if a menu with this ID exists.
|
Chris@0
|
166 if ($this->entityTypeManager->getStorage('menu')->getQuery()->condition('id', $value)->range(0, 1)->count()->execute()) {
|
Chris@0
|
167 return TRUE;
|
Chris@0
|
168 }
|
Chris@0
|
169
|
Chris@0
|
170 // Check for a link assigned to this menu.
|
Chris@0
|
171 return $this->menuLinkManager->menuNameInUse($value);
|
Chris@0
|
172 }
|
Chris@0
|
173
|
Chris@0
|
174 /**
|
Chris@0
|
175 * {@inheritdoc}
|
Chris@0
|
176 */
|
Chris@0
|
177 public function save(array $form, FormStateInterface $form_state) {
|
Chris@0
|
178 $menu = $this->entity;
|
Chris@0
|
179 $status = $menu->save();
|
Chris@18
|
180 $edit_link = $this->entity->toLink($this->t('Edit'), 'edit-form')->toString();
|
Chris@0
|
181 if ($status == SAVED_UPDATED) {
|
Chris@17
|
182 $this->messenger()->addStatus($this->t('Menu %label has been updated.', ['%label' => $menu->label()]));
|
Chris@0
|
183 $this->logger('menu')->notice('Menu %label has been updated.', ['%label' => $menu->label(), 'link' => $edit_link]);
|
Chris@0
|
184 }
|
Chris@0
|
185 else {
|
Chris@17
|
186 $this->messenger()->addStatus($this->t('Menu %label has been added.', ['%label' => $menu->label()]));
|
Chris@0
|
187 $this->logger('menu')->notice('Menu %label has been added.', ['%label' => $menu->label(), 'link' => $edit_link]);
|
Chris@0
|
188 }
|
Chris@0
|
189
|
Chris@18
|
190 $form_state->setRedirectUrl($this->entity->toUrl('edit-form'));
|
Chris@0
|
191 }
|
Chris@0
|
192
|
Chris@0
|
193 /**
|
Chris@0
|
194 * {@inheritdoc}
|
Chris@0
|
195 */
|
Chris@0
|
196 public function submitForm(array &$form, FormStateInterface $form_state) {
|
Chris@0
|
197 parent::submitForm($form, $form_state);
|
Chris@0
|
198
|
Chris@0
|
199 if (!$this->entity->isNew() || $this->entity->isLocked()) {
|
Chris@0
|
200 $this->submitOverviewForm($form, $form_state);
|
Chris@0
|
201 }
|
Chris@0
|
202 }
|
Chris@0
|
203
|
Chris@0
|
204 /**
|
Chris@0
|
205 * Form constructor to edit an entire menu tree at once.
|
Chris@0
|
206 *
|
Chris@0
|
207 * Shows for one menu the menu links accessible to the current user and
|
Chris@0
|
208 * relevant operations.
|
Chris@0
|
209 *
|
Chris@0
|
210 * This form constructor can be integrated as a section into another form. It
|
Chris@0
|
211 * relies on the following keys in $form_state:
|
Chris@0
|
212 * - menu: A menu entity.
|
Chris@0
|
213 * - menu_overview_form_parents: An array containing the parent keys to this
|
Chris@0
|
214 * form.
|
Chris@0
|
215 * Forms integrating this section should call menu_overview_form_submit() from
|
Chris@0
|
216 * their form submit handler.
|
Chris@0
|
217 */
|
Chris@0
|
218 protected function buildOverviewForm(array &$form, FormStateInterface $form_state) {
|
Chris@0
|
219 // Ensure that menu_overview_form_submit() knows the parents of this form
|
Chris@0
|
220 // section.
|
Chris@0
|
221 if (!$form_state->has('menu_overview_form_parents')) {
|
Chris@0
|
222 $form_state->set('menu_overview_form_parents', []);
|
Chris@0
|
223 }
|
Chris@0
|
224
|
Chris@0
|
225 $form['#attached']['library'][] = 'menu_ui/drupal.menu_ui.adminforms';
|
Chris@0
|
226
|
Chris@0
|
227 $tree = $this->menuTree->load($this->entity->id(), new MenuTreeParameters());
|
Chris@0
|
228
|
Chris@0
|
229 // We indicate that a menu administrator is running the menu access check.
|
Chris@0
|
230 $this->getRequest()->attributes->set('_menu_admin', TRUE);
|
Chris@0
|
231 $manipulators = [
|
Chris@0
|
232 ['callable' => 'menu.default_tree_manipulators:checkAccess'],
|
Chris@0
|
233 ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
|
Chris@0
|
234 ];
|
Chris@0
|
235 $tree = $this->menuTree->transform($tree, $manipulators);
|
Chris@0
|
236 $this->getRequest()->attributes->set('_menu_admin', FALSE);
|
Chris@0
|
237
|
Chris@0
|
238 // Determine the delta; the number of weights to be made available.
|
Chris@0
|
239 $count = function (array $tree) {
|
Chris@0
|
240 $sum = function ($carry, MenuLinkTreeElement $item) {
|
Chris@0
|
241 return $carry + $item->count();
|
Chris@0
|
242 };
|
Chris@0
|
243 return array_reduce($tree, $sum);
|
Chris@0
|
244 };
|
Chris@0
|
245 $delta = max($count($tree), 50);
|
Chris@0
|
246
|
Chris@0
|
247 $form['links'] = [
|
Chris@0
|
248 '#type' => 'table',
|
Chris@0
|
249 '#theme' => 'table__menu_overview',
|
Chris@0
|
250 '#header' => [
|
Chris@0
|
251 $this->t('Menu link'),
|
Chris@0
|
252 [
|
Chris@0
|
253 'data' => $this->t('Enabled'),
|
Chris@0
|
254 'class' => ['checkbox'],
|
Chris@0
|
255 ],
|
Chris@0
|
256 $this->t('Weight'),
|
Chris@0
|
257 [
|
Chris@0
|
258 'data' => $this->t('Operations'),
|
Chris@0
|
259 'colspan' => 3,
|
Chris@0
|
260 ],
|
Chris@0
|
261 ],
|
Chris@0
|
262 '#attributes' => [
|
Chris@0
|
263 'id' => 'menu-overview',
|
Chris@0
|
264 ],
|
Chris@0
|
265 '#tabledrag' => [
|
Chris@0
|
266 [
|
Chris@0
|
267 'action' => 'match',
|
Chris@0
|
268 'relationship' => 'parent',
|
Chris@0
|
269 'group' => 'menu-parent',
|
Chris@0
|
270 'subgroup' => 'menu-parent',
|
Chris@0
|
271 'source' => 'menu-id',
|
Chris@0
|
272 'hidden' => TRUE,
|
Chris@0
|
273 'limit' => \Drupal::menuTree()->maxDepth() - 1,
|
Chris@0
|
274 ],
|
Chris@0
|
275 [
|
Chris@0
|
276 'action' => 'order',
|
Chris@0
|
277 'relationship' => 'sibling',
|
Chris@0
|
278 'group' => 'menu-weight',
|
Chris@0
|
279 ],
|
Chris@0
|
280 ],
|
Chris@0
|
281 ];
|
Chris@0
|
282
|
Chris@0
|
283 $form['links']['#empty'] = $this->t('There are no menu links yet. <a href=":url">Add link</a>.', [
|
Chris@0
|
284 ':url' => $this->url('entity.menu.add_link_form', ['menu' => $this->entity->id()], [
|
Chris@18
|
285 'query' => ['destination' => $this->entity->toUrl('edit-form')->toString()],
|
Chris@0
|
286 ]),
|
Chris@0
|
287 ]);
|
Chris@0
|
288 $links = $this->buildOverviewTreeForm($tree, $delta);
|
Chris@18
|
289
|
Chris@18
|
290 // Get the menu links which have pending revisions, and disable the
|
Chris@18
|
291 // tabledrag if there are any.
|
Chris@18
|
292 $edited_ids = array_filter(array_map(function ($element) {
|
Chris@18
|
293 return is_array($element) && isset($element['#item']) && $element['#item']->link instanceof MenuLinkContent ? $element['#item']->link->getMetaData()['entity_id'] : NULL;
|
Chris@18
|
294 }, $links));
|
Chris@18
|
295 $pending_menu_link_ids = array_intersect($this->menuLinkContentStorage->getMenuLinkIdsWithPendingRevisions(), $edited_ids);
|
Chris@18
|
296 if ($pending_menu_link_ids) {
|
Chris@18
|
297 $form['help'] = [
|
Chris@18
|
298 '#type' => 'container',
|
Chris@18
|
299 'message' => [
|
Chris@18
|
300 '#markup' => $this->formatPlural(
|
Chris@18
|
301 count($pending_menu_link_ids),
|
Chris@18
|
302 '%capital_name contains 1 menu link with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.',
|
Chris@18
|
303 '%capital_name contains @count menu links with pending revisions. Manipulation of a menu tree having links with pending revisions is not supported, but you can re-enable manipulation by getting each menu link to a published state.',
|
Chris@18
|
304 [
|
Chris@18
|
305 '%capital_name' => $this->entity->label(),
|
Chris@18
|
306 ]
|
Chris@18
|
307 ),
|
Chris@18
|
308 ],
|
Chris@18
|
309 '#attributes' => ['class' => ['messages', 'messages--warning']],
|
Chris@18
|
310 '#weight' => -10,
|
Chris@18
|
311 ];
|
Chris@18
|
312
|
Chris@18
|
313 unset($form['links']['#tabledrag']);
|
Chris@18
|
314 unset($form['links']['#header'][2]);
|
Chris@18
|
315 }
|
Chris@18
|
316
|
Chris@0
|
317 foreach (Element::children($links) as $id) {
|
Chris@0
|
318 if (isset($links[$id]['#item'])) {
|
Chris@0
|
319 $element = $links[$id];
|
Chris@0
|
320
|
Chris@18
|
321 $is_pending_menu_link = isset($element['#item']->link->getMetaData()['entity_id'])
|
Chris@18
|
322 && in_array($element['#item']->link->getMetaData()['entity_id'], $pending_menu_link_ids);
|
Chris@18
|
323
|
Chris@0
|
324 $form['links'][$id]['#item'] = $element['#item'];
|
Chris@0
|
325
|
Chris@0
|
326 // TableDrag: Mark the table row as draggable.
|
Chris@0
|
327 $form['links'][$id]['#attributes'] = $element['#attributes'];
|
Chris@0
|
328 $form['links'][$id]['#attributes']['class'][] = 'draggable';
|
Chris@0
|
329
|
Chris@18
|
330 if ($is_pending_menu_link) {
|
Chris@18
|
331 $form['links'][$id]['#attributes']['class'][] = 'color-warning';
|
Chris@18
|
332 $form['links'][$id]['#attributes']['class'][] = 'menu-link-content--pending-revision';
|
Chris@18
|
333 }
|
Chris@18
|
334
|
Chris@0
|
335 // TableDrag: Sort the table row according to its existing/configured weight.
|
Chris@0
|
336 $form['links'][$id]['#weight'] = $element['#item']->link->getWeight();
|
Chris@0
|
337
|
Chris@0
|
338 // Add special classes to be used for tabledrag.js.
|
Chris@0
|
339 $element['parent']['#attributes']['class'] = ['menu-parent'];
|
Chris@0
|
340 $element['weight']['#attributes']['class'] = ['menu-weight'];
|
Chris@0
|
341 $element['id']['#attributes']['class'] = ['menu-id'];
|
Chris@0
|
342
|
Chris@0
|
343 $form['links'][$id]['title'] = [
|
Chris@0
|
344 [
|
Chris@0
|
345 '#theme' => 'indentation',
|
Chris@0
|
346 '#size' => $element['#item']->depth - 1,
|
Chris@0
|
347 ],
|
Chris@0
|
348 $element['title'],
|
Chris@0
|
349 ];
|
Chris@0
|
350 $form['links'][$id]['enabled'] = $element['enabled'];
|
Chris@0
|
351 $form['links'][$id]['enabled']['#wrapper_attributes']['class'] = ['checkbox', 'menu-enabled'];
|
Chris@0
|
352
|
Chris@18
|
353 // Disallow changing the publishing status of a pending revision.
|
Chris@18
|
354 if ($is_pending_menu_link) {
|
Chris@18
|
355 $form['links'][$id]['enabled']['#access'] = FALSE;
|
Chris@18
|
356 }
|
Chris@18
|
357
|
Chris@18
|
358 if (!$pending_menu_link_ids) {
|
Chris@18
|
359 $form['links'][$id]['weight'] = $element['weight'];
|
Chris@18
|
360 }
|
Chris@0
|
361
|
Chris@0
|
362 // Operations (dropbutton) column.
|
Chris@0
|
363 $form['links'][$id]['operations'] = $element['operations'];
|
Chris@0
|
364
|
Chris@0
|
365 $form['links'][$id]['id'] = $element['id'];
|
Chris@0
|
366 $form['links'][$id]['parent'] = $element['parent'];
|
Chris@0
|
367 }
|
Chris@0
|
368 }
|
Chris@0
|
369
|
Chris@0
|
370 return $form;
|
Chris@0
|
371 }
|
Chris@0
|
372
|
Chris@0
|
373 /**
|
Chris@0
|
374 * Recursive helper function for buildOverviewForm().
|
Chris@0
|
375 *
|
Chris@0
|
376 * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
|
Chris@0
|
377 * The tree retrieved by \Drupal\Core\Menu\MenuLinkTreeInterface::load().
|
Chris@0
|
378 * @param int $delta
|
Chris@0
|
379 * The default number of menu items used in the menu weight selector is 50.
|
Chris@0
|
380 *
|
Chris@0
|
381 * @return array
|
Chris@0
|
382 * The overview tree form.
|
Chris@0
|
383 */
|
Chris@0
|
384 protected function buildOverviewTreeForm($tree, $delta) {
|
Chris@0
|
385 $form = &$this->overviewTreeForm;
|
Chris@0
|
386 $tree_access_cacheability = new CacheableMetadata();
|
Chris@0
|
387 foreach ($tree as $element) {
|
Chris@0
|
388 $tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($element->access));
|
Chris@0
|
389
|
Chris@0
|
390 // Only render accessible links.
|
Chris@0
|
391 if (!$element->access->isAllowed()) {
|
Chris@0
|
392 continue;
|
Chris@0
|
393 }
|
Chris@0
|
394
|
Chris@0
|
395 /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
Chris@0
|
396 $link = $element->link;
|
Chris@0
|
397 if ($link) {
|
Chris@0
|
398 $id = 'menu_plugin_id:' . $link->getPluginId();
|
Chris@0
|
399 $form[$id]['#item'] = $element;
|
Chris@0
|
400 $form[$id]['#attributes'] = $link->isEnabled() ? ['class' => ['menu-enabled']] : ['class' => ['menu-disabled']];
|
Chris@0
|
401 $form[$id]['title'] = Link::fromTextAndUrl($link->getTitle(), $link->getUrlObject())->toRenderable();
|
Chris@0
|
402 if (!$link->isEnabled()) {
|
Chris@0
|
403 $form[$id]['title']['#suffix'] = ' (' . $this->t('disabled') . ')';
|
Chris@0
|
404 }
|
Chris@0
|
405 // @todo Remove this in https://www.drupal.org/node/2568785.
|
Chris@0
|
406 elseif ($id === 'menu_plugin_id:user.logout') {
|
Chris@0
|
407 $form[$id]['title']['#suffix'] = ' (' . $this->t('<q>Log in</q> for anonymous users') . ')';
|
Chris@0
|
408 }
|
Chris@0
|
409 // @todo Remove this in https://www.drupal.org/node/2568785.
|
Chris@0
|
410 elseif (($url = $link->getUrlObject()) && $url->isRouted() && $url->getRouteName() == 'user.page') {
|
Chris@0
|
411 $form[$id]['title']['#suffix'] = ' (' . $this->t('logged in users only') . ')';
|
Chris@0
|
412 }
|
Chris@0
|
413
|
Chris@0
|
414 $form[$id]['enabled'] = [
|
Chris@0
|
415 '#type' => 'checkbox',
|
Chris@0
|
416 '#title' => $this->t('Enable @title menu link', ['@title' => $link->getTitle()]),
|
Chris@0
|
417 '#title_display' => 'invisible',
|
Chris@0
|
418 '#default_value' => $link->isEnabled(),
|
Chris@0
|
419 ];
|
Chris@0
|
420 $form[$id]['weight'] = [
|
Chris@0
|
421 '#type' => 'weight',
|
Chris@0
|
422 '#delta' => $delta,
|
Chris@0
|
423 '#default_value' => $link->getWeight(),
|
Chris@0
|
424 '#title' => $this->t('Weight for @title', ['@title' => $link->getTitle()]),
|
Chris@0
|
425 '#title_display' => 'invisible',
|
Chris@0
|
426 ];
|
Chris@0
|
427 $form[$id]['id'] = [
|
Chris@0
|
428 '#type' => 'hidden',
|
Chris@0
|
429 '#value' => $link->getPluginId(),
|
Chris@0
|
430 ];
|
Chris@0
|
431 $form[$id]['parent'] = [
|
Chris@0
|
432 '#type' => 'hidden',
|
Chris@0
|
433 '#default_value' => $link->getParent(),
|
Chris@0
|
434 ];
|
Chris@0
|
435 // Build a list of operations.
|
Chris@0
|
436 $operations = [];
|
Chris@0
|
437 $operations['edit'] = [
|
Chris@0
|
438 'title' => $this->t('Edit'),
|
Chris@0
|
439 ];
|
Chris@0
|
440 // Allow for a custom edit link per plugin.
|
Chris@0
|
441 $edit_route = $link->getEditRoute();
|
Chris@0
|
442 if ($edit_route) {
|
Chris@0
|
443 $operations['edit']['url'] = $edit_route;
|
Chris@0
|
444 // Bring the user back to the menu overview.
|
Chris@0
|
445 $operations['edit']['query'] = $this->getDestinationArray();
|
Chris@0
|
446 }
|
Chris@0
|
447 else {
|
Chris@0
|
448 // Fall back to the standard edit link.
|
Chris@0
|
449 $operations['edit'] += [
|
Chris@0
|
450 'url' => Url::fromRoute('menu_ui.link_edit', ['menu_link_plugin' => $link->getPluginId()]),
|
Chris@0
|
451 ];
|
Chris@0
|
452 }
|
Chris@0
|
453 // Links can either be reset or deleted, not both.
|
Chris@0
|
454 if ($link->isResettable()) {
|
Chris@0
|
455 $operations['reset'] = [
|
Chris@0
|
456 'title' => $this->t('Reset'),
|
Chris@0
|
457 'url' => Url::fromRoute('menu_ui.link_reset', ['menu_link_plugin' => $link->getPluginId()]),
|
Chris@0
|
458 ];
|
Chris@0
|
459 }
|
Chris@0
|
460 elseif ($delete_link = $link->getDeleteRoute()) {
|
Chris@0
|
461 $operations['delete']['url'] = $delete_link;
|
Chris@0
|
462 $operations['delete']['query'] = $this->getDestinationArray();
|
Chris@0
|
463 $operations['delete']['title'] = $this->t('Delete');
|
Chris@0
|
464 }
|
Chris@0
|
465 if ($link->isTranslatable()) {
|
Chris@0
|
466 $operations['translate'] = [
|
Chris@0
|
467 'title' => $this->t('Translate'),
|
Chris@0
|
468 'url' => $link->getTranslateRoute(),
|
Chris@0
|
469 ];
|
Chris@0
|
470 }
|
Chris@0
|
471 $form[$id]['operations'] = [
|
Chris@0
|
472 '#type' => 'operations',
|
Chris@0
|
473 '#links' => $operations,
|
Chris@0
|
474 ];
|
Chris@0
|
475 }
|
Chris@0
|
476
|
Chris@0
|
477 if ($element->subtree) {
|
Chris@0
|
478 $this->buildOverviewTreeForm($element->subtree, $delta);
|
Chris@0
|
479 }
|
Chris@0
|
480 }
|
Chris@0
|
481
|
Chris@0
|
482 $tree_access_cacheability
|
Chris@0
|
483 ->merge(CacheableMetadata::createFromRenderArray($form))
|
Chris@0
|
484 ->applyTo($form);
|
Chris@0
|
485
|
Chris@0
|
486 return $form;
|
Chris@0
|
487 }
|
Chris@0
|
488
|
Chris@0
|
489 /**
|
Chris@0
|
490 * Submit handler for the menu overview form.
|
Chris@0
|
491 *
|
Chris@0
|
492 * This function takes great care in saving parent items first, then items
|
Chris@0
|
493 * underneath them. Saving items in the incorrect order can break the tree.
|
Chris@0
|
494 */
|
Chris@0
|
495 protected function submitOverviewForm(array $complete_form, FormStateInterface $form_state) {
|
Chris@0
|
496 // Form API supports constructing and validating self-contained sections
|
Chris@0
|
497 // within forms, but does not allow to handle the form section's submission
|
Chris@0
|
498 // equally separated yet. Therefore, we use a $form_state key to point to
|
Chris@0
|
499 // the parents of the form section.
|
Chris@0
|
500 $parents = $form_state->get('menu_overview_form_parents');
|
Chris@0
|
501 $input = NestedArray::getValue($form_state->getUserInput(), $parents);
|
Chris@0
|
502 $form = &NestedArray::getValue($complete_form, $parents);
|
Chris@0
|
503
|
Chris@0
|
504 // When dealing with saving menu items, the order in which these items are
|
Chris@0
|
505 // saved is critical. If a changed child item is saved before its parent,
|
Chris@0
|
506 // the child item could be saved with an invalid path past its immediate
|
Chris@0
|
507 // parent. To prevent this, save items in the form in the same order they
|
Chris@0
|
508 // are sent, ensuring parents are saved first, then their children.
|
Chris@0
|
509 // See https://www.drupal.org/node/181126#comment-632270.
|
Chris@0
|
510 $order = is_array($input) ? array_flip(array_keys($input)) : [];
|
Chris@0
|
511 // Update our original form with the new order.
|
Chris@0
|
512 $form = array_intersect_key(array_merge($order, $form), $form);
|
Chris@0
|
513
|
Chris@0
|
514 $fields = ['weight', 'parent', 'enabled'];
|
Chris@0
|
515 $form_links = $form['links'];
|
Chris@0
|
516 foreach (Element::children($form_links) as $id) {
|
Chris@0
|
517 if (isset($form_links[$id]['#item'])) {
|
Chris@0
|
518 $element = $form_links[$id];
|
Chris@0
|
519 $updated_values = [];
|
Chris@0
|
520 // Update any fields that have changed in this menu item.
|
Chris@0
|
521 foreach ($fields as $field) {
|
Chris@18
|
522 if (isset($element[$field]['#value']) && $element[$field]['#value'] != $element[$field]['#default_value']) {
|
Chris@0
|
523 $updated_values[$field] = $element[$field]['#value'];
|
Chris@0
|
524 }
|
Chris@0
|
525 }
|
Chris@0
|
526 if ($updated_values) {
|
Chris@0
|
527 // Use the ID from the actual plugin instance since the hidden value
|
Chris@0
|
528 // in the form could be tampered with.
|
Chris@0
|
529 $this->menuLinkManager->updateDefinition($element['#item']->link->getPLuginId(), $updated_values);
|
Chris@0
|
530 }
|
Chris@0
|
531 }
|
Chris@0
|
532 }
|
Chris@0
|
533 }
|
Chris@0
|
534
|
Chris@0
|
535 }
|