3 namespace Drupal\entityqueue\Form;
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;
18 * Base form for entity queue edit forms.
20 class EntityQueueForm extends BundleEntityFormBase {
23 * The entity being used by this form.
25 * @var \Drupal\entityqueue\EntityQueueInterface
30 * The entity type repository.
32 * @var \Drupal\Core\Entity\EntityTypeRepositoryInterface
34 protected $entityTypeRepository;
37 * The entity queue handler plugin manager.
39 * @var \Drupal\entityqueue\EntityQueueHandlerManager
41 protected $entityQueueHandlerManager;
44 * Selection manager service.
46 * @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface
48 protected $selectionManager;
53 * @var \Psr\Log\LoggerInterface
60 public static function create(ContainerInterface $container) {
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')
70 * Constructs a EntityQueueForm.
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
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;
89 public function form(array $form, FormStateInterface $form_state) {
90 $form = parent::form($form, $form_state);
91 $queue = $this->entity;
93 // Default to nodes as the queue target entity type.
94 $target_entity_type_id = $queue->getTargetEntityTypeId() ?: 'node';
97 '#type' => 'textfield',
98 '#title' => $this->t('Name'),
101 '#default_value' => $queue->label(),
102 '#description' => $this->t('The human-readable name of this entity queue. This name must be unique.'),
107 '#type' => 'machine_name',
108 '#default_value' => $queue->id(),
110 'exists' => '\Drupal\entityqueue\Entity\EntityQueue::load',
112 '#disabled' => !$queue->isNew(),
115 $handler_plugin = $this->getHandlerPlugin($this->getEntity(), $form_state);
118 '#title' => $this->t('Type'),
119 '#options' => $this->entityQueueHandlerManager->getAllEntityQueueHandlers(),
120 '#default_value' => $handler_plugin->getPluginId(),
122 '#disabled' => !$queue->isNew(),
124 'callback' => '::settingsAjax',
125 'wrapper' => 'entityqueue-handler-settings-wrapper',
126 'trigger_as' => ['name' => 'handler_change'],
129 $form['handler_change'] = [
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']],
137 'callback' => '::settingsAjax',
138 'wrapper' => 'entityqueue-handler-settings-wrapper',
142 $form['handler_settings_wrapper'] = [
143 '#type' => 'container',
144 '#id' => 'entityqueue-handler-settings-wrapper',
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);
152 $form['settings'] = [
153 '#type' => 'vertical_tabs',
156 $form['queue_settings'] = [
157 '#type' => 'details',
158 '#title' => $this->t('Queue settings'),
161 '#group' => 'settings',
163 $form['queue_settings']['size'] = [
164 '#type' => 'container',
165 '#attributes' => ['class' => ['form--inline', 'clearfix']],
167 [EntityReferenceItem::class, 'formProcessMergeParent']
170 $form['queue_settings']['size']['min_size'] = [
173 '#default_value' => $queue->getMinimumSize(),
174 '#field_prefix' => $this->t('Restrict this queue to a minimum of'),
176 $form['queue_settings']['size']['max_size'] = [
178 '#default_value' => $queue->getMaximumSize(),
179 '#field_prefix' => $this->t('and a maximum of'),
180 '#field_suffix' => $this->t('items.'),
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.'),
189 ':input[name="queue_settings[max_size]"]' => ['value' => 0],
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.'),
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'),
208 '#group' => 'settings',
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',
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']);
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']);
227 ksort($selection_handlers_options);
229 $form['entity_settings']['settings'] = [
230 '#type' => 'container',
232 [EntityReferenceItem::class, 'fieldSettingsAjaxProcess'],
233 [EntityReferenceItem::class, 'formProcessMergeParent']
235 '#element_validate' => [[get_class($this), 'entityReferenceSelectionSettingsValidate']],
238 // @todo It should be up to the queue handler to determine what entity types
240 $form['entity_settings']['settings']['target_type'] = [
242 '#title' => $this->t('Type of items to queue'),
243 '#options' => $this->entityTypeRepository->getEntityTypeLabels(TRUE),
244 '#default_value' => $target_entity_type_id,
246 '#disabled' => !$queue->isNew(),
249 '#limit_validation_errors' => [],
252 $form['entity_settings']['settings']['handler'] = [
254 '#title' => $this->t('Reference method'),
255 '#options' => $selection_handlers_options,
256 '#default_value' => $queue->getEntitySettings()['handler'],
259 '#limit_validation_errors' => [],
261 $form['entity_settings']['settings']['handler_submit'] = [
263 '#value' => $this->t('Change handler'),
264 '#limit_validation_errors' => [],
266 'class' => ['js-hide'],
268 '#submit' => [[EntityReferenceItem::class, 'settingsAjaxSubmit']],
271 $form['entity_settings']['settings']['handler_settings'] = [
272 '#type' => 'container',
275 $selection_handler = $this->selectionManager->getInstance($queue->getEntitySettings());
276 $form['entity_settings']['settings']['handler_settings'] += $selection_handler->buildConfigurationForm([], $form_state);
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;
288 * Gets the handler plugin for the currently selected queue handler.
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.
295 * @return \Drupal\entityqueue\EntityQueueHandlerInterface
296 * The queue handler plugin.
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() : [];
307 $handler_plugin = $this->entityQueueHandlerManager->createInstance($handler_id, $handler_configuration);
308 $form_state->set('handler_plugin', $handler_plugin);
310 return $handler_plugin;
314 * Ajax callback for the queue settings form.
316 public static function settingsAjax($form, FormStateInterface $form_state) {
317 return $form['handler_settings_wrapper'];
321 * Submit handler for the non-JS case.
323 public static function settingsAjaxSubmit($form, FormStateInterface $form_state) {
324 $form_state->set('handler_plugin', NULL);
325 $form_state->setRebuild();
329 * Form element validation handler; Invokes selection plugin's validation.
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.
336 public static function entityReferenceSelectionSettingsValidate(array $form, FormStateInterface $form_state) {
337 /** @var \Drupal\entityqueue\EntityQueueInterface $queue */
338 $queue = $form_state->getFormObject()->getEntity();
340 $selection_handler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($queue->getEntitySettings());
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);
347 // If no checkboxes were checked for 'target_bundles', store NULL ("all
348 // bundles are referenceable") rather than empty array ("no bundle is
350 if ($form_state->getValue(['entity_settings', 'handler_settings', 'target_bundles']) === []) {
351 $form_state->setValue(['entity_settings', 'handler_settings', 'target_bundles'], NULL);
358 public function validateForm(array &$form, FormStateInterface $form_state) {
359 parent::validateForm($form, $form_state);
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);
367 * Overrides \Drupal\field_ui\Form\EntityDisplayFormBase::submitForm().
369 public function submitForm(array &$form, FormStateInterface $form_state) {
370 parent::submitForm($form, $form_state);
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);
378 $queue->setHandlerPlugin($handler_plugin);
384 public function save(array $form, FormStateInterface $form_state) {
385 $queue = $this->entity;
386 $status = $queue->save();
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]);
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]);
398 $form_state->setRedirectUrl($queue->toUrl('collection'));