upgrades core to 8.4.2
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\media\MediaInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Provides an access checker for media item revisions.
|
||||
*
|
||||
* @ingroup media_access
|
||||
*/
|
||||
class MediaRevisionAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* The media storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityStorageInterface
|
||||
*/
|
||||
protected $mediaStorage;
|
||||
|
||||
/**
|
||||
* The media access control handler.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityAccessControlHandlerInterface
|
||||
*/
|
||||
protected $mediaAccess;
|
||||
|
||||
/**
|
||||
* A static cache of access checks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $access = [];
|
||||
|
||||
/**
|
||||
* Constructs a new MediaRevisionAccessCheck.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->mediaStorage = $entity_type_manager->getStorage('media');
|
||||
$this->mediaAccess = $entity_type_manager->getAccessControlHandler('media');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks routing access for the media item revision.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
* @param int $media_revision
|
||||
* (optional) The media item revision ID. If not specified, but $media is,
|
||||
* access is checked for that object's revision.
|
||||
* @param \Drupal\media\MediaInterface $media
|
||||
* (optional) A media item. Used for checking access to a media items
|
||||
* default revision when $media_revision is unspecified. Ignored when
|
||||
* $media_revision is specified. If neither $media_revision nor $media are
|
||||
* specified, then access is denied.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(Route $route, AccountInterface $account, $media_revision = NULL, MediaInterface $media = NULL) {
|
||||
if ($media_revision) {
|
||||
$media = $this->mediaStorage->loadRevision($media_revision);
|
||||
}
|
||||
$operation = $route->getRequirement('_access_media_revision');
|
||||
return AccessResult::allowedIf($media && $this->checkAccess($media, $account, $operation))->cachePerPermissions()->addCacheableDependency($media);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks media item revision access.
|
||||
*
|
||||
* @param \Drupal\media\MediaInterface $media
|
||||
* The media item to check.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* A user object representing the user for whom the operation is to be
|
||||
* performed.
|
||||
* @param string $op
|
||||
* (optional) The specific operation being checked. Defaults to 'view'.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the operation may be performed, FALSE otherwise.
|
||||
*/
|
||||
public function checkAccess(MediaInterface $media, AccountInterface $account, $op = 'view') {
|
||||
if (!$media || $op !== 'view') {
|
||||
// If there was no media to check against, or the $op was not one of the
|
||||
// supported ones, we return access denied.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Statically cache access by revision ID, language code, user account ID,
|
||||
// and operation.
|
||||
$langcode = $media->language()->getId();
|
||||
$cid = $media->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $op;
|
||||
|
||||
if (!isset($this->access[$cid])) {
|
||||
// Perform basic permission checks first.
|
||||
if (!$account->hasPermission('view all media revisions') && !$account->hasPermission('administer media')) {
|
||||
$this->access[$cid] = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// There should be at least two revisions. If the revision ID of the
|
||||
// given media item and the revision ID of the default revision differ,
|
||||
// then we already have two different revisions so there is no need for a
|
||||
// separate database check.
|
||||
if ($media->isDefaultRevision() && ($this->countDefaultLanguageRevisions($media) == 1)) {
|
||||
$this->access[$cid] = FALSE;
|
||||
}
|
||||
elseif ($account->hasPermission('administer media')) {
|
||||
$this->access[$cid] = TRUE;
|
||||
}
|
||||
else {
|
||||
// First check the access to the default revision and finally, if the
|
||||
// media passed in is not the default revision then access to that, too.
|
||||
$this->access[$cid] = $this->mediaAccess->access($this->mediaStorage->load($media->id()), $op, $account) && ($media->isDefaultRevision() || $this->mediaAccess->access($media, $op, $account));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->access[$cid];
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of revisions in the default language.
|
||||
*
|
||||
* @param \Drupal\media\MediaInterface $media
|
||||
* The media item for which to to count the revisions.
|
||||
*
|
||||
* @return int
|
||||
* The number of revisions in the default language.
|
||||
*/
|
||||
protected function countDefaultLanguageRevisions(MediaInterface $media) {
|
||||
$entity_type = $media->getEntityType();
|
||||
$count = $this->mediaStorage->getQuery()
|
||||
->allRevisions()
|
||||
->condition($entity_type->getKey('id'), $media->id())
|
||||
->condition($entity_type->getKey('default_langcode'), 1)
|
||||
->count()
|
||||
->execute();
|
||||
return $count;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines a media source plugin annotation object.
|
||||
*
|
||||
* Media sources are responsible for implementing all the logic for dealing
|
||||
* with a particular type of media. They provide various universal and
|
||||
* type-specific metadata about media of the type they handle.
|
||||
*
|
||||
* Plugin namespace: Plugin\media\Source
|
||||
*
|
||||
* For a working example, see \Drupal\media\Plugin\media\Source\File.
|
||||
*
|
||||
* @see \Drupal\media\MediaSourceInterface
|
||||
* @see \Drupal\media\MediaSourceBase
|
||||
* @see \Drupal\media\MediaSourceManager
|
||||
* @see hook_media_source_info_alter()
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class MediaSource extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the media source.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* A brief description of the media source.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $description = '';
|
||||
|
||||
/**
|
||||
* The field types that can be used as a source field for this media source.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $allowed_field_types = [];
|
||||
|
||||
/**
|
||||
* A filename for the default thumbnail.
|
||||
*
|
||||
* The thumbnails are placed in the directory defined by the config setting
|
||||
* 'media.settings.icon_base_uri'. When using custom icons, make sure the
|
||||
* module provides a hook_install() implementation to copy the custom icons
|
||||
* to this directory. The media_install() function provides a clear example
|
||||
* of how to do this.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @see media_install()
|
||||
*/
|
||||
public $default_thumbnail_filename = 'generic.png';
|
||||
|
||||
/**
|
||||
* The metadata attribute name to provide the thumbnail URI.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $thumbnail_uri_metadata_attribute = 'thumbnail_uri';
|
||||
|
||||
/**
|
||||
* (optional) The metadata attribute name to provide the thumbnail alt.
|
||||
*
|
||||
* "Thumbnail" will be used if the attribute name is not provided.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $thumbnail_alt_metadata_attribute;
|
||||
|
||||
/**
|
||||
* (optional) The metadata attribute name to provide the thumbnail title.
|
||||
*
|
||||
* The name of the media entity will be used if the attribute name is not
|
||||
* provided.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $thumbnail_title_metadata_attribute;
|
||||
|
||||
/**
|
||||
* The metadata attribute name to provide the default name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $default_name_metadata_attribute = 'default_name';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Entity;
|
||||
|
||||
use Drupal\Core\Entity\EditorialContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\media\MediaInterface;
|
||||
use Drupal\media\MediaSourceEntityConstraintsInterface;
|
||||
use Drupal\media\MediaSourceFieldConstraintsInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Defines the media entity class.
|
||||
*
|
||||
* @todo Remove default/fallback entity form operation when #2006348 is done.
|
||||
* @see https://www.drupal.org/node/2006348.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "media",
|
||||
* label = @Translation("Media"),
|
||||
* label_singular = @Translation("media item"),
|
||||
* label_plural = @Translation("media items"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count media item",
|
||||
* plural = "@count media items"
|
||||
* ),
|
||||
* bundle_label = @Translation("Media type"),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
|
||||
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
|
||||
* "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
|
||||
* "access" = "Drupal\media\MediaAccessControlHandler",
|
||||
* "form" = {
|
||||
* "default" = "Drupal\media\MediaForm",
|
||||
* "add" = "Drupal\media\MediaForm",
|
||||
* "edit" = "Drupal\media\MediaForm",
|
||||
* "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
|
||||
* },
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler",
|
||||
* "views_data" = "Drupal\media\MediaViewsData",
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
|
||||
* }
|
||||
* },
|
||||
* base_table = "media",
|
||||
* data_table = "media_field_data",
|
||||
* revision_table = "media_revision",
|
||||
* revision_data_table = "media_field_revision",
|
||||
* translatable = TRUE,
|
||||
* show_revision_ui = TRUE,
|
||||
* entity_keys = {
|
||||
* "id" = "mid",
|
||||
* "revision" = "vid",
|
||||
* "bundle" = "bundle",
|
||||
* "label" = "name",
|
||||
* "langcode" = "langcode",
|
||||
* "uuid" = "uuid",
|
||||
* "published" = "status",
|
||||
* },
|
||||
* revision_metadata_keys = {
|
||||
* "revision_user" = "revision_user",
|
||||
* "revision_created" = "revision_created",
|
||||
* "revision_log_message" = "revision_log_message",
|
||||
* },
|
||||
* bundle_entity_type = "media_type",
|
||||
* permission_granularity = "entity_type",
|
||||
* admin_permission = "administer media",
|
||||
* field_ui_base_route = "entity.media_type.edit_form",
|
||||
* common_reference_target = TRUE,
|
||||
* links = {
|
||||
* "add-page" = "/media/add",
|
||||
* "add-form" = "/media/add/{media_type}",
|
||||
* "canonical" = "/media/{media}",
|
||||
* "delete-form" = "/media/{media}/delete",
|
||||
* "edit-form" = "/media/{media}/edit",
|
||||
* "revision" = "/media/{media}/revisions/{media_revision}/view",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Media extends EditorialContentEntityBase implements MediaInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName() {
|
||||
$name = $this->get('name');
|
||||
|
||||
if ($name->isEmpty()) {
|
||||
$media_source = $this->getSource();
|
||||
return $media_source->getMetadata($this, $media_source->getPluginDefinition()['default_name_metadata_attribute']);
|
||||
}
|
||||
else {
|
||||
return $name->value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function label() {
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setName($name) {
|
||||
return $this->set('name', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCreatedTime() {
|
||||
return $this->get('created')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCreatedTime($timestamp) {
|
||||
return $this->set('created', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOwner() {
|
||||
return $this->get('uid')->entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOwner(UserInterface $account) {
|
||||
return $this->set('uid', $account->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOwnerId() {
|
||||
return $this->get('uid')->target_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOwnerId($uid) {
|
||||
return $this->set('uid', $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSource() {
|
||||
return $this->bundle->entity->getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the thumbnail for the media item.
|
||||
*
|
||||
* @param bool $from_queue
|
||||
* Specifies whether the thumbnail update is triggered from the queue.
|
||||
*
|
||||
* @return \Drupal\media\MediaInterface
|
||||
* The updated media item.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @todo There has been some disagreement about how to handle updates to
|
||||
* thumbnails. We need to decide on what the API will be for this.
|
||||
* https://www.drupal.org/node/2878119
|
||||
*/
|
||||
protected function updateThumbnail($from_queue = FALSE) {
|
||||
$file_storage = \Drupal::service('entity_type.manager')->getStorage('file');
|
||||
$thumbnail_uri = $this->getThumbnailUri($from_queue);
|
||||
$existing = $file_storage->getQuery()
|
||||
->condition('uri', $thumbnail_uri)
|
||||
->execute();
|
||||
|
||||
if ($existing) {
|
||||
$this->thumbnail->target_id = reset($existing);
|
||||
}
|
||||
else {
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file = $file_storage->create(['uri' => $thumbnail_uri]);
|
||||
if ($owner = $this->getOwner()) {
|
||||
$file->setOwner($owner);
|
||||
}
|
||||
$file->setPermanent();
|
||||
$file->save();
|
||||
$this->thumbnail->target_id = $file->id();
|
||||
}
|
||||
|
||||
// Set the thumbnail alt.
|
||||
$media_source = $this->getSource();
|
||||
$plugin_definition = $media_source->getPluginDefinition();
|
||||
if (!empty($plugin_definition['thumbnail_alt_metadata_attribute'])) {
|
||||
$this->thumbnail->alt = $media_source->getMetadata($this, $plugin_definition['thumbnail_alt_metadata_attribute']);
|
||||
}
|
||||
else {
|
||||
$this->thumbnail->alt = $this->t('Thumbnail', [], ['langcode' => $this->langcode->value]);
|
||||
}
|
||||
|
||||
// Set the thumbnail title.
|
||||
if (!empty($plugin_definition['thumbnail_title_metadata_attribute'])) {
|
||||
$this->thumbnail->title = $media_source->getMetadata($this, $plugin_definition['thumbnail_title_metadata_attribute']);
|
||||
}
|
||||
else {
|
||||
$this->thumbnail->title = $this->label();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the queued thumbnail for the media item.
|
||||
*
|
||||
* @return \Drupal\media\MediaInterface
|
||||
* The updated media item.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @todo If the need arises in contrib, consider making this a public API,
|
||||
* by adding an interface that extends MediaInterface.
|
||||
*/
|
||||
public function updateQueuedThumbnail() {
|
||||
$this->updateThumbnail(TRUE);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI for the thumbnail of a media item.
|
||||
*
|
||||
* If thumbnail fetching is queued, new media items will use the default
|
||||
* thumbnail, and existing media items will use the current thumbnail, until
|
||||
* the queue is processed and the updated thumbnail has been fetched.
|
||||
* Otherwise, the new thumbnail will be fetched immediately.
|
||||
*
|
||||
* @param bool $from_queue
|
||||
* Specifies whether the thumbnail is being fetched from the queue.
|
||||
*
|
||||
* @return string
|
||||
* The file URI for the thumbnail of the media item.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function getThumbnailUri($from_queue) {
|
||||
$thumbnails_queued = $this->bundle->entity->thumbnailDownloadsAreQueued();
|
||||
if ($thumbnails_queued && $this->isNew()) {
|
||||
$default_thumbnail_filename = $this->getSource()->getPluginDefinition()['default_thumbnail_filename'];
|
||||
$thumbnail_uri = \Drupal::service('config.factory')->get('media.settings')->get('icon_base_uri') . '/' . $default_thumbnail_filename;
|
||||
}
|
||||
elseif ($thumbnails_queued && !$from_queue) {
|
||||
$thumbnail_uri = $this->get('thumbnail')->entity->getFileUri();
|
||||
}
|
||||
else {
|
||||
$thumbnail_uri = $this->getSource()->getMetadata($this, $this->getSource()->getPluginDefinition()['thumbnail_uri_metadata_attribute']);
|
||||
}
|
||||
|
||||
return $thumbnail_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the source field value has changed.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the source field value changed, FALSE otherwise.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function hasSourceFieldChanged() {
|
||||
$source_field_name = $this->getSource()->getConfiguration()['source_field'];
|
||||
$current_items = $this->get($source_field_name);
|
||||
return isset($this->original) && !$current_items->equals($this->original->get($source_field_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the thumbnail should be updated for a media item.
|
||||
*
|
||||
* @param bool $is_new
|
||||
* Specifies whether the media item is new.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the thumbnail should be updated, FALSE otherwise.
|
||||
*/
|
||||
protected function shouldUpdateThumbnail($is_new = FALSE) {
|
||||
// Update thumbnail if we don't have a thumbnail yet or when the source
|
||||
// field value changes.
|
||||
return !$this->get('thumbnail')->entity || $is_new || $this->hasSourceFieldChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
|
||||
$media_source = $this->getSource();
|
||||
foreach ($this->translations as $langcode => $data) {
|
||||
if ($this->hasTranslation($langcode)) {
|
||||
$translation = $this->getTranslation($langcode);
|
||||
// Try to set fields provided by the media source and mapped in
|
||||
// media type config.
|
||||
foreach ($translation->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) {
|
||||
// Only save value in entity field if empty. Do not overwrite existing
|
||||
// data.
|
||||
if ($translation->hasField($entity_field_name) && ($translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged())) {
|
||||
$translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
|
||||
}
|
||||
}
|
||||
|
||||
// Try to set a default name for this media item if no name is provided.
|
||||
if ($translation->get('name')->isEmpty()) {
|
||||
$translation->setName($translation->getName());
|
||||
}
|
||||
|
||||
// Set thumbnail.
|
||||
if ($translation->shouldUpdateThumbnail()) {
|
||||
$translation->updateThumbnail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
parent::postSave($storage, $update);
|
||||
$is_new = !$update;
|
||||
foreach ($this->translations as $langcode => $data) {
|
||||
if ($this->hasTranslation($langcode)) {
|
||||
$translation = $this->getTranslation($langcode);
|
||||
if ($translation->bundle->entity->thumbnailDownloadsAreQueued() && $translation->shouldUpdateThumbnail($is_new)) {
|
||||
\Drupal::queue('media_entity_thumbnail')->createItem(['id' => $translation->id()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) {
|
||||
parent::preSaveRevision($storage, $record);
|
||||
|
||||
$is_new_revision = $this->isNewRevision();
|
||||
if (!$is_new_revision && isset($this->original) && empty($record->revision_log_message)) {
|
||||
// If we are updating an existing media item without adding a
|
||||
// new revision, we need to make sure $entity->revision_log_message is
|
||||
// reset whenever it is empty.
|
||||
// Therefore, this code allows us to avoid clobbering an existing log
|
||||
// entry with an empty one.
|
||||
$record->revision_log_message = $this->original->revision_log_message->value;
|
||||
}
|
||||
|
||||
if ($is_new_revision) {
|
||||
$record->revision_created = self::getRequestTime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate() {
|
||||
$media_source = $this->getSource();
|
||||
|
||||
if ($media_source instanceof MediaSourceEntityConstraintsInterface) {
|
||||
$entity_constraints = $media_source->getEntityConstraints();
|
||||
$this->getTypedData()->getDataDefinition()->setConstraints($entity_constraints);
|
||||
}
|
||||
|
||||
if ($media_source instanceof MediaSourceFieldConstraintsInterface) {
|
||||
$source_field_name = $media_source->getConfiguration()['source_field'];
|
||||
$source_field_constraints = $media_source->getSourceFieldConstraints();
|
||||
$this->get($source_field_name)->getDataDefinition()->setConstraints($source_field_constraints);
|
||||
}
|
||||
|
||||
return parent::validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
$fields['name'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Name'))
|
||||
->setRequired(TRUE)
|
||||
->setTranslatable(TRUE)
|
||||
->setRevisionable(TRUE)
|
||||
->setDefaultValue('')
|
||||
->setSetting('max_length', 255)
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'string_textfield',
|
||||
'weight' => -5,
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE)
|
||||
->setDisplayOptions('view', [
|
||||
'label' => 'hidden',
|
||||
'type' => 'string',
|
||||
'weight' => -5,
|
||||
]);
|
||||
|
||||
$fields['thumbnail'] = BaseFieldDefinition::create('image')
|
||||
->setLabel(t('Thumbnail'))
|
||||
->setDescription(t('The thumbnail of the media item.'))
|
||||
->setRevisionable(TRUE)
|
||||
->setTranslatable(TRUE)
|
||||
->setDisplayOptions('view', [
|
||||
'type' => 'image',
|
||||
'weight' => 5,
|
||||
'label' => 'hidden',
|
||||
'settings' => [
|
||||
'image_style' => 'thumbnail',
|
||||
],
|
||||
])
|
||||
->setDisplayConfigurable('view', TRUE)
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel(t('Authored by'))
|
||||
->setDescription(t('The user ID of the author.'))
|
||||
->setRevisionable(TRUE)
|
||||
->setDefaultValueCallback(static::class . '::getCurrentUserId')
|
||||
->setSetting('target_type', 'user')
|
||||
->setTranslatable(TRUE)
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'entity_reference_autocomplete',
|
||||
'weight' => 5,
|
||||
'settings' => [
|
||||
'match_operator' => 'CONTAINS',
|
||||
'size' => '60',
|
||||
'autocomplete_type' => 'tags',
|
||||
'placeholder' => '',
|
||||
],
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE)
|
||||
->setDisplayOptions('view', [
|
||||
'label' => 'hidden',
|
||||
'type' => 'author',
|
||||
'weight' => 0,
|
||||
])
|
||||
->setDisplayConfigurable('view', TRUE);
|
||||
|
||||
$fields['status']
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'boolean_checkbox',
|
||||
'settings' => [
|
||||
'display_label' => TRUE,
|
||||
],
|
||||
'weight' => 100,
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE);
|
||||
|
||||
$fields['created'] = BaseFieldDefinition::create('created')
|
||||
->setLabel(t('Authored on'))
|
||||
->setDescription(t('The time the media item was created.'))
|
||||
->setTranslatable(TRUE)
|
||||
->setRevisionable(TRUE)
|
||||
->setDefaultValueCallback(static::class . '::getRequestTime')
|
||||
->setDisplayOptions('form', [
|
||||
'type' => 'datetime_timestamp',
|
||||
'weight' => 10,
|
||||
])
|
||||
->setDisplayConfigurable('form', TRUE)
|
||||
->setDisplayOptions('view', [
|
||||
'label' => 'hidden',
|
||||
'type' => 'timestamp',
|
||||
'weight' => 0,
|
||||
])
|
||||
->setDisplayConfigurable('view', TRUE);
|
||||
|
||||
$fields['changed'] = BaseFieldDefinition::create('changed')
|
||||
->setLabel(t('Changed'))
|
||||
->setDescription(t('The time the media item was last edited.'))
|
||||
->setTranslatable(TRUE)
|
||||
->setRevisionable(TRUE);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value callback for 'uid' base field definition.
|
||||
*
|
||||
* @see ::baseFieldDefinitions()
|
||||
*
|
||||
* @return int[]
|
||||
* An array of default values.
|
||||
*/
|
||||
public static function getCurrentUserId() {
|
||||
return [\Drupal::currentUser()->id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getRequestTime() {
|
||||
return \Drupal::time()->getRequestTime();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
|
||||
use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
|
||||
use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
|
||||
use Drupal\media\MediaTypeInterface;
|
||||
|
||||
/**
|
||||
* Defines the Media type configuration entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "media_type",
|
||||
* label = @Translation("Media type"),
|
||||
* label_collection = @Translation("Media types"),
|
||||
* label_singular = @Translation("media type"),
|
||||
* label_plural = @Translation("media types"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count media type",
|
||||
* plural = "@count media types"
|
||||
* ),
|
||||
* handlers = {
|
||||
* "form" = {
|
||||
* "add" = "Drupal\media\MediaTypeForm",
|
||||
* "edit" = "Drupal\media\MediaTypeForm",
|
||||
* "delete" = "Drupal\media\Form\MediaTypeDeleteConfirmForm"
|
||||
* },
|
||||
* "list_builder" = "Drupal\media\MediaTypeListBuilder",
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
|
||||
* }
|
||||
* },
|
||||
* admin_permission = "administer media types",
|
||||
* config_prefix = "type",
|
||||
* bundle_of = "media",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label",
|
||||
* "status" = "status",
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "description",
|
||||
* "source",
|
||||
* "queue_thumbnail_downloads",
|
||||
* "new_revision",
|
||||
* "source_configuration",
|
||||
* "field_map",
|
||||
* "status",
|
||||
* },
|
||||
* links = {
|
||||
* "add-form" = "/admin/structure/media/add",
|
||||
* "edit-form" = "/admin/structure/media/manage/{media_type}",
|
||||
* "delete-form" = "/admin/structure/media/manage/{media_type}/delete",
|
||||
* "collection" = "/admin/structure/media",
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class MediaType extends ConfigEntityBundleBase implements MediaTypeInterface, EntityWithPluginCollectionInterface {
|
||||
|
||||
/**
|
||||
* The machine name of this media type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the media type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* A brief description of this media type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* The media source ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* Whether media items should be published by default.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $status = TRUE;
|
||||
|
||||
/**
|
||||
* Whether thumbnail downloads are queued.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $queue_thumbnail_downloads = FALSE;
|
||||
|
||||
/**
|
||||
* Default value of the 'Create new revision' checkbox of this media type.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $new_revision = FALSE;
|
||||
|
||||
/**
|
||||
* The media source configuration.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $source_configuration = [];
|
||||
|
||||
/**
|
||||
* Lazy collection for the media source.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
|
||||
*/
|
||||
protected $sourcePluginCollection;
|
||||
|
||||
/**
|
||||
* Field map. Fields provided by type plugin to be stored as entity fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $field_map = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPluginCollections() {
|
||||
return [
|
||||
'source_configuration' => $this->sourcePluginCollection(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDescription($description) {
|
||||
return $this->set('description', $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function thumbnailDownloadsAreQueued() {
|
||||
return $this->queue_thumbnail_downloads;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setQueueThumbnailDownloadsStatus($queue_thumbnail_downloads) {
|
||||
return $this->set('queue_thumbnail_downloads', $queue_thumbnail_downloads);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSource() {
|
||||
return $this->sourcePluginCollection()->get($this->source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns media source lazy plugin collection.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection|null
|
||||
* The tag plugin collection or NULL if the plugin ID was not set yet.
|
||||
*/
|
||||
protected function sourcePluginCollection() {
|
||||
if (!$this->sourcePluginCollection && $this->source) {
|
||||
$this->sourcePluginCollection = new DefaultSingleLazyPluginCollection(\Drupal::service('plugin.manager.media.source'), $this->source, $this->source_configuration);
|
||||
}
|
||||
return $this->sourcePluginCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStatus() {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function shouldCreateNewRevision() {
|
||||
return $this->new_revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setNewRevision($new_revision) {
|
||||
return $this->set('new_revision', $new_revision);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldMap() {
|
||||
return $this->field_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFieldMap(array $map) {
|
||||
return $this->set('field_map', $map);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
/**
|
||||
* Provides a confirmation form to delete multiple media items at once.
|
||||
*/
|
||||
class MediaDeleteMultipleConfirmForm extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The array of media items to delete, indexed by ID and language.
|
||||
*
|
||||
* @var string[][]
|
||||
*/
|
||||
protected $mediaItems = [];
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\user\PrivateTempStoreFactory
|
||||
*/
|
||||
protected $tempStoreFactory;
|
||||
|
||||
/**
|
||||
* The entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* Constructs a MediaDeleteMultipleConfirmForm form object.
|
||||
*
|
||||
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityTypeManagerInterface $manager) {
|
||||
$this->tempStoreFactory = $temp_store_factory;
|
||||
$this->storage = $manager->getStorage('media');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('user.private_tempstore'),
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'media_multiple_delete_confirm';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->formatPlural(count($this->mediaItems), 'Are you sure you want to delete this item?', 'Are you sure you want to delete these items?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
// @todo Change to media library when #2834729 is done.
|
||||
// https://www.drupal.org/node/2834729.
|
||||
return new Url('system.admin_content');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Change to trait or base class when #2843395 is done.
|
||||
* @see https://www.drupal.org/node/2843395
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$this->mediaItems = $this->tempStoreFactory->get('media_multiple_delete_confirm')->get($this->currentUser()->id());
|
||||
if (empty($this->mediaItems)) {
|
||||
return new RedirectResponse($this->getCancelUrl()->setAbsolute()->toString());
|
||||
}
|
||||
/** @var \Drupal\media\MediaInterface[] $entities */
|
||||
$entities = $this->storage->loadMultiple(array_keys($this->mediaItems));
|
||||
|
||||
$items = [];
|
||||
foreach ($this->mediaItems as $id => $langcodes) {
|
||||
foreach ($langcodes as $langcode) {
|
||||
$entity = $entities[$id]->getTranslation($langcode);
|
||||
$key = $id . ':' . $langcode;
|
||||
$default_key = $id . ':' . $entity->getUntranslated()->language()->getId();
|
||||
|
||||
// If we have a translated entity we build a nested list of translations
|
||||
// that will be deleted.
|
||||
$languages = $entity->getTranslationLanguages();
|
||||
if (count($languages) > 1 && $entity->isDefaultTranslation()) {
|
||||
$names = [];
|
||||
foreach ($languages as $translation_langcode => $language) {
|
||||
$names[] = $language->getName();
|
||||
unset($items[$id . ':' . $translation_langcode]);
|
||||
}
|
||||
$items[$default_key] = [
|
||||
'label' => [
|
||||
'#markup' => $this->t('@label (Original translation) - <em>The following translations will be deleted:</em>', ['@label' => $entity->label()]),
|
||||
],
|
||||
'deleted_translations' => [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $names,
|
||||
],
|
||||
];
|
||||
}
|
||||
elseif (!isset($items[$default_key])) {
|
||||
$items[$key] = $entity->label();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['entities'] = [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
];
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Change to trait or base class when #2843395 is done.
|
||||
* @see https://www.drupal.org/node/2843395
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($form_state->getValue('confirm') && !empty($this->mediaItems)) {
|
||||
$total_count = 0;
|
||||
$delete_entities = [];
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface[][] $delete_translations */
|
||||
$delete_translations = [];
|
||||
/** @var \Drupal\media\MediaInterface[] $entities */
|
||||
$entities = $this->storage->loadMultiple(array_keys($this->mediaItems));
|
||||
|
||||
foreach ($this->mediaItems as $id => $langcodes) {
|
||||
foreach ($langcodes as $langcode) {
|
||||
$entity = $entities[$id]->getTranslation($langcode);
|
||||
if ($entity->isDefaultTranslation()) {
|
||||
$delete_entities[$id] = $entity;
|
||||
unset($delete_translations[$id]);
|
||||
$total_count += count($entity->getTranslationLanguages());
|
||||
}
|
||||
elseif (!isset($delete_entities[$id])) {
|
||||
$delete_translations[$id][] = $entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($delete_entities) {
|
||||
$this->storage->delete($delete_entities);
|
||||
$this->logger('media')->notice('Deleted @count media items.', ['@count' => count($delete_entities)]);
|
||||
}
|
||||
|
||||
if ($delete_translations) {
|
||||
$count = 0;
|
||||
foreach ($delete_translations as $id => $translations) {
|
||||
$entity = $entities[$id]->getUntranslated();
|
||||
foreach ($translations as $translation) {
|
||||
$entity->removeTranslation($translation->language()->getId());
|
||||
}
|
||||
$entity->save();
|
||||
$count += count($translations);
|
||||
}
|
||||
if ($count) {
|
||||
$total_count += $count;
|
||||
$this->logger('media')->notice('Deleted @count media translations.', ['@count' => $count]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($total_count) {
|
||||
drupal_set_message($this->formatPlural($total_count, 'Deleted 1 media item.', 'Deleted @count media items.'));
|
||||
}
|
||||
|
||||
$this->tempStoreFactory->get('media_multiple_delete_confirm')->delete(\Drupal::currentUser()->id());
|
||||
}
|
||||
|
||||
// @todo Change to media library when #2834729 is done.
|
||||
// https://www.drupal.org/node/2834729.
|
||||
$form_state->setRedirect('system.admin_content');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\EntityDeleteForm;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for media type deletion.
|
||||
*/
|
||||
class MediaTypeDeleteConfirmForm extends EntityDeleteForm {
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a new MediaTypeDeleteConfirm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$num_entities = $this->entityTypeManager->getStorage('media')->getQuery()
|
||||
->condition('bundle', $this->entity->id())
|
||||
->count()
|
||||
->execute();
|
||||
if ($num_entities) {
|
||||
$form['#title'] = $this->getQuestion();
|
||||
$form['description'] = [
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '<p>{{ message }}</p>',
|
||||
'#context' => [
|
||||
'message' => $this->formatPlural($num_entities,
|
||||
'%type is used by @count media item on your site. You can not remove this media type until you have removed all of the %type media items.',
|
||||
'%type is used by @count media items on your site. You can not remove this media type until you have removed all of the %type media items.',
|
||||
['%type' => $this->entity->label()]),
|
||||
],
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines an access control handler for the media entity.
|
||||
*/
|
||||
class MediaAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($account->hasPermission('administer media')) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
$is_owner = ($account->id() && $account->id() === $entity->getOwnerId());
|
||||
switch ($operation) {
|
||||
case 'view':
|
||||
$access_result = AccessResult::allowedIf($account->hasPermission('view media') && $entity->isPublished())
|
||||
->cachePerPermissions()
|
||||
->addCacheableDependency($entity);
|
||||
if (!$access_result->isAllowed()) {
|
||||
$access_result->setReason("The 'view media' permission is required and the media item must be published.");
|
||||
}
|
||||
return $access_result;
|
||||
|
||||
case 'update':
|
||||
if ($account->hasPermission('update any media')) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
return AccessResult::allowedIf($account->hasPermission('update media') && $is_owner)
|
||||
->cachePerPermissions()
|
||||
->cachePerUser()
|
||||
->addCacheableDependency($entity);
|
||||
|
||||
case 'delete':
|
||||
if ($account->hasPermission('delete any media')) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
return AccessResult::allowedIf($account->hasPermission('delete media') && $is_owner)
|
||||
->cachePerPermissions()
|
||||
->cachePerUser()
|
||||
->addCacheableDependency($entity);
|
||||
|
||||
default:
|
||||
return AccessResult::neutral()->cachePerPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
|
||||
return AccessResult::allowedIfHasPermissions($account, ['administer media', 'create media'], 'OR');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityForm;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the media edit forms.
|
||||
*/
|
||||
class MediaForm extends ContentEntityForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
/** @var \Drupal\media\MediaTypeInterface $media_type */
|
||||
$media_type = $this->entity->bundle->entity;
|
||||
|
||||
if ($this->operation === 'edit') {
|
||||
$form['#title'] = $this->t('Edit %type_label @label', [
|
||||
'%type_label' => $media_type->label(),
|
||||
'@label' => $this->entity->label(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Media author information for administrators.
|
||||
if (isset($form['uid']) || isset($form['created'])) {
|
||||
$form['author'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Authoring information'),
|
||||
'#group' => 'advanced',
|
||||
'#attributes' => [
|
||||
'class' => ['media-form-author'],
|
||||
],
|
||||
'#weight' => 90,
|
||||
'#optional' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
if (isset($form['uid'])) {
|
||||
$form['uid']['#group'] = 'author';
|
||||
}
|
||||
|
||||
if (isset($form['created'])) {
|
||||
$form['created']['#group'] = 'author';
|
||||
}
|
||||
|
||||
$form['#attached']['library'][] = 'media/form';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$saved = parent::save($form, $form_state);
|
||||
$context = ['@type' => $this->entity->bundle(), '%label' => $this->entity->label()];
|
||||
$logger = $this->logger('media');
|
||||
$t_args = ['@type' => $this->entity->bundle->entity->label(), '%label' => $this->entity->label()];
|
||||
|
||||
if ($saved === SAVED_NEW) {
|
||||
$logger->notice('@type: added %label.', $context);
|
||||
drupal_set_message($this->t('@type %label has been created.', $t_args));
|
||||
}
|
||||
else {
|
||||
$logger->notice('@type: updated %label.', $context);
|
||||
drupal_set_message($this->t('@type %label has been updated.', $t_args));
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($this->entity->toUrl('canonical'));
|
||||
return $saved;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Entity\EntityChangedInterface;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
use Drupal\Core\Entity\RevisionLogInterface;
|
||||
use Drupal\user\EntityOwnerInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining an entity for media items.
|
||||
*/
|
||||
interface MediaInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface, EntityOwnerInterface, EntityPublishedInterface {
|
||||
|
||||
/**
|
||||
* Gets the media item name.
|
||||
*
|
||||
* @return string
|
||||
* The name of the media item.
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Sets the media item name.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the media item.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name);
|
||||
|
||||
/**
|
||||
* Returns the media item creation timestamp.
|
||||
*
|
||||
* @todo Remove and use the new interface when #2833378 is done.
|
||||
* @see https://www.drupal.org/node/2833378
|
||||
*
|
||||
* @return int
|
||||
* Creation timestamp of the media item.
|
||||
*/
|
||||
public function getCreatedTime();
|
||||
|
||||
/**
|
||||
* Sets the media item creation timestamp.
|
||||
*
|
||||
* @todo Remove and use the new interface when #2833378 is done.
|
||||
* @see https://www.drupal.org/node/2833378
|
||||
*
|
||||
* @param int $timestamp
|
||||
* The media creation timestamp.
|
||||
*
|
||||
* @return \Drupal\media\MediaInterface
|
||||
* The called media item.
|
||||
*/
|
||||
public function setCreatedTime($timestamp);
|
||||
|
||||
/**
|
||||
* Returns the media source.
|
||||
*
|
||||
* @return \Drupal\media\MediaSourceInterface
|
||||
* The media source.
|
||||
*/
|
||||
public function getSource();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Base implementation of media source plugin.
|
||||
*/
|
||||
abstract class MediaSourceBase extends PluginBase implements MediaSourceInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* Plugin label.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The entity type manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity field manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* The field type plugin manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* The config factory service.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* Entity type manager service.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* Entity field manager service.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type plugin manager service.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
$this->configFactory = $config_factory;
|
||||
|
||||
// Add the default configuration of the media source to the plugin.
|
||||
$this->setConfiguration($configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConfiguration(array $configuration) {
|
||||
$this->configuration = NestedArray::mergeDeep(
|
||||
$this->defaultConfiguration(),
|
||||
$configuration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfiguration() {
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'source_field' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(MediaInterface $media, $attribute_name) {
|
||||
switch ($attribute_name) {
|
||||
case 'default_name':
|
||||
return 'media:' . $media->bundle() . ':' . $media->uuid();
|
||||
|
||||
case 'thumbnail_uri':
|
||||
$default_thumbnail_filename = $this->pluginDefinition['default_thumbnail_filename'];
|
||||
return $this->configFactory->get('media.settings')->get('icon_base_uri') . '/' . $default_thumbnail_filename;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source field options for the media type form.
|
||||
*
|
||||
* This returns all fields related to media entities, filtered by the allowed
|
||||
* field types in the media source annotation.
|
||||
*
|
||||
* @return string[]
|
||||
* A list of source field options for the media type form.
|
||||
*/
|
||||
protected function getSourceFieldOptions() {
|
||||
// If there are existing fields to choose from, allow the user to reuse one.
|
||||
$options = [];
|
||||
foreach ($this->entityFieldManager->getFieldStorageDefinitions('media') as $field_name => $field) {
|
||||
$allowed_type = in_array($field->getType(), $this->pluginDefinition['allowed_field_types'], TRUE);
|
||||
if ($allowed_type && !$field->isBaseField()) {
|
||||
$options[$field_name] = $field->getLabel();
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$options = $this->getSourceFieldOptions();
|
||||
$form['source_field'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Field with source information'),
|
||||
'#default_value' => $this->configuration['source_field'],
|
||||
'#empty_option' => $this->t('- Create -'),
|
||||
'#options' => $options,
|
||||
'#description' => $this->t('Select the field that will store essential information about the media item. If "Create" is selected a new field will be automatically created.'),
|
||||
];
|
||||
|
||||
if (!$options && $form_state->get('operation') === 'add') {
|
||||
$form['source_field']['#access'] = FALSE;
|
||||
$field_definition = $this->fieldTypeManager->getDefinition(reset($this->pluginDefinition['allowed_field_types']));
|
||||
$form['source_field_message'] = [
|
||||
'#markup' => $this->t('%field_type field will be automatically created on this type to store the essential information about the media item.', [
|
||||
'%field_type' => $field_definition['label'],
|
||||
]),
|
||||
];
|
||||
}
|
||||
elseif ($form_state->get('operation') === 'edit') {
|
||||
$form['source_field']['#access'] = FALSE;
|
||||
$fields = $this->entityFieldManager->getFieldDefinitions('media', $form_state->get('type')->id());
|
||||
$form['source_field_message'] = [
|
||||
'#markup' => $this->t('%field_name field is used to store the essential information about the media item.', [
|
||||
'%field_name' => $fields[$this->configuration['source_field']]->getLabel(),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
foreach (array_intersect_key($form_state->getValues(), $this->configuration) as $config_key => $config_value) {
|
||||
$this->configuration[$config_key] = $config_value;
|
||||
}
|
||||
|
||||
// If no source field is explicitly set, create it now.
|
||||
if (empty($this->configuration['source_field'])) {
|
||||
$field_storage = $this->createSourceFieldStorage();
|
||||
$field_storage->save();
|
||||
$this->configuration['source_field'] = $field_storage->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the source field storage definition.
|
||||
*
|
||||
* By default, the first field type listed in the plugin definition's
|
||||
* allowed_field_types array will be the generated field's type.
|
||||
*
|
||||
* @return \Drupal\field\FieldStorageConfigInterface
|
||||
* The unsaved field storage definition.
|
||||
*/
|
||||
protected function createSourceFieldStorage() {
|
||||
return $this->entityTypeManager
|
||||
->getStorage('field_storage_config')
|
||||
->create([
|
||||
'entity_type' => 'media',
|
||||
'field_name' => $this->getSourceFieldName(),
|
||||
'type' => reset($this->pluginDefinition['allowed_field_types']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source field storage definition.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface|null
|
||||
* The field storage definition or NULL if it doesn't exists.
|
||||
*/
|
||||
protected function getSourceFieldStorage() {
|
||||
// Nothing to do if no source field is configured yet.
|
||||
$field = $this->configuration['source_field'];
|
||||
if ($field) {
|
||||
// Even if we do know the name of the source field, there's no
|
||||
// guarantee that it exists.
|
||||
$fields = $this->entityFieldManager->getFieldStorageDefinitions('media');
|
||||
return isset($fields[$field]) ? $fields[$field] : NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourceFieldDefinition(MediaTypeInterface $type) {
|
||||
// Nothing to do if no source field is configured yet.
|
||||
$field = $this->configuration['source_field'];
|
||||
if ($field) {
|
||||
// Even if we do know the name of the source field, there is no
|
||||
// guarantee that it already exists.
|
||||
$fields = $this->entityFieldManager->getFieldDefinitions('media', $type->id());
|
||||
return isset($fields[$field]) ? $fields[$field] : NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createSourceField(MediaTypeInterface $type) {
|
||||
$storage = $this->getSourceFieldStorage() ?: $this->createSourceFieldStorage();
|
||||
return $this->entityTypeManager
|
||||
->getStorage('field_config')
|
||||
->create([
|
||||
'field_storage' => $storage,
|
||||
'bundle' => $type->id(),
|
||||
'label' => $this->pluginDefinition['label'],
|
||||
'required' => TRUE,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the name of the source field.
|
||||
*
|
||||
* @return string
|
||||
* The source field name. If one is already stored in configuration, it is
|
||||
* returned. Otherwise, a new, unused one is generated.
|
||||
*/
|
||||
protected function getSourceFieldName() {
|
||||
$base_id = 'field_media_' . $this->getPluginId();
|
||||
$tries = 0;
|
||||
$storage = $this->entityTypeManager->getStorage('field_storage_config');
|
||||
|
||||
// Iterate at least once, until no field with the generated ID is found.
|
||||
do {
|
||||
$id = $base_id;
|
||||
// If we've tried before, increment and append the suffix.
|
||||
if ($tries) {
|
||||
$id .= '_' . $tries;
|
||||
}
|
||||
$field = $storage->load('media.' . $id);
|
||||
$tries++;
|
||||
} while ($field);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
/**
|
||||
* Defines an interface for a media source with entity constraints.
|
||||
*
|
||||
* This allows a media source to optionally add entity validation constraints
|
||||
* for media items. To add constraints at the source field level, a media source
|
||||
* can also implement MediaSourceFieldConstraintsInterface.
|
||||
*
|
||||
* @see \Drupal\media\MediaSourceInterface
|
||||
* @see \Drupal\media\MediaSourceFieldConstraintsInterface.php
|
||||
* @see \Drupal\media\MediaSourceBase
|
||||
* @see \Drupal\media\Entity\Media
|
||||
*/
|
||||
interface MediaSourceEntityConstraintsInterface extends MediaSourceInterface {
|
||||
|
||||
/**
|
||||
* Gets media source-specific validation constraints for a media item.
|
||||
*
|
||||
* @return \Symfony\Component\Validator\Constraint[]
|
||||
* An array of validation constraint definitions, keyed by constraint name.
|
||||
* Each constraint definition can be used for instantiating
|
||||
* \Symfony\Component\Validator\Constraint objects.
|
||||
*/
|
||||
public function getEntityConstraints();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
/**
|
||||
* Defines an interface for a media source with source field constraints.
|
||||
*
|
||||
* This allows a media source to optionally add source field validation
|
||||
* constraints for media items. To add constraints at the entity level, a
|
||||
* media source can also implement MediaSourceEntityConstraintsInterface.
|
||||
*
|
||||
* @see \Drupal\media\MediaSourceInterface
|
||||
* @see \Drupal\media\MediaSourceEntityConstraintsInterface
|
||||
* @see \Drupal\media\MediaSourceBase
|
||||
* @see \Drupal\media\Entity\Media
|
||||
*/
|
||||
interface MediaSourceFieldConstraintsInterface extends MediaSourceInterface {
|
||||
|
||||
/**
|
||||
* Gets media source-specific validation constraints for a source field.
|
||||
*
|
||||
* @return \Symfony\Component\Validator\Constraint[]
|
||||
* An array of validation constraint definitions, keyed by constraint name.
|
||||
* Each constraint definition can be used for instantiating
|
||||
* \Symfony\Component\Validator\Constraint objects.
|
||||
*/
|
||||
public function getSourceFieldConstraints();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\Core\Plugin\PluginFormInterface;
|
||||
|
||||
/**
|
||||
* Defines the interface for media source plugins.
|
||||
*
|
||||
* Media sources provide the critical link between media items in Drupal and the
|
||||
* actual media itself, which typically exists independently of Drupal. Each
|
||||
* media source works with a certain kind of media. For example, local files and
|
||||
* YouTube videos can both be catalogued in a similar way as media items, but
|
||||
* they need very different handling to actually display them.
|
||||
*
|
||||
* Each media type needs exactly one source. A single source can be used on many
|
||||
* media types.
|
||||
*
|
||||
* Examples of possible sources are:
|
||||
* - File: handles local files,
|
||||
* - Image: handles local images,
|
||||
* - oEmbed: handles resources that are exposed through the oEmbed standard,
|
||||
* - YouTube: handles YouTube videos,
|
||||
* - SoundCould: handles SoundCloud audio,
|
||||
* - Instagram: handles Instagram posts,
|
||||
* - Twitter: handles tweets,
|
||||
* - ...
|
||||
*
|
||||
* Their responsibilities are:
|
||||
* - Defining how media is represented (stored). Media sources are not
|
||||
* responsible for actually storing the media. They only define how it is
|
||||
* represented on a media item (usually using some kind of a field).
|
||||
* - Providing thumbnails. Media sources that are responsible for remote
|
||||
* media will generally fetch the image from a third-party API and make
|
||||
* it available for the local usage. Media sources that represent local
|
||||
* media (such as images) will usually use some locally provided image.
|
||||
* Media sources should fall back to a pre-defined default thumbnail if
|
||||
* everything else fails.
|
||||
* - Validating a media item before it is saved. The entity constraint system
|
||||
* will be used to ensure the valid structure of the media item.
|
||||
* For example, media sources that represent remote media might check the
|
||||
* URL or other identifier, while sources that represent local files might
|
||||
* check the MIME type of the file.
|
||||
* - Providing a default name for a media item. This will save users from
|
||||
* manually entering the name when it can be reliably set automatically.
|
||||
* Media sources for local files will generally use the filename, while media
|
||||
* sources for remote resources might obtain a title attribute through a
|
||||
* third-party API. The name can always be overridden by the user.
|
||||
* - Providing metadata specific to the given media type. For example, remote
|
||||
* media sources generally get information available through a
|
||||
* third-party API and make it available to Drupal, while local media sources
|
||||
* can expose things such as EXIF or ID3.
|
||||
* - Mapping metadata to the media item. Metadata that a media source exposes
|
||||
* can automatically be mapped to the fields on the media item. Media
|
||||
* sources will be able to define how this is done.
|
||||
*
|
||||
* @see \Drupal\media\Annotation\MediaSource
|
||||
* @see \Drupal\media\MediaSourceBase
|
||||
* @see \Drupal\media\MediaSourceManager
|
||||
* @see \Drupal\media\MediaTypeInterface
|
||||
* @see \Drupal\media\MediaSourceEntityConstraintsInterface
|
||||
* @see \Drupal\media\MediaSourceFieldConstraintsInterface
|
||||
* @see plugin_api
|
||||
*/
|
||||
interface MediaSourceInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface {
|
||||
|
||||
/**
|
||||
* Default empty value for metadata fields.
|
||||
*/
|
||||
const METADATA_FIELD_EMPTY = '_none';
|
||||
|
||||
/**
|
||||
* Gets a list of metadata attributes provided by this plugin.
|
||||
*
|
||||
* Most media sources have associated metadata, describing attributes
|
||||
* such as:
|
||||
* - dimensions
|
||||
* - duration
|
||||
* - encoding
|
||||
* - date
|
||||
* - location
|
||||
* - permalink
|
||||
* - licensing information
|
||||
* - ...
|
||||
*
|
||||
* This method should list all metadata attributes that a media source MAY
|
||||
* offer. In other words: it is possible that a particular media item does
|
||||
* not contain a certain attribute. For example: an oEmbed media source can
|
||||
* contain both video and images. Images don't have a duration, but
|
||||
* videos do.
|
||||
*
|
||||
* (The term 'attributes' was chosen because it cannot be confused
|
||||
* with 'fields' and 'properties', both of which are concepts in Drupal's
|
||||
* Entity Field API.)
|
||||
*
|
||||
* @return array
|
||||
* Associative array with:
|
||||
* - keys: metadata attribute names
|
||||
* - values: human-readable labels for those attribute names
|
||||
*/
|
||||
public function getMetadataAttributes();
|
||||
|
||||
/**
|
||||
* Gets the value for a metadata attribute for a given media item.
|
||||
*
|
||||
* @param \Drupal\media\MediaInterface $media
|
||||
* A media item.
|
||||
* @param string $attribute_name
|
||||
* Name of the attribute to fetch.
|
||||
*
|
||||
* @return mixed|null
|
||||
* Metadata attribute value or NULL if unavailable.
|
||||
*/
|
||||
public function getMetadata(MediaInterface $media, $attribute_name);
|
||||
|
||||
/**
|
||||
* Get the source field definition for a media type.
|
||||
*
|
||||
* @param \Drupal\media\MediaTypeInterface $type
|
||||
* A media type.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldDefinitionInterface|null
|
||||
* The source field definition, or NULL if it doesn't exist or has not been
|
||||
* configured yet.
|
||||
*/
|
||||
public function getSourceFieldDefinition(MediaTypeInterface $type);
|
||||
|
||||
/**
|
||||
* Creates the source field definition for a type.
|
||||
*
|
||||
* @param \Drupal\media\MediaTypeInterface $type
|
||||
* The media type.
|
||||
*
|
||||
* @return \Drupal\field\FieldConfigInterface
|
||||
* The unsaved field definition. The field storage definition, if new,
|
||||
* should also be unsaved.
|
||||
*/
|
||||
public function createSourceField(MediaTypeInterface $type);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\media\Annotation\MediaSource;
|
||||
|
||||
/**
|
||||
* Manages media source plugins.
|
||||
*/
|
||||
class MediaSourceManager extends DefaultPluginManager {
|
||||
|
||||
/**
|
||||
* Constructs a new MediaSourceManager.
|
||||
*
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Plugin/media/Source', $namespaces, $module_handler, MediaSourceInterface::class, MediaSource::class);
|
||||
|
||||
$this->alterInfo('media_source_info');
|
||||
$this->setCacheBackend($cache_backend, 'media_source_plugins');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\ReplaceCommand;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\SubformState;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\media\Entity\MediaType;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for media type forms.
|
||||
*/
|
||||
class MediaTypeForm extends EntityForm {
|
||||
|
||||
/**
|
||||
* Media source plugin manager.
|
||||
*
|
||||
* @var \Drupal\media\MediaSourceManager
|
||||
*/
|
||||
protected $sourceManager;
|
||||
|
||||
/**
|
||||
* Entity field manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
* @param \Drupal\media\MediaSourceManager $source_manager
|
||||
* Media source plugin manager.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* Entity field manager service.
|
||||
*/
|
||||
public function __construct(MediaSourceManager $source_manager, EntityFieldManagerInterface $entity_field_manager) {
|
||||
$this->sourceManager = $source_manager;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.media.source'),
|
||||
$container->get('entity_field.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback triggered by the type provider select element.
|
||||
*/
|
||||
public function ajaxHandlerData(array $form, FormStateInterface $form_state) {
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new ReplaceCommand('#source-dependent', $form['source_dependent']));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
// Source is not set when the entity is initially created.
|
||||
/** @var \Drupal\media\MediaSourceInterface $source */
|
||||
$source = $this->entity->get('source') ? $this->entity->getSource() : NULL;
|
||||
|
||||
if ($this->operation === 'add') {
|
||||
$form['#title'] = $this->t('Add media type');
|
||||
}
|
||||
|
||||
$form['label'] = [
|
||||
'#title' => $this->t('Name'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->entity->label(),
|
||||
'#description' => $this->t('The human-readable name of this media type.'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 30,
|
||||
];
|
||||
|
||||
$form['id'] = [
|
||||
'#type' => 'machine_name',
|
||||
'#default_value' => $this->entity->id(),
|
||||
'#maxlength' => 32,
|
||||
'#disabled' => !$this->entity->isNew(),
|
||||
'#machine_name' => [
|
||||
'exists' => [MediaType::class, 'load'],
|
||||
],
|
||||
'#description' => $this->t('A unique machine-readable name for this media type.'),
|
||||
];
|
||||
|
||||
$form['description'] = [
|
||||
'#title' => $this->t('Description'),
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => $this->entity->getDescription(),
|
||||
'#description' => $this->t('Describe this media type. The text will be displayed on the <em>Add new media</em> page.'),
|
||||
];
|
||||
|
||||
$plugins = $this->sourceManager->getDefinitions();
|
||||
$options = [];
|
||||
foreach ($plugins as $plugin_id => $definition) {
|
||||
$options[$plugin_id] = $definition['label'];
|
||||
}
|
||||
|
||||
$form['source_dependent'] = [
|
||||
'#type' => 'container',
|
||||
'#attributes' => ['id' => 'source-dependent'],
|
||||
];
|
||||
|
||||
$form['source_dependent']['source'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Media source'),
|
||||
'#default_value' => $source ? $source->getPluginId() : NULL,
|
||||
'#options' => $options,
|
||||
'#description' => $this->t('Media source that is responsible for additional logic related to this media type.'),
|
||||
'#ajax' => ['callback' => '::ajaxHandlerData'],
|
||||
'#required' => TRUE,
|
||||
];
|
||||
|
||||
if (!$source) {
|
||||
$form['type']['#empty_option'] = $this->t('- Select media source -');
|
||||
}
|
||||
|
||||
if ($source) {
|
||||
// Media source plugin configuration.
|
||||
$form['source_dependent']['source_configuration'] = [
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Media source configuration'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
$form['source_dependent']['source_configuration'] = $source->buildConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
|
||||
}
|
||||
|
||||
// Field mapping configuration.
|
||||
$form['source_dependent']['field_map'] = [
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Field mapping'),
|
||||
'#tree' => TRUE,
|
||||
'description' => [
|
||||
'#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>',
|
||||
],
|
||||
];
|
||||
|
||||
if (empty($source) || empty($source->getMetadataAttributes())) {
|
||||
$form['source_dependent']['field_map']['#access'] = FALSE;
|
||||
}
|
||||
else {
|
||||
$options = [MediaSourceInterface::METADATA_FIELD_EMPTY => $this->t('- Skip field -')];
|
||||
foreach ($this->entityFieldManager->getFieldDefinitions('media', $this->entity->id()) as $field_name => $field) {
|
||||
if (!($field instanceof BaseFieldDefinition) || $field_name === 'name') {
|
||||
$options[$field_name] = $field->getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
$field_map = $this->entity->getFieldMap();
|
||||
foreach ($source->getMetadataAttributes() as $metadata_attribute_name => $metadata_attribute_label) {
|
||||
$form['source_dependent']['field_map'][$metadata_attribute_name] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $metadata_attribute_label,
|
||||
'#options' => $options,
|
||||
'#default_value' => isset($field_map[$metadata_attribute_name]) ? $field_map[$metadata_attribute_name] : MediaSourceInterface::METADATA_FIELD_EMPTY,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$form['additional_settings'] = [
|
||||
'#type' => 'vertical_tabs',
|
||||
'#attached' => [
|
||||
'library' => ['media/type_form'],
|
||||
],
|
||||
];
|
||||
|
||||
$form['workflow'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Publishing options'),
|
||||
'#group' => 'additional_settings',
|
||||
];
|
||||
|
||||
$form['workflow']['options'] = [
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Default options'),
|
||||
'#default_value' => $this->getWorkflowOptions(),
|
||||
'#options' => [
|
||||
'status' => $this->t('Published'),
|
||||
'new_revision' => $this->t('Create new revision'),
|
||||
'queue_thumbnail_downloads' => $this->t('Queue thumbnail downloads'),
|
||||
],
|
||||
];
|
||||
|
||||
$form['workflow']['options']['status']['#description'] = $this->t('Media will be automatically published when created.');
|
||||
$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.');
|
||||
$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.');
|
||||
|
||||
if ($this->moduleHandler->moduleExists('language')) {
|
||||
$form['language'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Language settings'),
|
||||
'#group' => 'additional_settings',
|
||||
];
|
||||
|
||||
$language_configuration = ContentLanguageSettings::loadByEntityTypeBundle('media', $this->entity->id());
|
||||
$form['language']['language_configuration'] = [
|
||||
'#type' => 'language_configuration',
|
||||
'#entity_information' => [
|
||||
'entity_type' => 'media',
|
||||
'bundle' => $this->entity->id(),
|
||||
],
|
||||
'#default_value' => $language_configuration,
|
||||
];
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares workflow options to be used in the 'checkboxes' form element.
|
||||
*
|
||||
* @return array
|
||||
* Array of options ready to be used in #options.
|
||||
*/
|
||||
protected function getWorkflowOptions() {
|
||||
$workflow_options = [
|
||||
'status' => $this->entity->getStatus(),
|
||||
'new_revision' => $this->entity->shouldCreateNewRevision(),
|
||||
'queue_thumbnail_downloads' => $this->entity->thumbnailDownloadsAreQueued(),
|
||||
];
|
||||
// Prepare workflow options to be used for 'checkboxes' form element.
|
||||
$keys = array_keys(array_filter($workflow_options));
|
||||
return array_combine($keys, $keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets subform state for the media source configuration subform.
|
||||
*
|
||||
* @param array $form
|
||||
* Full form array.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* Parent form state.
|
||||
*
|
||||
* @return \Drupal\Core\Form\SubformStateInterface
|
||||
* Sub-form state for the media source configuration form.
|
||||
*/
|
||||
protected function getSourceSubFormState(array $form, FormStateInterface $form_state) {
|
||||
return SubformState::createForSubform($form['source_dependent']['source_configuration'], $form, $form_state)
|
||||
->set('operation', $this->operation)
|
||||
->set('type', $this->entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
if ($form['source_dependent']['source_configuration']) {
|
||||
// Let the selected plugin validate its settings.
|
||||
$this->entity->getSource()->validateConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setValue('field_map', array_filter(
|
||||
$form_state->getValue('field_map', []),
|
||||
function ($item) {
|
||||
return $item != MediaSourceInterface::METADATA_FIELD_EMPTY;
|
||||
}
|
||||
));
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
$this->entity->setQueueThumbnailDownloadsStatus((bool) $form_state->getValue(['options', 'queue_thumbnail_downloads']))
|
||||
->setStatus((bool) $form_state->getValue(['options', 'status']))
|
||||
->setNewRevision((bool) $form_state->getValue(['options', 'new_revision']));
|
||||
|
||||
if ($form['source_dependent']['source_configuration']) {
|
||||
// Let the selected plugin save its settings.
|
||||
$this->entity->getSource()->submitConfigurationForm($form['source_dependent']['source_configuration'], $this->getSourceSubFormState($form, $form_state));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$actions = parent::actions($form, $form_state);
|
||||
$actions['submit']['#value'] = $this->t('Save');
|
||||
$actions['delete']['#value'] = $this->t('Delete');
|
||||
$actions['delete']['#access'] = $this->entity->access('delete');
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$status = parent::save($form, $form_state);
|
||||
/** @var \Drupal\media\MediaTypeInterface $media_type */
|
||||
$media_type = $this->entity;
|
||||
|
||||
// If the media source is using a source field, ensure it's
|
||||
// properly created.
|
||||
$source = $media_type->getSource();
|
||||
$source_field = $source->getSourceFieldDefinition($media_type);
|
||||
if (!$source_field) {
|
||||
$source_field = $source->createSourceField($media_type);
|
||||
/** @var \Drupal\field\FieldStorageConfigInterface $storage */
|
||||
$storage = $source_field->getFieldStorageDefinition();
|
||||
if ($storage->isNew()) {
|
||||
$storage->save();
|
||||
}
|
||||
$source_field->save();
|
||||
|
||||
// Add the new field to the default form and view displays for this
|
||||
// media type.
|
||||
$field_name = $source_field->getName();
|
||||
$field_type = $source_field->getType();
|
||||
|
||||
if ($source_field->isDisplayConfigurable('form')) {
|
||||
// Use the default widget and settings.
|
||||
$component = \Drupal::service('plugin.manager.field.widget')
|
||||
->prepareConfiguration($field_type, []);
|
||||
|
||||
// @todo Replace entity_get_form_display() when #2367933 is done.
|
||||
// https://www.drupal.org/node/2872159.
|
||||
entity_get_form_display('media', $media_type->id(), 'default')
|
||||
->setComponent($field_name, $component)
|
||||
->save();
|
||||
}
|
||||
if ($source_field->isDisplayConfigurable('view')) {
|
||||
// Use the default formatter and settings.
|
||||
$component = \Drupal::service('plugin.manager.field.formatter')
|
||||
->prepareConfiguration($field_type, []);
|
||||
|
||||
// @todo Replace entity_get_display() when #2367933 is done.
|
||||
// https://www.drupal.org/node/2872159.
|
||||
entity_get_display('media', $media_type->id(), 'default')
|
||||
->setComponent($field_name, $component)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
$t_args = ['%name' => $media_type->label()];
|
||||
if ($status === SAVED_UPDATED) {
|
||||
drupal_set_message($this->t('The media type %name has been updated.', $t_args));
|
||||
}
|
||||
elseif ($status === SAVED_NEW) {
|
||||
drupal_set_message($this->t('The media type %name has been added.', $t_args));
|
||||
$this->logger('media')->notice('Added media type %name.', $t_args);
|
||||
}
|
||||
|
||||
// Override the "status" base field default value, for this media type.
|
||||
$fields = $this->entityFieldManager->getFieldDefinitions('media', $media_type->id());
|
||||
/** @var \Drupal\media\MediaInterface $media */
|
||||
$media = $this->entityTypeManager->getStorage('media')->create(['bundle' => $media_type->id()]);
|
||||
$value = (bool) $form_state->getValue(['options', 'status']);
|
||||
if ($media->status->value != $value) {
|
||||
$fields['status']->getConfig($media_type->id())->setDefaultValue($value)->save();
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($media_type->toUrl('collection'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Entity\EntityDescriptionInterface;
|
||||
use Drupal\Core\Entity\RevisionableEntityBundleInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a media type entity.
|
||||
*
|
||||
* Media types are bundles for media items. They are used to group media with
|
||||
* the same semantics. Media types are not about where media comes from. They
|
||||
* are about the semantics that media has in the context of a given Drupal site.
|
||||
*
|
||||
* Media sources, on the other hand, are aware where media comes from and know
|
||||
* how to represent and handle it in Drupal's context. They are aware of the low
|
||||
* level details, while the media types don't care about them at all. That said,
|
||||
* media types can not exist without media sources.
|
||||
*
|
||||
* Consider the following examples:
|
||||
* - oEmbed media source which can represent any oEmbed resource. Media types
|
||||
* that could be used with this source are "Videos", "Charts", "Music", etc.
|
||||
* All of them are retrieved using the same protocol, but they represent very
|
||||
* different things.
|
||||
* - Media sources that represent files could be used with media types like
|
||||
* "Invoices", "Subtitles", "Meeting notes", etc. They are all files stored on
|
||||
* some kind of storage, but their meaning and uses in a Drupal site are
|
||||
* different.
|
||||
*
|
||||
* @see \Drupal\media\MediaSourceInterface
|
||||
*/
|
||||
interface MediaTypeInterface extends ConfigEntityInterface, EntityDescriptionInterface, RevisionableEntityBundleInterface {
|
||||
|
||||
/**
|
||||
* Returns whether thumbnail downloads are queued.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if thumbnails are queued for download later, FALSE if they should be
|
||||
* downloaded now.
|
||||
*/
|
||||
public function thumbnailDownloadsAreQueued();
|
||||
|
||||
/**
|
||||
* Sets a flag to indicate that thumbnails should be downloaded via a queue.
|
||||
*
|
||||
* @param bool $queue_thumbnail_downloads
|
||||
* The queue downloads flag.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setQueueThumbnailDownloadsStatus($queue_thumbnail_downloads);
|
||||
|
||||
/**
|
||||
* Returns the media source plugin.
|
||||
*
|
||||
* @return \Drupal\media\MediaSourceInterface
|
||||
* The media source.
|
||||
*/
|
||||
public function getSource();
|
||||
|
||||
/**
|
||||
* Sets whether new revisions should be created by default.
|
||||
*
|
||||
* @param bool $new_revision
|
||||
* TRUE if media items of this type should create new revisions by default.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNewRevision($new_revision);
|
||||
|
||||
/**
|
||||
* Returns the metadata field map.
|
||||
*
|
||||
* Field mapping allows site builders to map media item-related metadata to
|
||||
* entity fields. This information will be used when saving a given media item
|
||||
* and if metadata values will be available they are going to be automatically
|
||||
* copied to the corresponding entity fields.
|
||||
*
|
||||
* @return array
|
||||
* Field mapping array provided by media source with metadata attribute
|
||||
* names as keys and entity field names as values.
|
||||
*/
|
||||
public function getFieldMap();
|
||||
|
||||
/**
|
||||
* Sets the metadata field map.
|
||||
*
|
||||
* @param array $map
|
||||
* Field mapping array with metadata attribute names as keys and entity
|
||||
* field names as values.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFieldMap(array $map);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Provides a listing of media types.
|
||||
*/
|
||||
class MediaTypeListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['title'] = $this->t('Name');
|
||||
$header['description'] = [
|
||||
'data' => $this->t('Description'),
|
||||
'class' => [RESPONSIVE_PRIORITY_MEDIUM],
|
||||
];
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
$row['title'] = [
|
||||
'data' => $entity->label(),
|
||||
'class' => ['menu-label'],
|
||||
];
|
||||
$row['description']['data'] = ['#markup' => $entity->getDescription()];
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render() {
|
||||
$build = parent::render();
|
||||
$build['table']['#empty'] = $this->t('No media types available. <a href=":url">Add media type</a>.', [
|
||||
':url' => Url::fromRoute('entity.media_type.add_form')->toString(),
|
||||
]);
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media;
|
||||
|
||||
use Drupal\views\EntityViewsData;
|
||||
|
||||
/**
|
||||
* Provides the Views data for the media entity type.
|
||||
*/
|
||||
class MediaViewsData extends EntityViewsData {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewsData() {
|
||||
$data = parent::getViewsData();
|
||||
|
||||
$data['media_field_data']['table']['wizard_id'] = 'media';
|
||||
$data['media_field_revision']['table']['wizard_id'] = 'media_revision';
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\image\ImageStyleStorageInterface;
|
||||
use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatter;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\media\MediaInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'media_thumbnail' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "media_thumbnail",
|
||||
* label = @Translation("Thumbnail"),
|
||||
* field_types = {
|
||||
* "entity_reference"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class MediaThumbnailFormatter extends ImageFormatter {
|
||||
|
||||
/**
|
||||
* The renderer service.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs an MediaThumbnailFormatter object.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the formatter.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The definition of the field to which the formatter is associated.
|
||||
* @param array $settings
|
||||
* The formatter settings.
|
||||
* @param string $label
|
||||
* The formatter label display setting.
|
||||
* @param string $view_mode
|
||||
* The view mode.
|
||||
* @param array $third_party_settings
|
||||
* Any third party settings settings.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
* @param \Drupal\image\ImageStyleStorageInterface $image_style_storage
|
||||
* The image style entity storage handler.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer service.
|
||||
*/
|
||||
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user, ImageStyleStorageInterface $image_style_storage, RendererInterface $renderer) {
|
||||
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings, $current_user, $image_style_storage);
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$configuration['field_definition'],
|
||||
$configuration['settings'],
|
||||
$configuration['label'],
|
||||
$configuration['view_mode'],
|
||||
$configuration['third_party_settings'],
|
||||
$container->get('current_user'),
|
||||
$container->get('entity_type.manager')->getStorage('image_style'),
|
||||
$container->get('renderer')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* This has to be overridden because FileFormatterBase expects $item to be
|
||||
* of type \Drupal\file\Plugin\Field\FieldType\FileItem and calls
|
||||
* isDisplayed() which is not in FieldItemInterface.
|
||||
*/
|
||||
protected function needsEntityLoad(EntityReferenceItem $item) {
|
||||
return !$item->hasNewEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$element = parent::settingsForm($form, $form_state);
|
||||
|
||||
$link_types = [
|
||||
'content' => $this->t('Content'),
|
||||
'media' => $this->t('Media entity'),
|
||||
];
|
||||
$element['image_link']['#options'] = $link_types;
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = parent::settingsSummary();
|
||||
|
||||
$link_types = [
|
||||
'content' => $this->t('Linked to content'),
|
||||
'media' => $this->t('Linked to media item'),
|
||||
];
|
||||
// Display this setting only if image is linked.
|
||||
$image_link_setting = $this->getSetting('image_link');
|
||||
if (isset($link_types[$image_link_setting])) {
|
||||
$summary[] = $link_types[$image_link_setting];
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
$elements = [];
|
||||
$media_items = $this->getEntitiesToView($items, $langcode);
|
||||
|
||||
// Early opt-out if the field is empty.
|
||||
if (empty($media_items)) {
|
||||
return $elements;
|
||||
}
|
||||
|
||||
$image_style_setting = $this->getSetting('image_style');
|
||||
|
||||
/** @var \Drupal\media\MediaInterface[] $media_items */
|
||||
foreach ($media_items as $delta => $media) {
|
||||
$elements[$delta] = [
|
||||
'#theme' => 'image_formatter',
|
||||
'#item' => $media->get('thumbnail')->first(),
|
||||
'#item_attributes' => [],
|
||||
'#image_style' => $this->getSetting('image_style'),
|
||||
'#url' => $this->getMediaThumbnailUrl($media, $items->getEntity()),
|
||||
];
|
||||
|
||||
// Add cacheability of each item in the field.
|
||||
$this->renderer->addCacheableDependency($elements[$delta], $media);
|
||||
}
|
||||
|
||||
// Add cacheability of the image style setting.
|
||||
if ($this->getSetting('image_link') && ($image_style = $this->imageStyleStorage->load($image_style_setting))) {
|
||||
$this->renderer->addCacheableDependency($elements, $image_style);
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function isApplicable(FieldDefinitionInterface $field_definition) {
|
||||
// This formatter is only available for entity types that reference
|
||||
// media items.
|
||||
return ($field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'media');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL for the media thumbnail.
|
||||
*
|
||||
* @param \Drupal\media\MediaInterface $media
|
||||
* The media item.
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity that the field belongs to.
|
||||
*
|
||||
* @return \Drupal\Core\Url|null
|
||||
* The URL object for the media item or null if we don't want to add
|
||||
* a link.
|
||||
*/
|
||||
protected function getMediaThumbnailUrl(MediaInterface $media, EntityInterface $entity) {
|
||||
$url = NULL;
|
||||
$image_link_setting = $this->getSetting('image_link');
|
||||
// Check if the formatter involves a link.
|
||||
if ($image_link_setting == 'content') {
|
||||
if (!$entity->isNew()) {
|
||||
$url = $entity->toUrl();
|
||||
}
|
||||
}
|
||||
elseif ($image_link_setting === 'media') {
|
||||
$url = $media->toUrl();
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Plugin\QueueWorker;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Queue\QueueWorkerBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Process a queue of media items to fetch their thumbnails.
|
||||
*
|
||||
* @QueueWorker(
|
||||
* id = "media_entity_thumbnail",
|
||||
* title = @Translation("Thumbnail downloader"),
|
||||
* cron = {"time" = 60}
|
||||
* )
|
||||
*/
|
||||
class ThumbnailDownloader extends QueueWorkerBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity type manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* Entity type manager service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processItem($data) {
|
||||
/** @var \Drupal\media\Entity\Media $media */
|
||||
if ($media = $this->entityTypeManager->getStorage('media')->load($data['id'])) {
|
||||
$media->updateQueuedThumbnail();
|
||||
$media->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Plugin\media\Source;
|
||||
|
||||
use Drupal\file\FileInterface;
|
||||
use Drupal\media\MediaInterface;
|
||||
use Drupal\media\MediaTypeInterface;
|
||||
use Drupal\media\MediaSourceBase;
|
||||
|
||||
/**
|
||||
* File entity media source.
|
||||
*
|
||||
* @see \Drupal\file\FileInterface
|
||||
*
|
||||
* @MediaSource(
|
||||
* id = "file",
|
||||
* label = @Translation("File"),
|
||||
* description = @Translation("Use local files for reusable media."),
|
||||
* allowed_field_types = {"file"},
|
||||
* default_thumbnail_filename = "generic.png"
|
||||
* )
|
||||
*/
|
||||
class File extends MediaSourceBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadataAttributes() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(MediaInterface $media, $attribute_name) {
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file = $media->get($this->configuration['source_field'])->entity;
|
||||
// If the source field is not required, it may be empty.
|
||||
if (!$file) {
|
||||
return parent::getMetadata($media, $attribute_name);
|
||||
}
|
||||
switch ($attribute_name) {
|
||||
case 'default_name':
|
||||
return $file->getFilename();
|
||||
|
||||
case 'thumbnail_uri':
|
||||
return $this->getThumbnail($file) ?: parent::getMetadata($media, $attribute_name);
|
||||
|
||||
default:
|
||||
return parent::getMetadata($media, $attribute_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the thumbnail image URI based on a file entity.
|
||||
*
|
||||
* @param \Drupal\file\FileInterface $file
|
||||
* A file entity.
|
||||
*
|
||||
* @return string
|
||||
* File URI of the thumbnail image or NULL if there is no specific icon.
|
||||
*/
|
||||
protected function getThumbnail(FileInterface $file) {
|
||||
$icon_base = $this->configFactory->get('media.settings')->get('icon_base_uri');
|
||||
|
||||
// We try to automatically use the most specific icon present in the
|
||||
// $icon_base directory, based on the MIME type. For instance, if an
|
||||
// icon file named "pdf.png" is present, it will be used if the file
|
||||
// matches this MIME type.
|
||||
$mimetype = $file->getMimeType();
|
||||
$mimetype = explode('/', $mimetype);
|
||||
|
||||
$icon_names = [
|
||||
$mimetype[0] . '--' . $mimetype[1],
|
||||
$mimetype[1],
|
||||
$mimetype[0],
|
||||
];
|
||||
foreach ($icon_names as $icon_name) {
|
||||
$thumbnail = $icon_base . '/' . $icon_name . '.png';
|
||||
if (is_file($thumbnail)) {
|
||||
return $thumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createSourceField(MediaTypeInterface $type) {
|
||||
return parent::createSourceField($type)->set('settings', ['file_extensions' => 'txt doc docx pdf']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Plugin\media\Source;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\File\FileSystem;
|
||||
use Drupal\Core\Image\ImageFactory;
|
||||
use Drupal\media\MediaInterface;
|
||||
use Drupal\media\MediaTypeInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Image entity media source.
|
||||
*
|
||||
* @see \Drupal\Core\Image\ImageInterface
|
||||
*
|
||||
* @MediaSource(
|
||||
* id = "image",
|
||||
* label = @Translation("Image"),
|
||||
* description = @Translation("Use local images for reusable media."),
|
||||
* allowed_field_types = {"image"},
|
||||
* default_thumbnail_filename = "no-thumbnail.png"
|
||||
* )
|
||||
*/
|
||||
class Image extends File {
|
||||
|
||||
/**
|
||||
* Key for "image width" metadata attribute.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const METADATA_ATTRIBUTE_WIDTH = 'width';
|
||||
|
||||
/**
|
||||
* Key for "image height" metadata attribute.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const METADATA_ATTRIBUTE_HEIGHT = 'height';
|
||||
|
||||
/**
|
||||
* The image factory service.
|
||||
*
|
||||
* @var \Drupal\Core\Image\ImageFactory
|
||||
*/
|
||||
protected $imageFactory;
|
||||
|
||||
/**
|
||||
* The file system service.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileSystem
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* Entity type manager service.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* Entity field manager service.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type plugin manager service.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\Core\Image\ImageFactory $image_factory
|
||||
* The image factory.
|
||||
* @param \Drupal\Core\File\FileSystem $file_system
|
||||
* The file system service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory, ImageFactory $image_factory, FileSystem $file_system) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
|
||||
|
||||
$this->imageFactory = $image_factory;
|
||||
$this->fileSystem = $file_system;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('config.factory'),
|
||||
$container->get('image.factory'),
|
||||
$container->get('file_system')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadataAttributes() {
|
||||
$attributes = parent::getMetadataAttributes();
|
||||
|
||||
$attributes += [
|
||||
static::METADATA_ATTRIBUTE_WIDTH => $this->t('Width'),
|
||||
static::METADATA_ATTRIBUTE_HEIGHT => $this->t('Height'),
|
||||
];
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(MediaInterface $media, $name) {
|
||||
// Get the file and image data.
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file = $media->get($this->configuration['source_field'])->entity;
|
||||
// If the source field is not required, it may be empty.
|
||||
if (!$file) {
|
||||
return parent::getMetadata($media, $name);
|
||||
}
|
||||
|
||||
$uri = $file->getFileUri();
|
||||
$image = $this->imageFactory->get($uri);
|
||||
switch ($name) {
|
||||
case static::METADATA_ATTRIBUTE_WIDTH:
|
||||
return $image->getWidth() ?: NULL;
|
||||
|
||||
case static::METADATA_ATTRIBUTE_HEIGHT:
|
||||
return $image->getHeight() ?: NULL;
|
||||
|
||||
case 'thumbnail_uri':
|
||||
return $uri;
|
||||
}
|
||||
|
||||
return parent::getMetadata($media, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createSourceField(MediaTypeInterface $type) {
|
||||
/** @var \Drupal\field\FieldConfigInterface $field */
|
||||
$field = parent::createSourceField($type);
|
||||
|
||||
// Reset the field to its default settings so that we don't inherit the
|
||||
// settings from the parent class' source field.
|
||||
$settings = $this->fieldTypeManager->getDefaultFieldSettings($field->getType());
|
||||
|
||||
return $field->set('settings', $settings);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Plugin\views\wizard;
|
||||
|
||||
use Drupal\views\Plugin\views\wizard\WizardPluginBase;
|
||||
|
||||
/**
|
||||
* Provides Views creation wizard for Media.
|
||||
*
|
||||
* @ViewsWizard(
|
||||
* id = "media",
|
||||
* base_table = "media_field_data",
|
||||
* title = @Translation("Media")
|
||||
* )
|
||||
*/
|
||||
class Media extends WizardPluginBase {
|
||||
|
||||
/**
|
||||
* Set the created column.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $createdColumn = 'media_field_data-created';
|
||||
|
||||
/**
|
||||
* Set default values for the filters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filters = [
|
||||
'status' => [
|
||||
'value' => '1',
|
||||
'table' => 'media_field_data',
|
||||
'field' => 'status',
|
||||
'plugin_id' => 'boolean',
|
||||
'entity_type' => 'media',
|
||||
'entity_field' => 'status',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAvailableSorts() {
|
||||
return [
|
||||
'media_field_data-name:DESC' => $this->t('Media name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defaultDisplayOptions() {
|
||||
$display_options = parent::defaultDisplayOptions();
|
||||
|
||||
// Add permission-based access control.
|
||||
$display_options['access']['type'] = 'perm';
|
||||
$display_options['access']['options']['perm'] = 'view media';
|
||||
|
||||
// Remove the default fields, since we are customizing them here.
|
||||
unset($display_options['fields']);
|
||||
|
||||
// Add the name field, so that the display has content if the user switches
|
||||
// to a row style that uses fields.
|
||||
$display_options['fields']['name']['id'] = 'name';
|
||||
$display_options['fields']['name']['table'] = 'media_field_data';
|
||||
$display_options['fields']['name']['field'] = 'name';
|
||||
$display_options['fields']['name']['entity_type'] = 'media';
|
||||
$display_options['fields']['name']['entity_field'] = 'media';
|
||||
$display_options['fields']['name']['label'] = '';
|
||||
$display_options['fields']['name']['alter']['alter_text'] = 0;
|
||||
$display_options['fields']['name']['alter']['make_link'] = 0;
|
||||
$display_options['fields']['name']['alter']['absolute'] = 0;
|
||||
$display_options['fields']['name']['alter']['trim'] = 0;
|
||||
$display_options['fields']['name']['alter']['word_boundary'] = 0;
|
||||
$display_options['fields']['name']['alter']['ellipsis'] = 0;
|
||||
$display_options['fields']['name']['alter']['strip_tags'] = 0;
|
||||
$display_options['fields']['name']['alter']['html'] = 0;
|
||||
$display_options['fields']['name']['hide_empty'] = 0;
|
||||
$display_options['fields']['name']['empty_zero'] = 0;
|
||||
$display_options['fields']['name']['settings']['link_to_entity'] = 1;
|
||||
$display_options['fields']['name']['plugin_id'] = 'field';
|
||||
|
||||
return $display_options;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\media\Plugin\views\wizard;
|
||||
|
||||
use Drupal\views\Plugin\views\wizard\WizardPluginBase;
|
||||
|
||||
/**
|
||||
* Provides Views creation wizard for Media revisions.
|
||||
*
|
||||
* @ViewsWizard(
|
||||
* id = "media_revision",
|
||||
* base_table = "media_field_revision",
|
||||
* title = @Translation("Media revisions")
|
||||
* )
|
||||
*/
|
||||
class MediaRevision extends WizardPluginBase {
|
||||
|
||||
/**
|
||||
* Set the created column.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $createdColumn = 'media_field_revision-created';
|
||||
|
||||
/**
|
||||
* Set default values for the filters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $filters = [
|
||||
'status' => [
|
||||
'value' => '1',
|
||||
'table' => 'media_field_revision',
|
||||
'field' => 'status',
|
||||
'plugin_id' => 'boolean',
|
||||
'entity_type' => 'media',
|
||||
'entity_field' => 'status',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defaultDisplayOptions() {
|
||||
$display_options = parent::defaultDisplayOptions();
|
||||
|
||||
// Add permission-based access control.
|
||||
$display_options['access']['type'] = 'perm';
|
||||
$display_options['access']['options']['perm'] = 'view all revisions';
|
||||
|
||||
// Remove the default fields, since we are customizing them here.
|
||||
unset($display_options['fields']);
|
||||
|
||||
// Add the changed field.
|
||||
$display_options['fields']['changed']['id'] = 'changed';
|
||||
$display_options['fields']['changed']['table'] = 'media_field_revision';
|
||||
$display_options['fields']['changed']['field'] = 'changed';
|
||||
$display_options['fields']['changed']['entity_type'] = 'media';
|
||||
$display_options['fields']['changed']['entity_field'] = 'changed';
|
||||
$display_options['fields']['changed']['alter']['alter_text'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['make_link'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['absolute'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['trim'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['word_boundary'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['ellipsis'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['strip_tags'] = FALSE;
|
||||
$display_options['fields']['changed']['alter']['html'] = FALSE;
|
||||
$display_options['fields']['changed']['hide_empty'] = FALSE;
|
||||
$display_options['fields']['changed']['empty_zero'] = FALSE;
|
||||
$display_options['fields']['changed']['plugin_id'] = 'field';
|
||||
$display_options['fields']['changed']['type'] = 'timestamp';
|
||||
$display_options['fields']['changed']['settings']['date_format'] = 'medium';
|
||||
$display_options['fields']['changed']['settings']['custom_date_format'] = '';
|
||||
$display_options['fields']['changed']['settings']['timezone'] = '';
|
||||
|
||||
// Add the name field.
|
||||
$display_options['fields']['name']['id'] = 'name';
|
||||
$display_options['fields']['name']['table'] = 'media_field_revision';
|
||||
$display_options['fields']['name']['field'] = 'name';
|
||||
$display_options['fields']['name']['entity_type'] = 'media';
|
||||
$display_options['fields']['name']['entity_field'] = 'name';
|
||||
$display_options['fields']['name']['label'] = '';
|
||||
$display_options['fields']['name']['alter']['alter_text'] = 0;
|
||||
$display_options['fields']['name']['alter']['make_link'] = 0;
|
||||
$display_options['fields']['name']['alter']['absolute'] = 0;
|
||||
$display_options['fields']['name']['alter']['trim'] = 0;
|
||||
$display_options['fields']['name']['alter']['word_boundary'] = 0;
|
||||
$display_options['fields']['name']['alter']['ellipsis'] = 0;
|
||||
$display_options['fields']['name']['alter']['strip_tags'] = 0;
|
||||
$display_options['fields']['name']['alter']['html'] = 0;
|
||||
$display_options['fields']['name']['hide_empty'] = 0;
|
||||
$display_options['fields']['name']['empty_zero'] = 0;
|
||||
$display_options['fields']['name']['settings']['link_to_entity'] = 0;
|
||||
$display_options['fields']['name']['plugin_id'] = 'field';
|
||||
|
||||
return $display_options;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user