Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / inline_entity_form / src / Form / EntityInlineForm.php
1 <?php
2
3 namespace Drupal\inline_entity_form\Form;
4
5 use Drupal\Core\Entity\ContentEntityInterface;
6 use Drupal\Core\Entity\Entity\EntityFormDisplay;
7 use Drupal\Core\Entity\EntityInterface;
8 use Drupal\Core\Entity\EntityFieldManagerInterface;
9 use Drupal\Core\Entity\EntityTypeInterface;
10 use Drupal\Core\Entity\EntityTypeManagerInterface;
11 use Drupal\Core\Extension\ModuleHandlerInterface;
12 use Drupal\Core\Field\WidgetBase;
13 use Drupal\Core\Form\FormStateInterface;
14 use Drupal\Core\Render\Element;
15 use Drupal\inline_entity_form\InlineFormInterface;
16 use Symfony\Component\DependencyInjection\ContainerInterface;
17
18 /**
19  * Generic entity inline form handler.
20  */
21 class EntityInlineForm implements InlineFormInterface {
22
23   /**
24    * The entity field manager.
25    *
26    * @var \Drupal\Core\Entity\EntityFieldManagerInterface
27    */
28   protected $entityFieldManager;
29
30   /**
31    * The entity type manager.
32    *
33    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
34    */
35   protected $entityTypeManager;
36
37   /**
38    * The entity type managed by this handler.
39    *
40    * @var \Drupal\Core\Entity\EntityTypeInterface
41    */
42   protected $entityType;
43
44   /**
45    * Module handler service.
46    *
47    * @var \Drupal\Core\Extension\ModuleHandlerInterface
48    */
49   protected $moduleHandler;
50
51   /**
52    * Constructs the inline entity form controller.
53    *
54    * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
55    *   The entity field manager.
56    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
57    *   The entity type manager.
58    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
59    *   The module handler.
60    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
61    *   The entity type.
62    */
63   public function __construct(EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, EntityTypeInterface $entity_type) {
64     $this->entityFieldManager = $entity_field_manager;
65     $this->entityTypeManager = $entity_type_manager;
66     $this->moduleHandler = $module_handler;
67     $this->entityType = $entity_type;
68   }
69
70   /**
71    * {@inheritdoc}
72    */
73   public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
74     return new static(
75       $container->get('entity_field.manager'),
76       $container->get('entity_type.manager'),
77       $container->get('module_handler'),
78       $entity_type
79     );
80   }
81
82   /**
83    * {@inheritdoc}
84    */
85   public function getEntityType() {
86     return $this->entityType;
87   }
88
89   /**
90    * {@inheritdoc}
91    */
92   public function getEntityTypeLabels() {
93     $lowercase_label = $this->entityType->getLowercaseLabel();
94     return [
95       'singular' => $lowercase_label,
96       'plural' => t('@entity_type entities', ['@entity_type' => $lowercase_label]),
97     ];
98   }
99
100   /**
101    * {@inheritdoc}
102    */
103   public function getEntityLabel(EntityInterface $entity) {
104     return $entity->label();
105   }
106
107   /**
108    * {@inheritdoc}
109    */
110   public function getTableFields($bundles) {
111     $definitions = $this->entityFieldManager->getBaseFieldDefinitions($this->entityType->id());
112     $label_key = $this->entityType->getKey('label');
113     $label_field_label = t('Label');
114     if ($label_key && isset($definitions[$label_key])) {
115       $label_field_label = $definitions[$label_key]->getLabel();
116     }
117     $bundle_key = $this->entityType->getKey('bundle');
118     $bundle_field_label = t('Type');
119     if ($bundle_key && isset($definitions[$bundle_key])) {
120       $bundle_field_label = $definitions[$bundle_key]->getLabel();
121     }
122
123     $fields = [];
124     $fields['label'] = [
125       'type' => 'label',
126       'label' => $label_field_label,
127       'weight' => 1,
128     ];
129     if (count($bundles) > 1) {
130       $fields[$bundle_key] = [
131         'type' => 'field',
132         'label' => $bundle_field_label,
133         'weight' => 2,
134         'display_options' => [
135           'type' => 'entity_reference_label',
136           'settings' => ['link' => FALSE],
137         ],
138       ];
139     }
140
141     return $fields;
142   }
143
144   /**
145    * {@inheritdoc}
146    */
147   public function isTableDragEnabled($element) {
148     $children = Element::children($element);
149     // If there is only one row, disable tabledrag.
150     if (count($children) == 1) {
151       return FALSE;
152     }
153     // If one of the rows is in form context, disable tabledrag.
154     foreach ($children as $key) {
155       if (!empty($element[$key]['form'])) {
156         return FALSE;
157       }
158     }
159
160     return TRUE;
161   }
162
163   /**
164    * {@inheritdoc}
165    */
166   public function entityForm(array $entity_form, FormStateInterface $form_state) {
167     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
168     $entity = $entity_form['#entity'];
169     $form_display = $this->getFormDisplay($entity, $entity_form['#form_mode']);
170     $form_display->buildForm($entity, $entity_form, $form_state);
171     $entity_form['#ief_element_submit'][] = [get_class($this), 'submitCleanFormState'];
172     // Inline entities inherit the parent language.
173     $langcode_key = $this->entityType->getKey('langcode');
174     if ($langcode_key && isset($entity_form[$langcode_key])) {
175       $entity_form[$langcode_key]['#access'] = FALSE;
176     }
177     if (!empty($entity_form['#translating'])) {
178       // Hide the non-translatable fields.
179       foreach ($entity->getFieldDefinitions() as $field_name => $definition) {
180         if (isset($entity_form[$field_name]) && $field_name != $langcode_key) {
181           $entity_form[$field_name]['#access'] = $definition->isTranslatable();
182         }
183       }
184     }
185
186     // Determine the children of the entity form before it has been altered.
187     $children_before = Element::children($entity_form);
188
189     // Allow other modules to alter the form.
190     $this->moduleHandler->alter('inline_entity_form_entity_form', $entity_form, $form_state);
191
192     // Determine the children of the entity form after it has been altered.
193     $children_after = Element::children($entity_form);
194
195     // Ensure that any new children added have #tree, #parents, #array_parents
196     // and handle setting the proper #group if it's referencing a local element.
197     // Note: the #tree, #parents and #array_parents code is a direct copy from
198     // \Drupal\Core\Form\FormBuilder::doBuildForm.
199     $children_diff = array_diff($children_after, $children_before);
200     foreach ($children_diff as $child) {
201       // Don't squash an existing tree value.
202       if (!isset($entity_form[$child]['#tree'])) {
203         $entity_form[$child]['#tree'] = $entity_form['#tree'];
204       }
205
206       // Don't squash existing parents value.
207       if (!isset($entity_form[$child]['#parents'])) {
208         // Check to see if a tree of child elements is present. If so,
209         // continue down the tree if required.
210         $entity_form[$child]['#parents'] = $entity_form[$child]['#tree'] && $entity_form['#tree'] ? array_merge($entity_form['#parents'], [$child]) : [$child];
211       }
212
213       // Ensure #array_parents follows the actual form structure.
214       $array_parents = $entity_form['#array_parents'];
215       $array_parents[] = $child;
216       $entity_form[$child]['#array_parents'] = $array_parents;
217
218       // Detect if there is a #group and it specifies a local element. If so,
219       // change it to use the proper local element's #parents group name.
220       if (isset($entity_form[$child]['#group']) && isset($entity_form[$entity_form[$child]['#group']])) {
221         $entity_form[$child]['#group'] = implode('][', $entity_form[$entity_form[$child]['#group']]['#parents']);
222       }
223     }
224
225     return $entity_form;
226   }
227
228   /**
229    * {@inheritdoc}
230    */
231   public function entityFormValidate(array &$entity_form, FormStateInterface $form_state) {
232     // Perform entity validation only if the inline form was submitted,
233     // skipping other requests such as file uploads.
234     $triggering_element = $form_state->getTriggeringElement();
235     if (!empty($triggering_element['#ief_submit_trigger'])) {
236       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
237       $entity = $entity_form['#entity'];
238       $this->buildEntity($entity_form, $entity, $form_state);
239       $form_display = $this->getFormDisplay($entity, $entity_form['#form_mode']);
240       $form_display->validateFormValues($entity, $entity_form, $form_state);
241       $entity->setValidationRequired(FALSE);
242
243       foreach ($form_state->getErrors() as $name => $message) {
244         // $name may be unknown in $form_state and
245         // $form_state->setErrorByName($name, $message) may suppress the error message.
246         $form_state->setError($triggering_element, $message);
247       }
248     }
249   }
250
251   /**
252    * {@inheritdoc}
253    */
254   public function entityFormSubmit(array &$entity_form, FormStateInterface $form_state) {
255     $form_state->cleanValues();
256     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
257     $entity = $entity_form['#entity'];
258     $this->buildEntity($entity_form, $entity, $form_state);
259   }
260
261   /**
262    * {@inheritdoc}
263    */
264   public function save(EntityInterface $entity) {
265     $entity->save();
266   }
267
268   /**
269    * {@inheritdoc}
270    */
271   public function delete($ids, $context) {
272     $storage_handler = $this->entityTypeManager->getStorage($this->entityType->id());
273     $entities = $storage_handler->loadMultiple($ids);
274     $storage_handler->delete($entities);
275   }
276
277   /**
278    * Builds an updated entity object based upon the submitted form values.
279    *
280    * @param array $entity_form
281    *   The entity form.
282    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
283    *   The entity.
284    * @param \Drupal\Core\Form\FormStateInterface $form_state
285    *   The current state of the form.
286    */
287   protected function buildEntity(array $entity_form, ContentEntityInterface $entity, FormStateInterface $form_state) {
288     $form_display = $this->getFormDisplay($entity, $entity_form['#form_mode']);
289     $form_display->extractFormValues($entity, $entity_form, $form_state);
290     // Invoke all specified builders for copying form values to entity fields.
291     if (isset($entity_form['#entity_builders'])) {
292       foreach ($entity_form['#entity_builders'] as $function) {
293         call_user_func_array($function, [$entity->getEntityTypeId(), $entity, &$entity_form, &$form_state]);
294       }
295     }
296   }
297
298   /**
299    * Cleans up the form state for a submitted entity form.
300    *
301    * After field_attach_submit() has run and the form has been closed, the form
302    * state still contains field data in $form_state->get('field'). Unless that
303    * data is removed, the next form with the same #parents (reopened add form,
304    * for example) will contain data (i.e. uploaded files) from the previous form.
305    *
306    * @param $entity_form
307    *   The entity form.
308    * @param $form_state
309    *   The form state of the parent form.
310    */
311   public static function submitCleanFormState(&$entity_form, FormStateInterface $form_state) {
312     /** @var \Drupal\Core\Entity\EntityInterface $entity */
313     $entity = $entity_form['#entity'];
314     $bundle = $entity->bundle();
315     /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $instances */
316     $instances = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_form['#entity_type'], $bundle);
317     foreach ($instances as $instance) {
318       $field_name = $instance->getName();
319       if (!empty($entity_form[$field_name]['#parents'])) {
320         $parents = $entity_form[$field_name]['#parents'];
321         array_pop($parents);
322         if (!empty($parents)) {
323           $field_state = [];
324           WidgetBase::setWidgetState($parents, $field_name, $form_state, $field_state);
325         }
326       }
327     }
328   }
329
330   /**
331    * Gets the form display for the given entity.
332    *
333    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
334    *   The entity.
335    * @param string $form_mode
336    *   The form mode.
337    *
338    * @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface
339    *   The form display.
340    */
341   protected function getFormDisplay(ContentEntityInterface $entity, $form_mode) {
342     return EntityFormDisplay::collectRenderDisplay($entity, $form_mode);
343   }
344
345 }