3 namespace Drupal\media;
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;
17 * Form controller for media type forms.
21 class MediaTypeForm extends EntityForm {
24 * Media source plugin manager.
26 * @var \Drupal\media\MediaSourceManager
28 protected $sourceManager;
31 * Entity field manager service.
33 * @var \Drupal\Core\Entity\EntityFieldManagerInterface
35 protected $entityFieldManager;
38 * Constructs a new class instance.
40 * @param \Drupal\media\MediaSourceManager $source_manager
41 * Media source plugin manager.
42 * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
43 * Entity field manager service.
45 public function __construct(MediaSourceManager $source_manager, EntityFieldManagerInterface $entity_field_manager) {
46 $this->sourceManager = $source_manager;
47 $this->entityFieldManager = $entity_field_manager;
53 public static function create(ContainerInterface $container) {
55 $container->get('plugin.manager.media.source'),
56 $container->get('entity_field.manager')
61 * Ajax callback triggered by the type provider select element.
63 public function ajaxHandlerData(array $form, FormStateInterface $form_state) {
64 $response = new AjaxResponse();
65 $response->addCommand(new ReplaceCommand('#source-dependent', $form['source_dependent']));
72 public function form(array $form, FormStateInterface $form_state) {
73 $form = parent::form($form, $form_state);
75 // Source is not set when the entity is initially created.
76 /** @var \Drupal\media\MediaSourceInterface $source */
77 $source = $this->entity->get('source') ? $this->entity->getSource() : NULL;
79 if ($this->operation === 'add') {
80 $form['#title'] = $this->t('Add media type');
84 '#title' => $this->t('Name'),
85 '#type' => 'textfield',
86 '#default_value' => $this->entity->label(),
87 '#description' => $this->t('The human-readable name of this media type.'),
93 '#type' => 'machine_name',
94 '#default_value' => $this->entity->id(),
96 '#disabled' => !$this->entity->isNew(),
98 'exists' => [MediaType::class, 'load'],
100 '#description' => $this->t('A unique machine-readable name for this media type.'),
103 $form['description'] = [
104 '#title' => $this->t('Description'),
105 '#type' => 'textarea',
106 '#default_value' => $this->entity->getDescription(),
107 '#description' => $this->t('Describe this media type. The text will be displayed on the <em>Add new media</em> page.'),
110 $plugins = $this->sourceManager->getDefinitions();
112 foreach ($plugins as $plugin_id => $definition) {
113 $options[$plugin_id] = $definition['label'];
116 $form['source_dependent'] = [
117 '#type' => 'container',
118 '#attributes' => ['id' => 'source-dependent'],
122 $source_description = $this->t('<em>The media source cannot be changed after the media type is created.</em>');
125 $source_description = $this->t('Media source that is responsible for additional logic related to this media type.');
127 $form['source_dependent']['source'] = [
129 '#title' => $this->t('Media source'),
130 '#default_value' => $source ? $source->getPluginId() : NULL,
131 '#options' => $options,
132 '#description' => $source_description,
133 '#ajax' => ['callback' => '::ajaxHandlerData'],
134 // Rebuilding the form as part of the AJAX request is a workaround to
135 // enforce machine_name validation.
136 // @todo This was added as part of #2932226 and it should be removed once
137 // https://www.drupal.org/project/drupal/issues/2557299 solves it in a
139 '#executes_submit_callback' => TRUE,
140 '#submit' => [[static::class, 'rebuildSubmit']],
142 // Once the media type is created, its source plugin cannot be changed
144 '#disabled' => !empty($source),
148 $form['type']['#empty_option'] = $this->t('- Select media source -');
152 // Media source plugin configuration.
153 $form['source_dependent']['source_configuration'] = [
154 '#type' => 'fieldset',
155 '#title' => $this->t('Media source configuration'),
159 $form['source_dependent']['source_configuration'] = $source->buildConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
162 // Field mapping configuration.
163 $form['source_dependent']['field_map'] = [
164 '#type' => 'fieldset',
165 '#title' => $this->t('Field mapping'),
168 '#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>',
172 if (empty($source) || empty($source->getMetadataAttributes())) {
173 $form['source_dependent']['field_map']['#access'] = FALSE;
176 $options = [MediaSourceInterface::METADATA_FIELD_EMPTY => $this->t('- Skip field -')];
177 foreach ($this->entityFieldManager->getFieldDefinitions('media', $this->entity->id()) as $field_name => $field) {
178 if (!($field instanceof BaseFieldDefinition) || $field_name === 'name') {
179 $options[$field_name] = $field->getLabel();
183 $field_map = $this->entity->getFieldMap();
184 foreach ($source->getMetadataAttributes() as $metadata_attribute_name => $metadata_attribute_label) {
185 $form['source_dependent']['field_map'][$metadata_attribute_name] = [
187 '#title' => $metadata_attribute_label,
188 '#options' => $options,
189 '#default_value' => isset($field_map[$metadata_attribute_name]) ? $field_map[$metadata_attribute_name] : MediaSourceInterface::METADATA_FIELD_EMPTY,
194 $form['additional_settings'] = [
195 '#type' => 'vertical_tabs',
197 'library' => ['media/type_form'],
201 $form['workflow'] = [
202 '#type' => 'details',
203 '#title' => $this->t('Publishing options'),
204 '#group' => 'additional_settings',
207 $form['workflow']['options'] = [
208 '#type' => 'checkboxes',
209 '#title' => $this->t('Default options'),
210 '#default_value' => $this->getWorkflowOptions(),
212 'status' => $this->t('Published'),
213 'new_revision' => $this->t('Create new revision'),
214 'queue_thumbnail_downloads' => $this->t('Queue thumbnail downloads'),
218 $form['workflow']['options']['status']['#description'] = $this->t('Media will be automatically published when created.');
219 $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.');
220 $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.');
222 if ($this->moduleHandler->moduleExists('language')) {
223 $form['language'] = [
224 '#type' => 'details',
225 '#title' => $this->t('Language settings'),
226 '#group' => 'additional_settings',
229 $language_configuration = ContentLanguageSettings::loadByEntityTypeBundle('media', $this->entity->id());
230 $form['language']['language_configuration'] = [
231 '#type' => 'language_configuration',
232 '#entity_information' => [
233 'entity_type' => 'media',
234 'bundle' => $this->entity->id(),
236 '#default_value' => $language_configuration,
244 * Form submission handler to rebuild the form on select submit.
248 * @param \Drupal\Core\Form\FormStateInterface $form_state
249 * Current form state.
251 public static function rebuildSubmit(array &$form, FormStateInterface $form_state) {
252 $form_state->setRebuild();
256 * Prepares workflow options to be used in the 'checkboxes' form element.
259 * Array of options ready to be used in #options.
261 protected function getWorkflowOptions() {
262 $workflow_options = [
263 'status' => $this->entity->getStatus(),
264 'new_revision' => $this->entity->shouldCreateNewRevision(),
265 'queue_thumbnail_downloads' => $this->entity->thumbnailDownloadsAreQueued(),
267 // Prepare workflow options to be used for 'checkboxes' form element.
268 $keys = array_keys(array_filter($workflow_options));
269 return array_combine($keys, $keys);
273 * Gets subform state for the media source configuration subform.
277 * @param \Drupal\Core\Form\FormStateInterface $form_state
280 * @return \Drupal\Core\Form\SubformStateInterface
281 * Sub-form state for the media source configuration form.
283 protected function getSourceSubFormState(array $form, FormStateInterface $form_state) {
284 return SubformState::createForSubform($form['source_dependent']['source_configuration'], $form, $form_state)
285 ->set('operation', $this->operation)
286 ->set('type', $this->entity);
292 public function validateForm(array &$form, FormStateInterface $form_state) {
293 parent::validateForm($form, $form_state);
295 if (isset($form['source_dependent']['source_configuration'])) {
296 // Let the selected plugin validate its settings.
297 $this->entity->getSource()->validateConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
304 public function submitForm(array &$form, FormStateInterface $form_state) {
305 $form_state->setValue('field_map', array_filter(
306 $form_state->getValue('field_map', []),
308 return $item != MediaSourceInterface::METADATA_FIELD_EMPTY;
312 parent::submitForm($form, $form_state);
314 $this->entity->setQueueThumbnailDownloadsStatus((bool) $form_state->getValue(['options', 'queue_thumbnail_downloads']))
315 ->setStatus((bool) $form_state->getValue(['options', 'status']))
316 ->setNewRevision((bool) $form_state->getValue(['options', 'new_revision']));
318 if (isset($form['source_dependent']['source_configuration'])) {
319 // Let the selected plugin save its settings.
320 $this->entity->getSource()->submitConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
327 protected function actions(array $form, FormStateInterface $form_state) {
328 $actions = parent::actions($form, $form_state);
329 $actions['submit']['#value'] = $this->t('Save');
330 $actions['delete']['#value'] = $this->t('Delete');
331 $actions['delete']['#access'] = $this->entity->access('delete');
338 public function save(array $form, FormStateInterface $form_state) {
339 $status = parent::save($form, $form_state);
340 /** @var \Drupal\media\MediaTypeInterface $media_type */
341 $media_type = $this->entity;
343 // If the media source is using a source field, ensure it's
345 $source = $media_type->getSource();
346 $source_field = $source->getSourceFieldDefinition($media_type);
347 if (!$source_field) {
348 $source_field = $source->createSourceField($media_type);
349 /** @var \Drupal\field\FieldStorageConfigInterface $storage */
350 $storage = $source_field->getFieldStorageDefinition();
351 if ($storage->isNew()) {
354 $source_field->save();
356 // Add the new field to the default form and view displays for this
358 if ($source_field->isDisplayConfigurable('form')) {
359 // @todo Replace entity_get_form_display() when #2367933 is done.
360 // https://www.drupal.org/node/2872159.
361 $display = entity_get_form_display('media', $media_type->id(), 'default');
362 $source->prepareFormDisplay($media_type, $display);
365 if ($source_field->isDisplayConfigurable('view')) {
366 // @todo Replace entity_get_display() when #2367933 is done.
367 // https://www.drupal.org/node/2872159.
368 $display = entity_get_display('media', $media_type->id(), 'default');
369 $source->prepareViewDisplay($media_type, $display);
374 $t_args = ['%name' => $media_type->label()];
375 if ($status === SAVED_UPDATED) {
376 drupal_set_message($this->t('The media type %name has been updated.', $t_args));
378 elseif ($status === SAVED_NEW) {
379 drupal_set_message($this->t('The media type %name has been added.', $t_args));
380 $this->logger('media')->notice('Added media type %name.', $t_args);
383 // Override the "status" base field default value, for this media type.
384 $fields = $this->entityFieldManager->getFieldDefinitions('media', $media_type->id());
385 /** @var \Drupal\media\MediaInterface $media */
386 $media = $this->entityTypeManager->getStorage('media')->create(['bundle' => $media_type->id()]);
387 $value = (bool) $form_state->getValue(['options', 'status']);
388 if ($media->status->value != $value) {
389 $fields['status']->getConfig($media_type->id())->setDefaultValue($value)->save();
392 $form_state->setRedirectUrl($media_type->toUrl('collection'));