2d01e4324e43bfb3331d3b6dd300d92a9358eb5b
[yaffs-website] / web / core / modules / workflows / src / Form / WorkflowTransitionEditForm.php
1 <?php
2
3 namespace Drupal\workflows\Form;
4
5 use Drupal\Core\Entity\EntityForm;
6 use Drupal\Core\Entity\EntityInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\Form\SubformState;
9 use Drupal\Core\Plugin\PluginFormFactoryInterface;
10 use Drupal\Core\Url;
11 use Drupal\workflows\State;
12 use Drupal\workflows\TransitionInterface;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
14
15 /**
16  * Class WorkflowTransitionEditForm.
17  *
18  * @internal
19  */
20 class WorkflowTransitionEditForm extends EntityForm {
21
22   /**
23    * The ID of the transition that is being edited.
24    *
25    * @var string
26    */
27   protected $transitionId;
28
29   /**
30    * The plugin form factory.
31    *
32    * @var \Drupal\Core\Plugin\PluginFormFactoryInterface
33    */
34   protected $pluginFormFactory;
35
36   /**
37    * Creates an instance of WorkflowStateEditForm.
38    *
39    * @param \Drupal\Core\Plugin\PluginFormFactoryInterface $pluginFormFactory
40    *   The plugin form factory.
41    */
42   public function __construct(PluginFormFactoryInterface $pluginFormFactory) {
43     $this->pluginFormFactory = $pluginFormFactory;
44   }
45
46   /**
47    * {@inheritdoc}
48    */
49   public static function create(ContainerInterface $container) {
50     return new static(
51       $container->get('plugin_form.factory')
52     );
53   }
54
55   /**
56    * {@inheritdoc}
57    */
58   public function getFormId() {
59     return 'workflow_transition_edit_form';
60   }
61
62   /**
63    * {@inheritdoc}
64    */
65   public function buildForm(array $form, FormStateInterface $form_state, $workflow_transition = NULL) {
66     $this->transitionId = $workflow_transition;
67     return parent::buildForm($form, $form_state);
68   }
69
70   /**
71    * {@inheritdoc}
72    */
73   public function form(array $form, FormStateInterface $form_state) {
74     $form = parent::form($form, $form_state);
75
76     /* @var \Drupal\workflows\WorkflowInterface $workflow */
77     $workflow = $this->getEntity();
78     $workflow_type = $workflow->getTypePlugin();
79     $transition = $workflow->getTypePlugin()->getTransition($this->transitionId);
80
81     $form['label'] = [
82       '#type' => 'textfield',
83       '#title' => $this->t('Transition label'),
84       '#maxlength' => 255,
85       '#default_value' => $transition->label(),
86       '#required' => TRUE,
87     ];
88
89     $form['id'] = [
90       '#type' => 'value',
91       '#value' => $this->transitionId,
92     ];
93
94     // @todo https://www.drupal.org/node/2830584 Add some ajax to ensure that
95     //   only valid transitions are selectable.
96     $states = array_map([State::class, 'labelCallback'], $workflow->getTypePlugin()->getStates());
97     $form['from'] = [
98       '#type' => 'checkboxes',
99       '#title' => $this->t('From'),
100       '#required' => TRUE,
101       '#default_value' => array_keys($transition->from()),
102       '#options' => $states,
103     ];
104     $form['to'] = [
105       '#type' => 'radios',
106       '#title' => $this->t('To'),
107       '#required' => TRUE,
108       '#default_value' => $transition->to()->id(),
109       '#options' => $states,
110       '#disabled' => TRUE,
111     ];
112
113     // Add additional form fields from the workflow type plugin.
114     if ($workflow_type->hasFormClass(TransitionInterface::PLUGIN_FORM_KEY)) {
115       $form['type_settings'] = [
116         '#tree' => TRUE,
117       ];
118       $subform_state = SubformState::createForSubform($form['type_settings'], $form, $form_state);
119       $subform_state->set('transition', $transition);
120       $form['type_settings'] += $this->pluginFormFactory
121         ->createInstance($workflow_type, TransitionInterface::PLUGIN_FORM_KEY)
122         ->buildConfigurationForm($form['type_settings'], $subform_state);
123     }
124
125     return $form;
126   }
127
128   /**
129    * {@inheritdoc}
130    */
131   public function validateForm(array &$form, FormStateInterface $form_state) {
132     /** @var \Drupal\workflows\WorkflowInterface $workflow */
133     $workflow = $this->getEntity();
134     $workflow_type = $workflow->getTypePlugin();
135     $transition = $workflow_type->getTransition($this->transitionId);
136
137     $values = $form_state->getValues();
138     foreach (array_filter($values['from']) as $from_state_id) {
139       if ($workflow_type->hasTransitionFromStateToState($from_state_id, $values['to'])) {
140         $existing_transition = $workflow_type->getTransitionFromStateToState($from_state_id, $values['to']);
141         if ($existing_transition->id() !== $values['id']) {
142           $form_state->setErrorByName('from][' . $from_state_id, $this->t('The transition from %from to %to already exists.', [
143             '%from' => $workflow->getTypePlugin()->getState($from_state_id)->label(),
144             '%to' => $workflow->getTypePlugin()->getState($values['to'])->label(),
145           ]));
146         }
147       }
148     }
149
150     if ($workflow_type->hasFormClass(TransitionInterface::PLUGIN_FORM_KEY)) {
151       $subform_state = SubformState::createForSubform($form['type_settings'], $form, $form_state);
152       $subform_state->set('transition', $transition);
153       $this->pluginFormFactory
154         ->createInstance($workflow_type, TransitionInterface::PLUGIN_FORM_KEY)
155         ->validateConfigurationForm($form['type_settings'], $subform_state);
156     }
157   }
158
159   /**
160    * Copies top-level form values to entity properties
161    *
162    * This form can only change values for a state, which is part of workflow.
163    *
164    * @param \Drupal\Core\Entity\EntityInterface $entity
165    *   The entity the current form should operate upon.
166    * @param array $form
167    *   A nested array of form elements comprising the form.
168    * @param \Drupal\Core\Form\FormStateInterface $form_state
169    *   The current state of the form.
170    */
171   protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
172     if (!$form_state->isValidationComplete()) {
173       // Only do something once form validation is complete.
174       return;
175     }
176     /** @var \Drupal\workflows\WorkflowInterface $entity */
177     $values = $form_state->getValues();
178     $form_state->set('created_transition', FALSE);
179     $entity->getTypePlugin()->setTransitionLabel($values['id'], $values['label']);
180     $entity->getTypePlugin()->setTransitionFromStates($values['id'], array_filter($values['from']));
181   }
182
183   /**
184    * {@inheritdoc}
185    */
186   public function save(array $form, FormStateInterface $form_state) {
187     /** @var \Drupal\workflows\WorkflowInterface $workflow */
188     $workflow = $this->entity;
189     $workflow_type = $workflow->getTypePlugin();
190     $transition = $workflow_type->getTransition($this->transitionId);
191
192     if ($workflow_type->hasFormClass(TransitionInterface::PLUGIN_FORM_KEY)) {
193       $subform_state = SubformState::createForSubform($form['type_settings'], $form, $form_state);
194       $subform_state->set('transition', $transition);
195       $this->pluginFormFactory
196         ->createInstance($workflow_type, TransitionInterface::PLUGIN_FORM_KEY)
197         ->submitConfigurationForm($form['type_settings'], $subform_state);
198     }
199
200     $workflow->save();
201     $this->messenger()->addStatus($this->t('Saved %label transition.', [
202       '%label' => $workflow->getTypePlugin()->getTransition($this->transitionId)->label(),
203     ]));
204     $form_state->setRedirectUrl($workflow->toUrl('edit-form'));
205   }
206
207   /**
208    * {@inheritdoc}
209    */
210   protected function actions(array $form, FormStateInterface $form_state) {
211     $actions['submit'] = [
212       '#type' => 'submit',
213       '#value' => $this->t('Save'),
214       '#submit' => ['::submitForm', '::save'],
215     ];
216
217     $actions['delete'] = [
218       '#type' => 'link',
219       '#title' => $this->t('Delete'),
220       // Deleting a transition is editing a workflow.
221       '#access' => $this->entity->access('edit'),
222       '#attributes' => [
223         'class' => ['button', 'button--danger'],
224       ],
225       '#url' => Url::fromRoute('entity.workflow.delete_transition_form', [
226         'workflow' => $this->entity->id(),
227         'workflow_transition' => $this->transitionId,
228       ]),
229     ];
230
231     return $actions;
232   }
233
234 }