Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / entityqueue / src / Form / EntityQueueForm.php
1 <?php
2
3 namespace Drupal\entityqueue\Form;
4
5 use Drupal\Component\Plugin\PluginManagerInterface;
6 use Drupal\Component\Utility\Html;
7 use Drupal\Core\Entity\BundleEntityFormBase;
8 use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
9 use Drupal\Core\Entity\EntityTypeRepositoryInterface;
10 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\Core\Form\SubformState;
13 use Drupal\entityqueue\EntityQueueInterface;
14 use Psr\Log\LoggerInterface;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16
17 /**
18  * Base form for entity queue edit forms.
19  */
20 class EntityQueueForm extends BundleEntityFormBase {
21
22   /**
23    * The entity being used by this form.
24    *
25    * @var \Drupal\entityqueue\EntityQueueInterface
26    */
27   protected $entity;
28
29   /**
30    * The entity type repository.
31    *
32    * @var \Drupal\Core\Entity\EntityTypeRepositoryInterface
33    */
34   protected $entityTypeRepository;
35
36   /**
37    * The entity queue handler plugin manager.
38    *
39    * @var \Drupal\entityqueue\EntityQueueHandlerManager
40    */
41   protected $entityQueueHandlerManager;
42
43   /**
44    * Selection manager service.
45    *
46    * @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface
47    */
48   protected $selectionManager;
49
50   /**
51    * A logger instance.
52    *
53    * @var \Psr\Log\LoggerInterface
54    */
55   protected $logger;
56
57   /**
58    * {@inheritdoc}
59    */
60   public static function create(ContainerInterface $container) {
61     return new static(
62       $container->get('entity_type.repository'),
63       $container->get('plugin.manager.entityqueue.handler'),
64       $container->get('plugin.manager.entity_reference_selection'),
65       $container->get('logger.factory')->get('entityqueue')
66     );
67   }
68
69   /**
70    * Constructs a EntityQueueForm.
71    *
72    * @param \Drupal\Core\Entity\EntityTypeRepositoryInterface $entity_type_repository
73    *   The entity type repository.
74    * @param \Drupal\Component\Plugin\PluginManagerInterface $entity_queue_handler_manager
75    *   The entity queue handler plugin manager.
76    * @param \Psr\Log\LoggerInterface $logger
77    *   A logger instance.
78    */
79   public function __construct(EntityTypeRepositoryInterface $entity_type_repository, PluginManagerInterface $entity_queue_handler_manager, SelectionPluginManagerInterface $selection_manager, LoggerInterface $logger) {
80     $this->entityTypeRepository = $entity_type_repository;
81     $this->entityQueueHandlerManager = $entity_queue_handler_manager;
82     $this->selectionManager = $selection_manager;
83     $this->logger = $logger;
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   public function form(array $form, FormStateInterface $form_state) {
90     $form = parent::form($form, $form_state);
91     $queue = $this->entity;
92
93     // Default to nodes as the queue target entity type.
94     $target_entity_type_id = $queue->getTargetEntityTypeId() ?: 'node';
95
96     $form['label'] = [
97       '#type' => 'textfield',
98       '#title' => $this->t('Name'),
99       '#maxlength' => 32,
100       '#size' => 32,
101       '#default_value' => $queue->label(),
102       '#description' => $this->t('The human-readable name of this entity queue. This name must be unique.'),
103       '#required' => TRUE,
104     ];
105
106     $form['id'] = [
107       '#type' => 'machine_name',
108       '#default_value' => $queue->id(),
109       '#machine_name' => [
110         'exists' => '\Drupal\entityqueue\Entity\EntityQueue::load',
111       ],
112       '#disabled' => !$queue->isNew(),
113     ];
114
115     $handler_plugin = $this->getHandlerPlugin($this->getEntity(), $form_state);
116     $form['handler'] = [
117       '#type' => 'radios',
118       '#title' => $this->t('Type'),
119       '#options' => $this->entityQueueHandlerManager->getAllEntityQueueHandlers(),
120       '#default_value' => $handler_plugin->getPluginId(),
121       '#required' => TRUE,
122       '#disabled' => !$queue->isNew(),
123       '#ajax' => [
124         'callback' => '::settingsAjax',
125         'wrapper' => 'entityqueue-handler-settings-wrapper',
126         'trigger_as' => ['name' => 'handler_change'],
127       ],
128     ];
129     $form['handler_change'] = [
130       '#type' => 'submit',
131       '#name' => 'handler_change',
132       '#value' => $this->t('Change type'),
133       '#limit_validation_errors' => [],
134       '#submit' => [[get_called_class(), 'settingsAjaxSubmit']],
135       '#attributes' => ['class' => ['js-hide']],
136       '#ajax' => [
137         'callback' => '::settingsAjax',
138         'wrapper' => 'entityqueue-handler-settings-wrapper',
139       ],
140     ];
141
142     $form['handler_settings_wrapper'] = [
143       '#type' => 'container',
144       '#id' => 'entityqueue-handler-settings-wrapper',
145       '#tree' => TRUE,
146     ];
147
148     $form['handler_settings_wrapper']['handler_settings'] = [];
149     $subform_state = SubformState::createForSubform($form['handler_settings_wrapper']['handler_settings'], $form, $form_state);
150     $form['handler_settings_wrapper']['handler_settings'] = $handler_plugin->buildConfigurationForm($form['handler_settings_wrapper']['handler_settings'], $subform_state);
151
152     $form['settings'] = [
153       '#type' => 'vertical_tabs',
154     ];
155
156     $form['queue_settings'] = [
157       '#type' => 'details',
158       '#title' => $this->t('Queue settings'),
159       '#open' => TRUE,
160       '#tree' => TRUE,
161       '#group' => 'settings',
162     ];
163     $form['queue_settings']['size'] = [
164       '#type' => 'container',
165       '#attributes' => ['class' => ['form--inline', 'clearfix']],
166       '#process' => [
167         [EntityReferenceItem::class, 'formProcessMergeParent']
168       ],
169     ];
170     $form['queue_settings']['size']['min_size'] = [
171       '#type' => 'number',
172       '#size' => 2,
173       '#default_value' => $queue->getMinimumSize(),
174       '#field_prefix' => $this->t('Restrict this queue to a minimum of'),
175     ];
176     $form['queue_settings']['size']['max_size'] = [
177       '#type' => 'number',
178       '#default_value' => $queue->getMaximumSize(),
179       '#field_prefix' => $this->t('and a maximum of'),
180       '#field_suffix' => $this->t('items.'),
181     ];
182     $form['queue_settings']['act_as_queue'] = [
183       '#type' => 'checkbox',
184       '#title' => $this->t('Act as queue'),
185       '#default_value' => $queue->getActAsQueue(),
186       '#description' => $this->t('When enabled, adding more than the maximum number of items will remove extra items from the top of the queue.'),
187       '#states' => [
188         'invisible' => [
189           ':input[name="queue_settings[max_size]"]' => ['value' => 0],
190         ],
191       ],
192     ];
193     $form['queue_settings']['reverse_in_admin'] = [
194       '#type' => 'checkbox',
195       '#title' => $this->t('Reverse order in admin view'),
196       '#default_value' => $queue->getReverseInAdmin(),
197       '#description' => $this->t('Ordinarily queues are arranged with the front of the queue (where items will be removed) on top and the back (where items will be added) on the bottom. If checked, this will display the queue such that items will be added to the top and removed from the bottom.'),
198     ];
199
200     // We have to duplicate all the code from
201     // \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::fieldSettingsForm()
202     // because field settings forms are not easily embeddable.
203     $form['entity_settings'] = [
204       '#type' => 'details',
205       '#title' => $this->t('Entity settings'),
206       '#open' => TRUE,
207       '#tree' => TRUE,
208       '#group' => 'settings',
209       '#weight' => -1,
210     ];
211
212     // Get all selection plugins for this entity type.
213     $selection_plugins = $this->selectionManager->getSelectionGroups($target_entity_type_id);
214     $selection_handlers_options = [];
215     foreach (array_keys($selection_plugins) as $selection_group_id) {
216       // We only display base plugins (e.g. 'default', 'views', ...) and not
217       // entity type specific plugins (e.g. 'default:node', 'default:user',
218       // ...).
219       if (array_key_exists($selection_group_id, $selection_plugins[$selection_group_id])) {
220         $selection_handlers_options[$selection_group_id] = Html::escape($selection_plugins[$selection_group_id][$selection_group_id]['label']);
221       }
222       elseif (array_key_exists($selection_group_id . ':' . $target_entity_type_id, $selection_plugins[$selection_group_id])) {
223         $selection_group_plugin = $selection_group_id . ':' . $target_entity_type_id;
224         $selection_handlers_options[$selection_group_plugin] = Html::escape($selection_plugins[$selection_group_id][$selection_group_plugin]['base_plugin_label']);
225       }
226     }
227     ksort($selection_handlers_options);
228
229     $form['entity_settings']['settings'] = [
230       '#type' => 'container',
231       '#process' => [
232         [EntityReferenceItem::class, 'fieldSettingsAjaxProcess'],
233         [EntityReferenceItem::class, 'formProcessMergeParent']
234       ],
235       '#element_validate' => [[get_class($this), 'entityReferenceSelectionSettingsValidate']],
236     ];
237
238     // @todo It should be up to the queue handler to determine what entity types
239     // are queue-able.
240     $form['entity_settings']['settings']['target_type'] = [
241       '#type' => 'select',
242       '#title' => $this->t('Type of items to queue'),
243       '#options' => $this->entityTypeRepository->getEntityTypeLabels(TRUE),
244       '#default_value' => $target_entity_type_id,
245       '#required' => TRUE,
246       '#disabled' => !$queue->isNew(),
247       '#size' => 1,
248       '#ajax' => TRUE,
249       '#limit_validation_errors' => [],
250     ];
251
252     $form['entity_settings']['settings']['handler'] = [
253       '#type' => 'select',
254       '#title' => $this->t('Reference method'),
255       '#options' => $selection_handlers_options,
256       '#default_value' => $queue->getEntitySettings()['handler'],
257       '#required' => TRUE,
258       '#ajax' => TRUE,
259       '#limit_validation_errors' => [],
260     ];
261     $form['entity_settings']['settings']['handler_submit'] = [
262       '#type' => 'submit',
263       '#value' => $this->t('Change handler'),
264       '#limit_validation_errors' => [],
265       '#attributes' => [
266         'class' => ['js-hide'],
267       ],
268       '#submit' => [[EntityReferenceItem::class, 'settingsAjaxSubmit']],
269     ];
270
271     $form['entity_settings']['settings']['handler_settings'] = [
272       '#type' => 'container',
273     ];
274
275     $selection_handler = $this->selectionManager->getInstance($queue->getEntitySettings());
276     $form['entity_settings']['settings']['handler_settings'] += $selection_handler->buildConfigurationForm([], $form_state);
277
278     // For entityqueue's purposes, the 'target_bundles' setting of the 'default'
279     // selection handler does not have to be required.
280     if (isset($form['entity_settings']['settings']['handler_settings']['target_bundles'])) {
281       $form['entity_settings']['settings']['handler_settings']['target_bundles']['#required'] = FALSE;
282     }
283
284     return $form;
285   }
286
287   /**
288    * Gets the handler plugin for the currently selected queue handler.
289    *
290    * @param \Drupal\entityqueue\EntityQueueInterface $entity
291    *   The current form entity.
292    * @param \Drupal\Core\Form\FormStateInterface $form_state
293    *   The current state of the form.
294    *
295    * @return \Drupal\entityqueue\EntityQueueHandlerInterface
296    *   The queue handler plugin.
297    */
298   protected function getHandlerPlugin(EntityQueueInterface $entity, FormStateInterface $form_state) {
299     if (!$handler_plugin = $form_state->get('handler_plugin')) {
300       $stored_handler_id = $entity->getHandler();
301       // Use selected handler if it exists, falling back to the stored handler.
302       $handler_id = $form_state->getValue('handler', $stored_handler_id);
303       // If the current handler is the stored handler, use the stored handler
304       // settings. Otherwise leave the settings empty.
305       $handler_configuration = $handler_id === $stored_handler_id ? $entity->getHandlerConfiguration() : [];
306
307       $handler_plugin = $this->entityQueueHandlerManager->createInstance($handler_id, $handler_configuration);
308       $form_state->set('handler_plugin', $handler_plugin);
309     }
310     return $handler_plugin;
311   }
312
313   /**
314    * Ajax callback for the queue settings form.
315    */
316   public static function settingsAjax($form, FormStateInterface $form_state) {
317     return $form['handler_settings_wrapper'];
318   }
319
320   /**
321    * Submit handler for the non-JS case.
322    */
323   public static function settingsAjaxSubmit($form, FormStateInterface $form_state) {
324     $form_state->set('handler_plugin', NULL);
325     $form_state->setRebuild();
326   }
327
328   /**
329    * Form element validation handler; Invokes selection plugin's validation.
330    *
331    * @param array $form
332    *   The form where the settings form is being included in.
333    * @param \Drupal\Core\Form\FormStateInterface $form_state
334    *   The form state of the (entire) configuration form.
335    */
336   public static function entityReferenceSelectionSettingsValidate(array $form, FormStateInterface $form_state) {
337     /** @var \Drupal\entityqueue\EntityQueueInterface $queue */
338     $queue = $form_state->getFormObject()->getEntity();
339
340     $selection_handler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($queue->getEntitySettings());
341
342     // @todo Take care of passing the right $form and $form_state structures to
343     // the selection validation method. For now, we just have to duplicate the
344     // validation of the 'default' selection plugin.
345     $selection_handler->validateConfigurationForm($form, $form_state);
346
347     // If no checkboxes were checked for 'target_bundles', store NULL ("all
348     // bundles are referenceable") rather than empty array ("no bundle is
349     // referenceable".
350     if ($form_state->getValue(['entity_settings', 'handler_settings', 'target_bundles']) === []) {
351       $form_state->setValue(['entity_settings', 'handler_settings', 'target_bundles'], NULL);
352     }
353   }
354
355   /**
356    * {@inheritdoc}
357    */
358   public function validateForm(array &$form, FormStateInterface $form_state) {
359     parent::validateForm($form, $form_state);
360
361     $handler_plugin = $this->getHandlerPlugin($this->getEntity(), $form_state);
362     $subform_state = SubformState::createForSubform($form['handler_settings_wrapper']['handler_settings'], $form, $form_state);
363     $handler_plugin->validateConfigurationForm($form['handler_settings_wrapper']['handler_settings'], $subform_state);
364   }
365
366   /**
367    * Overrides \Drupal\field_ui\Form\EntityDisplayFormBase::submitForm().
368    */
369   public function submitForm(array &$form, FormStateInterface $form_state) {
370     parent::submitForm($form, $form_state);
371
372     /** @var \Drupal\entityqueue\EntityQueueInterface $queue */
373     $queue = $this->getEntity();
374     $handler_plugin = $this->getHandlerPlugin($queue, $form_state);
375     $subform_state = SubformState::createForSubform($form['handler_settings_wrapper']['handler_settings'], $form, $form_state);
376     $handler_plugin->submitConfigurationForm($form['handler_settings_wrapper']['handler_settings'], $subform_state);
377
378     $queue->setHandlerPlugin($handler_plugin);
379   }
380
381   /**
382    * {@inheritdoc}
383    */
384   public function save(array $form, FormStateInterface $form_state) {
385     $queue = $this->entity;
386     $status = $queue->save();
387
388     $edit_link = $queue->toLink($this->t('Edit'), 'edit-form')->toString();
389     if ($status == SAVED_UPDATED) {
390       drupal_set_message($this->t('The entity queue %label has been updated.', ['%label' => $queue->label()]));
391       $this->logger->notice('The entity queue %label has been updated.', ['%label' => $queue->label(), 'link' => $edit_link]);
392     }
393     else {
394       drupal_set_message($this->t('The entity queue %label has been added.', ['%label' => $queue->label()]));
395       $this->logger->notice('The entity queue %label has been added.', ['%label' => $queue->label(), 'link' => $edit_link]);
396     }
397
398     $form_state->setRedirectUrl($queue->toUrl('collection'));
399   }
400
401 }