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