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