annotate core/modules/media_library/media_library.module @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@17 1 <?php
Chris@17 2
Chris@17 3 /**
Chris@17 4 * @file
Chris@17 5 * Contains hook implementations for the media_library module.
Chris@17 6 */
Chris@17 7
Chris@17 8 use Drupal\Component\Utility\UrlHelper;
Chris@18 9 use Drupal\Core\Access\AccessResult;
Chris@18 10 use Drupal\Core\Entity\EntityInterface;
Chris@18 11 use Drupal\Core\Entity\Entity\EntityFormDisplay;
Chris@18 12 use Drupal\Core\Entity\Entity\EntityViewDisplay;
Chris@17 13 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
Chris@17 14 use Drupal\Core\Form\FormStateInterface;
Chris@17 15 use Drupal\Core\Render\Element;
Chris@17 16 use Drupal\Core\Routing\RouteMatchInterface;
Chris@18 17 use Drupal\Core\Session\AccountInterface;
Chris@17 18 use Drupal\Core\Template\Attribute;
Chris@18 19 use Drupal\image\Entity\ImageStyle;
Chris@18 20 use Drupal\image\Plugin\Field\FieldType\ImageItem;
Chris@18 21 use Drupal\media\MediaTypeForm;
Chris@18 22 use Drupal\media\MediaTypeInterface;
Chris@18 23 use Drupal\media_library\Form\FileUploadForm;
Chris@18 24 use Drupal\media_library\Form\OEmbedForm;
Chris@18 25 use Drupal\media_library\MediaLibraryState;
Chris@17 26 use Drupal\views\Form\ViewsForm;
Chris@17 27 use Drupal\views\Plugin\views\cache\CachePluginBase;
Chris@17 28 use Drupal\views\ViewExecutable;
Chris@17 29
Chris@17 30 /**
Chris@17 31 * Implements hook_help().
Chris@17 32 *
Chris@17 33 * @todo Update in https://www.drupal.org/project/drupal/issues/2964789
Chris@17 34 */
Chris@17 35 function media_library_help($route_name, RouteMatchInterface $route_match) {
Chris@17 36 switch ($route_name) {
Chris@17 37 case 'help.page.media_library':
Chris@17 38 $output = '<h3>' . t('About') . '</h3>';
Chris@17 39 $output .= '<p>' . t('The Media library module overrides the /admin/content/media view to provide a rich visual interface for performing administrative operations on media. For more information, see the <a href=":media">online documentation for the Media library module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
Chris@17 40 return $output;
Chris@17 41 }
Chris@17 42 }
Chris@17 43
Chris@17 44 /**
Chris@18 45 * Implements hook_media_source_info_alter().
Chris@18 46 */
Chris@18 47 function media_library_media_source_info_alter(array &$sources) {
Chris@18 48 $sources['audio_file']['forms']['media_library_add'] = FileUploadForm::class;
Chris@18 49 $sources['file']['forms']['media_library_add'] = FileUploadForm::class;
Chris@18 50 $sources['image']['forms']['media_library_add'] = FileUploadForm::class;
Chris@18 51 $sources['video_file']['forms']['media_library_add'] = FileUploadForm::class;
Chris@18 52 $sources['oembed:video']['forms']['media_library_add'] = OEmbedForm::class;
Chris@18 53 }
Chris@18 54
Chris@18 55 /**
Chris@17 56 * Implements hook_theme().
Chris@17 57 */
Chris@17 58 function media_library_theme() {
Chris@17 59 return [
Chris@17 60 'media__media_library' => [
Chris@17 61 'base hook' => 'media',
Chris@17 62 ],
Chris@17 63 ];
Chris@17 64 }
Chris@17 65
Chris@17 66 /**
Chris@17 67 * Implements hook_views_post_render().
Chris@17 68 */
Chris@17 69 function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
Chris@17 70 if ($view->id() === 'media_library') {
Chris@17 71 $output['#attached']['library'][] = 'media_library/view';
Chris@18 72 if (strpos($view->current_display, 'widget') === 0) {
Chris@18 73 $query = MediaLibraryState::fromRequest($view->getRequest())->all();
Chris@17 74 // If the current query contains any parameters we use to contextually
Chris@17 75 // filter the view, ensure they persist across AJAX rebuilds.
Chris@17 76 // The ajax_path is shared for all AJAX views on the page, but our query
Chris@17 77 // parameters are prefixed and should not interfere with any other views.
Chris@17 78 // @todo Rework or remove this in https://www.drupal.org/node/2983451
Chris@17 79 if (!empty($query)) {
Chris@17 80 $ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
Chris@17 81 $parsed_url = UrlHelper::parse($ajax_path);
Chris@17 82 $query = array_merge($query, $parsed_url['query']);
Chris@17 83 $ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
Chris@17 84 }
Chris@17 85 }
Chris@17 86 }
Chris@17 87 }
Chris@17 88
Chris@17 89 /**
Chris@17 90 * Implements hook_preprocess_media().
Chris@17 91 */
Chris@17 92 function media_library_preprocess_media(&$variables) {
Chris@17 93 if ($variables['view_mode'] === 'media_library') {
Chris@17 94 /** @var \Drupal\media\MediaInterface $media */
Chris@17 95 $media = $variables['media'];
Chris@17 96 $variables['#cache']['contexts'][] = 'user.permissions';
Chris@17 97 $rel = $media->access('edit') ? 'edit-form' : 'canonical';
Chris@17 98 $variables['url'] = $media->toUrl($rel, [
Chris@17 99 'language' => $media->language(),
Chris@17 100 ]);
Chris@17 101 $variables['preview_attributes'] = new Attribute();
Chris@17 102 $variables['preview_attributes']->addClass('media-library-item__preview', 'js-media-library-item-preview', 'js-click-to-select-trigger');
Chris@17 103 $variables['metadata_attributes'] = new Attribute();
Chris@17 104 $variables['metadata_attributes']->addClass('media-library-item__attributes');
Chris@17 105 $variables['status'] = $media->isPublished();
Chris@17 106 }
Chris@17 107 }
Chris@17 108
Chris@17 109 /**
Chris@17 110 * Alter the bulk form to add a more accessible label.
Chris@17 111 *
Chris@17 112 * @param array $form
Chris@17 113 * An associative array containing the structure of the form.
Chris@17 114 * @param \Drupal\Core\Form\FormStateInterface $form_state
Chris@17 115 * The current state of the form.
Chris@17 116 *
Chris@17 117 * @todo Remove in https://www.drupal.org/node/2983454
Chris@17 118 */
Chris@17 119 function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
Chris@17 120 if (isset($form['media_bulk_form']) && isset($form['output'])) {
Chris@17 121 /** @var \Drupal\views\ViewExecutable $view */
Chris@17 122 $view = $form['output'][0]['#view'];
Chris@17 123 foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
Chris@17 124 if (isset($view->result[$key])) {
Chris@17 125 $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
Chris@17 126 $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
Chris@17 127 '@label' => $media->label(),
Chris@17 128 ]);
Chris@17 129 }
Chris@17 130 }
Chris@17 131 }
Chris@17 132 }
Chris@17 133
Chris@17 134 /**
Chris@17 135 * Implements hook_form_alter().
Chris@17 136 */
Chris@17 137 function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
Chris@17 138 $form_object = $form_state->getFormObject();
Chris@17 139 if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) {
Chris@17 140 $form['#attributes']['class'][] = 'media-library-views-form';
Chris@17 141 if (isset($form['header'])) {
Chris@17 142 $form['header']['#attributes']['class'][] = 'media-library-views-form__header';
Chris@17 143 $form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form';
Chris@17 144 }
Chris@17 145 }
Chris@17 146
Chris@17 147 // Add after build to fix media library views exposed filter's submit button.
Chris@18 148 if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) {
Chris@17 149 $form['#after_build'][] = '_media_library_views_form_media_library_after_build';
Chris@17 150 }
Chris@18 151
Chris@18 152 // Configures media_library displays when a type is submitted.
Chris@18 153 if ($form_object instanceof MediaTypeForm) {
Chris@18 154 $form['actions']['submit']['#submit'][] = '_media_library_media_type_form_submit';
Chris@18 155 }
Chris@17 156 }
Chris@17 157
Chris@17 158 /**
Chris@17 159 * After build callback for views form media library.
Chris@17 160 */
Chris@17 161 function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
Chris@17 162 // Remove .form-actions from media library views exposed filter actions
Chris@17 163 // and replace with .media-library-view--form-actions.
Chris@17 164 //
Chris@17 165 // This prevents the views exposed filter's 'Apply filter' submit button from
Chris@17 166 // being moved into the dialog's buttons.
Chris@17 167 // @see \Drupal\Core\Render\Element\Actions::processActions
Chris@17 168 // @see Drupal.behaviors.dialog.prepareDialogButtons
Chris@17 169 if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
Chris@17 170 unset($form['actions']['#attributes']['class'][$key]);
Chris@17 171 }
Chris@17 172 $form['actions']['#attributes']['class'][] = 'media-library-view--form-actions';
Chris@17 173 return $form;
Chris@17 174 }
Chris@17 175
Chris@17 176 /**
Chris@18 177 * Submit callback for media type form.
Chris@17 178 */
Chris@18 179 function _media_library_media_type_form_submit(array &$form, FormStateInterface $form_state) {
Chris@18 180 $form_object = $form_state->getFormObject();
Chris@18 181 if ($form_object->getOperation() === 'add') {
Chris@18 182 $type = $form_object->getEntity();
Chris@18 183 $form_display_created = _media_library_configure_form_display($type);
Chris@18 184 $view_display_created = _media_library_configure_view_display($type);
Chris@18 185 if ($form_display_created || $view_display_created) {
Chris@18 186 \Drupal::messenger()->addStatus(t('Media Library form and view displays have been created for the %type media type.', [
Chris@18 187 '%type' => $type->label(),
Chris@18 188 ]));
Chris@17 189 }
Chris@17 190 }
Chris@17 191 }
Chris@17 192
Chris@17 193 /**
Chris@17 194 * Implements hook_field_ui_preconfigured_options_alter().
Chris@17 195 */
Chris@17 196 function media_library_field_ui_preconfigured_options_alter(array &$options, $field_type) {
Chris@17 197 // If the field is not an "entity_reference"-based field, bail out.
Chris@17 198 $class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_type);
Chris@17 199 if (!is_a($class, EntityReferenceItem::class, TRUE)) {
Chris@17 200 return;
Chris@17 201 }
Chris@17 202
Chris@17 203 // Set the default field widget for media to be the Media library.
Chris@17 204 if (!empty($options['media'])) {
Chris@17 205 $options['media']['entity_form_display']['type'] = 'media_library_widget';
Chris@17 206 }
Chris@17 207 }
Chris@17 208
Chris@17 209 /**
Chris@17 210 * Implements hook_local_tasks_alter().
Chris@17 211 *
Chris@17 212 * Removes tasks for the Media library if the view display no longer exists.
Chris@17 213 */
Chris@17 214 function media_library_local_tasks_alter(&$local_tasks) {
Chris@17 215 /** @var \Symfony\Component\Routing\RouteCollection $route_collection */
Chris@17 216 $route_collection = \Drupal::service('router')->getRouteCollection();
Chris@17 217 foreach (['media_library.grid', 'media_library.table'] as $key) {
Chris@17 218 if (isset($local_tasks[$key]) && !$route_collection->get($local_tasks[$key]['route_name'])) {
Chris@17 219 unset($local_tasks[$key]);
Chris@17 220 }
Chris@17 221 }
Chris@17 222 }
Chris@17 223
Chris@17 224 /**
Chris@18 225 * Implements hook_ENTITY_TYPE_access().
Chris@18 226 */
Chris@18 227 function media_library_image_style_access(EntityInterface $entity, $operation, AccountInterface $account) {
Chris@18 228 // Prevent the fallback 'media_library' image style from being deleted.
Chris@18 229 // @todo: Lock the image style instead of preventing delete access.
Chris@18 230 // https://www.drupal.org/project/drupal/issues/2247293
Chris@18 231 if ($operation === 'delete' && $entity->id() === 'media_library') {
Chris@18 232 return AccessResult::forbidden();
Chris@18 233 }
Chris@18 234 }
Chris@18 235
Chris@18 236 /**
Chris@18 237 * Ensures that the given media type has a media_library form display.
Chris@17 238 *
Chris@18 239 * @param \Drupal\media\MediaTypeInterface $type
Chris@18 240 * The media type to configure.
Chris@18 241 *
Chris@18 242 * @return bool
Chris@18 243 * Whether a form display has been created or not.
Chris@18 244 *
Chris@18 245 * @throws \Drupal\Core\Entity\EntityStorageException
Chris@17 246 */
Chris@18 247 function _media_library_configure_form_display(MediaTypeInterface $type) {
Chris@18 248 $display = EntityFormDisplay::load('media.' . $type->id() . '.media_library');
Chris@18 249
Chris@18 250 if ($display) {
Chris@18 251 return FALSE;
Chris@17 252 }
Chris@18 253
Chris@18 254 $values = [
Chris@18 255 'targetEntityType' => 'media',
Chris@18 256 'bundle' => $type->id(),
Chris@18 257 'mode' => 'media_library',
Chris@18 258 'status' => TRUE,
Chris@18 259 ];
Chris@18 260 $display = EntityFormDisplay::create($values);
Chris@18 261 // Remove all default components.
Chris@18 262 foreach (array_keys($display->getComponents()) as $name) {
Chris@18 263 $display->removeComponent($name);
Chris@18 264 }
Chris@18 265 // Expose the name field when it is not mapped.
Chris@18 266 $field_map = $type->getFieldMap();
Chris@18 267 if (empty($field_map['name'])) {
Chris@18 268 $display->setComponent('name', [
Chris@18 269 'type' => 'string_textfield',
Chris@18 270 'settings' => [
Chris@18 271 'size' => 60,
Chris@18 272 ],
Chris@18 273 ]);
Chris@18 274 }
Chris@18 275 // If the source field is an image field, expose it so that users can set alt
Chris@18 276 // and title text.
Chris@18 277 $source_field = $type->getSource()->getSourceFieldDefinition($type);
Chris@18 278 if ($source_field->isDisplayConfigurable('form') && is_a($source_field->getItemDefinition()->getClass(), ImageItem::class, TRUE)) {
Chris@18 279 $type->getSource()->prepareFormDisplay($type, $display);
Chris@18 280 }
Chris@18 281 return (bool) $display->save();
Chris@17 282 }
Chris@18 283
Chris@18 284 /**
Chris@18 285 * Ensures that the given media type has a media_library view display.
Chris@18 286 *
Chris@18 287 * @param \Drupal\media\MediaTypeInterface $type
Chris@18 288 * The media type to configure.
Chris@18 289 *
Chris@18 290 * @return bool
Chris@18 291 * Whether a view display has been created or not.
Chris@18 292 *
Chris@18 293 * @throws \Drupal\Core\Entity\EntityStorageException
Chris@18 294 */
Chris@18 295 function _media_library_configure_view_display(MediaTypeInterface $type) {
Chris@18 296 $display = EntityViewDisplay::load('media.' . $type->id() . '.media_library');
Chris@18 297
Chris@18 298 if ($display) {
Chris@18 299 return FALSE;
Chris@18 300 }
Chris@18 301
Chris@18 302 $values = [
Chris@18 303 'targetEntityType' => 'media',
Chris@18 304 'bundle' => $type->id(),
Chris@18 305 'mode' => 'media_library',
Chris@18 306 'status' => TRUE,
Chris@18 307 ];
Chris@18 308 $display = EntityViewDisplay::create($values);
Chris@18 309 // Remove all default components.
Chris@18 310 foreach (array_keys($display->getComponents()) as $name) {
Chris@18 311 $display->removeComponent($name);
Chris@18 312 }
Chris@18 313
Chris@18 314 // @todo: Remove dependency on 'medium' and 'thumbnail' image styles from
Chris@18 315 // media and media library modules.
Chris@18 316 // https://www.drupal.org/project/drupal/issues/3030437
Chris@18 317 $image_style = ImageStyle::load('medium');
Chris@18 318
Chris@18 319 // Expose the thumbnail component. If the medium image style doesn't exist,
Chris@18 320 // use the fallback 'media_library' image style.
Chris@18 321 $display->setComponent('thumbnail', [
Chris@18 322 'type' => 'image',
Chris@18 323 'label' => 'hidden',
Chris@18 324 'settings' => [
Chris@18 325 'image_style' => $image_style ? $image_style->id() : 'media_library',
Chris@18 326 'image_link' => '',
Chris@18 327 ],
Chris@18 328 ]);
Chris@18 329 return (bool) $display->save();
Chris@18 330 }