fb4915fa3d0c5a93162a7a60dd433841e5e82603
[yaffs-website] / web / core / modules / media / src / MediaTypeForm.php
1 <?php
2
3 namespace Drupal\media;
4
5 use Drupal\Component\Plugin\PluginManagerInterface;
6 use Drupal\Core\Ajax\AjaxResponse;
7 use Drupal\Core\Ajax\ReplaceCommand;
8 use Drupal\Core\Entity\EntityFieldManagerInterface;
9 use Drupal\Core\Entity\EntityForm;
10 use Drupal\Core\Field\BaseFieldDefinition;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\Core\Form\SubformState;
13 use Drupal\language\Entity\ContentLanguageSettings;
14 use Drupal\media\Entity\MediaType;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16
17 /**
18  * Form controller for media type forms.
19  *
20  * @internal
21  */
22 class MediaTypeForm extends EntityForm {
23
24   /**
25    * Media source plugin manager.
26    *
27    * @var \Drupal\Component\Plugin\PluginManagerInterface
28    */
29   protected $sourceManager;
30
31   /**
32    * Entity field manager service.
33    *
34    * @var \Drupal\Core\Entity\EntityFieldManagerInterface
35    */
36   protected $entityFieldManager;
37
38   /**
39    * Constructs a new class instance.
40    *
41    * @param \Drupal\Component\Plugin\PluginManagerInterface $source_manager
42    *   Media source plugin manager.
43    * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
44    *   Entity field manager service.
45    */
46   public function __construct(PluginManagerInterface $source_manager, EntityFieldManagerInterface $entity_field_manager) {
47     $this->sourceManager = $source_manager;
48     $this->entityFieldManager = $entity_field_manager;
49   }
50
51   /**
52    * {@inheritdoc}
53    */
54   public static function create(ContainerInterface $container) {
55     return new static(
56       $container->get('plugin.manager.media.source'),
57       $container->get('entity_field.manager')
58     );
59   }
60
61   /**
62    * Ajax callback triggered by the type provider select element.
63    */
64   public function ajaxHandlerData(array $form, FormStateInterface $form_state) {
65     $response = new AjaxResponse();
66     $response->addCommand(new ReplaceCommand('#source-dependent', $form['source_dependent']));
67     return $response;
68   }
69
70   /**
71    * {@inheritdoc}
72    */
73   public function form(array $form, FormStateInterface $form_state) {
74     $form = parent::form($form, $form_state);
75
76     // Source is not set when the entity is initially created.
77     /** @var \Drupal\media\MediaSourceInterface $source */
78     $source = $this->entity->get('source') ? $this->entity->getSource() : NULL;
79
80     if ($this->operation === 'add') {
81       $form['#title'] = $this->t('Add media type');
82     }
83
84     $form['label'] = [
85       '#title' => $this->t('Name'),
86       '#type' => 'textfield',
87       '#default_value' => $this->entity->label(),
88       '#description' => $this->t('The human-readable name of this media type.'),
89       '#required' => TRUE,
90       '#size' => 30,
91     ];
92
93     $form['id'] = [
94       '#type' => 'machine_name',
95       '#default_value' => $this->entity->id(),
96       '#maxlength' => 32,
97       '#disabled' => !$this->entity->isNew(),
98       '#machine_name' => [
99         'exists' => [MediaType::class, 'load'],
100       ],
101       '#description' => $this->t('A unique machine-readable name for this media type.'),
102     ];
103
104     $form['description'] = [
105       '#title' => $this->t('Description'),
106       '#type' => 'textarea',
107       '#default_value' => $this->entity->getDescription(),
108       '#description' => $this->t('Describe this media type. The text will be displayed on the <em>Add new media</em> page.'),
109     ];
110
111     $plugins = $this->sourceManager->getDefinitions();
112     $options = [];
113     foreach ($plugins as $plugin_id => $definition) {
114       $options[$plugin_id] = $definition['label'];
115     }
116
117     $form['source_dependent'] = [
118       '#type' => 'container',
119       '#attributes' => ['id' => 'source-dependent'],
120     ];
121
122     if (!$this->entity->isNew()) {
123       $source_description = $this->t('<em>The media source cannot be changed after the media type is created.</em>');
124     }
125     else {
126       $source_description = $this->t('Media source that is responsible for additional logic related to this media type.');
127     }
128     $form['source_dependent']['source'] = [
129       '#type' => 'select',
130       '#title' => $this->t('Media source'),
131       '#default_value' => $source ? $source->getPluginId() : NULL,
132       '#options' => $options,
133       '#description' => $source_description,
134       '#ajax' => ['callback' => '::ajaxHandlerData'],
135       '#required' => TRUE,
136       // Once the media type is created, its source plugin cannot be changed
137       // anymore.
138       '#disabled' => !$this->entity->isNew(),
139     ];
140
141     if ($source) {
142       // Media source plugin configuration.
143       $form['source_dependent']['source_configuration'] = [
144         '#type' => 'fieldset',
145         '#title' => $this->t('Media source configuration'),
146         '#tree' => TRUE,
147       ];
148
149       $form['source_dependent']['source_configuration'] = $source->buildConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
150     }
151
152     // Field mapping configuration.
153     $form['source_dependent']['field_map'] = [
154       '#type' => 'fieldset',
155       '#title' => $this->t('Field mapping'),
156       '#tree' => TRUE,
157       'description' => [
158         '#markup' => '<p>' . $this->t('Media sources can provide metadata fields such as title, caption, size information, credits, etc. Media can automatically save this metadata information to entity fields, which can be configured below. Information will only be mapped if the entity field is empty.') . '</p>',
159       ],
160     ];
161
162     if (empty($source) || empty($source->getMetadataAttributes())) {
163       $form['source_dependent']['field_map']['#access'] = FALSE;
164     }
165     else {
166       $options = [MediaSourceInterface::METADATA_FIELD_EMPTY => $this->t('- Skip field -')];
167       foreach ($this->entityFieldManager->getFieldDefinitions('media', $this->entity->id()) as $field_name => $field) {
168         if (!($field instanceof BaseFieldDefinition) || $field_name === 'name') {
169           $options[$field_name] = $field->getLabel();
170         }
171       }
172
173       $field_map = $this->entity->getFieldMap();
174       foreach ($source->getMetadataAttributes() as $metadata_attribute_name => $metadata_attribute_label) {
175         $form['source_dependent']['field_map'][$metadata_attribute_name] = [
176           '#type' => 'select',
177           '#title' => $metadata_attribute_label,
178           '#options' => $options,
179           '#default_value' => isset($field_map[$metadata_attribute_name]) ? $field_map[$metadata_attribute_name] : MediaSourceInterface::METADATA_FIELD_EMPTY,
180         ];
181       }
182     }
183
184     $form['additional_settings'] = [
185       '#type' => 'vertical_tabs',
186       '#attached' => [
187         'library' => ['media/type_form'],
188       ],
189     ];
190
191     $form['workflow'] = [
192       '#type' => 'details',
193       '#title' => $this->t('Publishing options'),
194       '#group' => 'additional_settings',
195     ];
196
197     $form['workflow']['options'] = [
198       '#type' => 'checkboxes',
199       '#title' => $this->t('Default options'),
200       '#default_value' => $this->getWorkflowOptions(),
201       '#options' => [
202         'status' => $this->t('Published'),
203         'new_revision' => $this->t('Create new revision'),
204         'queue_thumbnail_downloads' => $this->t('Queue thumbnail downloads'),
205       ],
206     ];
207
208     $form['workflow']['options']['status']['#description'] = $this->t('Media will be automatically published when created.');
209     $form['workflow']['options']['new_revision']['#description'] = $this->t('Automatically create new revisions. Users with the "Administer media" permission will be able to override this option.');
210     $form['workflow']['options']['queue_thumbnail_downloads']['#description'] = $this->t('Download thumbnails via a queue. When using remote media sources, the thumbnail generation could be a slow process. Using a queue allows for this process to be handled in the background.');
211
212     if ($this->moduleHandler->moduleExists('language')) {
213       $form['language'] = [
214         '#type' => 'details',
215         '#title' => $this->t('Language settings'),
216         '#group' => 'additional_settings',
217       ];
218
219       $language_configuration = ContentLanguageSettings::loadByEntityTypeBundle('media', $this->entity->id());
220       $form['language']['language_configuration'] = [
221         '#type' => 'language_configuration',
222         '#entity_information' => [
223           'entity_type' => 'media',
224           'bundle' => $this->entity->id(),
225         ],
226         '#default_value' => $language_configuration,
227       ];
228     }
229
230     return $form;
231   }
232
233   /**
234    * Prepares workflow options to be used in the 'checkboxes' form element.
235    *
236    * @return array
237    *   Array of options ready to be used in #options.
238    */
239   protected function getWorkflowOptions() {
240     $workflow_options = [
241       'status' => $this->entity->getStatus(),
242       'new_revision' => $this->entity->shouldCreateNewRevision(),
243       'queue_thumbnail_downloads' => $this->entity->thumbnailDownloadsAreQueued(),
244     ];
245     // Prepare workflow options to be used for 'checkboxes' form element.
246     $keys = array_keys(array_filter($workflow_options));
247     return array_combine($keys, $keys);
248   }
249
250   /**
251    * Gets subform state for the media source configuration subform.
252    *
253    * @param array $form
254    *   Full form array.
255    * @param \Drupal\Core\Form\FormStateInterface $form_state
256    *   Parent form state.
257    *
258    * @return \Drupal\Core\Form\SubformStateInterface
259    *   Sub-form state for the media source configuration form.
260    */
261   protected function getSourceSubFormState(array $form, FormStateInterface $form_state) {
262     return SubformState::createForSubform($form['source_dependent']['source_configuration'], $form, $form_state)
263       ->set('operation', $this->operation)
264       ->set('type', $this->entity);
265   }
266
267   /**
268    * {@inheritdoc}
269    */
270   public function validateForm(array &$form, FormStateInterface $form_state) {
271     parent::validateForm($form, $form_state);
272
273     if (isset($form['source_dependent']['source_configuration'])) {
274       // Let the selected plugin validate its settings.
275       $this->entity->getSource()->validateConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
276     }
277   }
278
279   /**
280    * {@inheritdoc}
281    */
282   public function submitForm(array &$form, FormStateInterface $form_state) {
283     $form_state->setValue('field_map', array_filter(
284       $form_state->getValue('field_map', []),
285       function ($item) {
286         return $item != MediaSourceInterface::METADATA_FIELD_EMPTY;
287       }
288     ));
289
290     parent::submitForm($form, $form_state);
291
292     $this->entity->setQueueThumbnailDownloadsStatus((bool) $form_state->getValue(['options', 'queue_thumbnail_downloads']))
293       ->setStatus((bool) $form_state->getValue(['options', 'status']))
294       ->setNewRevision((bool) $form_state->getValue(['options', 'new_revision']));
295
296     if (isset($form['source_dependent']['source_configuration'])) {
297       // Let the selected plugin save its settings.
298       $this->entity->getSource()->submitConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
299     }
300   }
301
302   /**
303    * {@inheritdoc}
304    */
305   protected function actions(array $form, FormStateInterface $form_state) {
306     $actions = parent::actions($form, $form_state);
307     $actions['submit']['#value'] = $this->t('Save');
308     $actions['delete']['#value'] = $this->t('Delete');
309     $actions['delete']['#access'] = $this->entity->access('delete');
310     return $actions;
311   }
312
313   /**
314    * {@inheritdoc}
315    */
316   public function save(array $form, FormStateInterface $form_state) {
317     $status = parent::save($form, $form_state);
318     /** @var \Drupal\media\MediaTypeInterface $media_type */
319     $media_type = $this->entity;
320
321     // If the media source is using a source field, ensure it's
322     // properly created.
323     $source = $media_type->getSource();
324     $source_field = $source->getSourceFieldDefinition($media_type);
325     if (!$source_field) {
326       $source_field = $source->createSourceField($media_type);
327       /** @var \Drupal\field\FieldStorageConfigInterface $storage */
328       $storage = $source_field->getFieldStorageDefinition();
329       if ($storage->isNew()) {
330         $storage->save();
331       }
332       $source_field->save();
333
334       // Add the new field to the default form and view displays for this
335       // media type.
336       if ($source_field->isDisplayConfigurable('form')) {
337         // @todo Replace entity_get_form_display() when #2367933 is done.
338         // https://www.drupal.org/node/2872159.
339         $display = entity_get_form_display('media', $media_type->id(), 'default');
340         $source->prepareFormDisplay($media_type, $display);
341         $display->save();
342       }
343       if ($source_field->isDisplayConfigurable('view')) {
344         // @todo Replace entity_get_display() when #2367933 is done.
345         // https://www.drupal.org/node/2872159.
346         $display = entity_get_display('media', $media_type->id(), 'default');
347         $source->prepareViewDisplay($media_type, $display);
348         $display->save();
349       }
350     }
351
352     $t_args = ['%name' => $media_type->label()];
353     if ($status === SAVED_UPDATED) {
354       $this->messenger()->addStatus($this->t('The media type %name has been updated.', $t_args));
355     }
356     elseif ($status === SAVED_NEW) {
357       $this->messenger()->addStatus($this->t('The media type %name has been added.', $t_args));
358       $this->logger('media')->notice('Added media type %name.', $t_args);
359     }
360
361     // Override the "status" base field default value, for this media type.
362     $fields = $this->entityFieldManager->getFieldDefinitions('media', $media_type->id());
363     /** @var \Drupal\media\MediaInterface $media */
364     $media = $this->entityTypeManager->getStorage('media')->create(['bundle' => $media_type->id()]);
365     $value = (bool) $form_state->getValue(['options', 'status']);
366     if ($media->status->value != $value) {
367       $fields['status']->getConfig($media_type->id())->setDefaultValue($value)->save();
368     }
369
370     $form_state->setRedirectUrl($media_type->toUrl('collection'));
371   }
372
373 }