Commit 81b87f93 authored by Gábor Hojtsy's avatar Gábor Hojtsy

Issue #2831937 by mtodor, seanB, Wim Leers, phenaproxima, l0ke, webflo,...

Issue #2831937 by mtodor, seanB, Wim Leers, phenaproxima, l0ke, webflo, tedbow, Gábor Hojtsy, slashrsm, naveenvalecha, mondrake, oriol_e9g, dawehner, vijaycs85: Add "Image" MediaSource plugin
parent f62b4c76
langcode: en
status: true
dependencies:
config:
- field.field.media.image.field_media_image
- image.style.thumbnail
- media.type.image
module:
- image
id: media.image.default
targetEntityType: media
bundle: image
mode: default
content:
created:
type: datetime_timestamp
weight: 10
region: content
settings: { }
third_party_settings: { }
field_media_image:
settings:
progress_indicator: throbber
preview_image_style: thumbnail
third_party_settings: { }
type: image_image
weight: 26
region: content
name:
type: string_textfield
weight: -5
region: content
settings:
size: 60
placeholder: ''
third_party_settings: { }
uid:
type: entity_reference_autocomplete
weight: 5
settings:
match_operator: CONTAINS
size: 60
placeholder: ''
region: content
third_party_settings: { }
hidden: { }
langcode: en
status: true
dependencies:
config:
- field.field.media.image.field_media_image
- image.style.thumbnail
- media.type.image
module:
- image
- user
id: media.image.default
targetEntityType: media
bundle: image
mode: default
content:
created:
label: hidden
type: timestamp
weight: 0
region: content
settings:
date_format: medium
custom_date_format: ''
timezone: ''
third_party_settings: { }
field_media_image:
label: above
settings:
image_style: ''
image_link: ''
third_party_settings: { }
type: image
weight: 6
region: content
thumbnail:
type: image
weight: 5
label: hidden
settings:
image_style: thumbnail
image_link: ''
region: content
third_party_settings: { }
uid:
label: hidden
type: author
weight: 0
region: content
settings: { }
third_party_settings: { }
hidden: { }
langcode: en
status: true
dependencies:
config:
- field.storage.media.field_media_image
- media.type.image
enforced:
module:
- media
module:
- image
id: media.image.field_media_image
field_name: field_media_image
entity_type: media
bundle: image
label: Image
description: ''
required: true
translatable: true
default_value: { }
default_value_callback: ''
settings:
alt_field: true
alt_field_required: true
title_field: false
title_field_required: false
max_resolution: ''
min_resolution: ''
default_image:
uuid: null
alt: ''
title: ''
width: null
height: null
file_directory: '[date:custom:Y]-[date:custom:m]'
file_extensions: 'png gif jpg jpeg'
max_filesize: ''
handler: 'default:file'
handler_settings: { }
field_type: image
......@@ -20,6 +20,6 @@ module: file
locked: true
cardinality: 1
translatable: true
indexes: { }
indexes: { }
persist_with_no_fields: false
custom_storage: false
langcode: en
status: true
dependencies:
enforced:
module:
- media
module:
- file
- image
- media
id: media.field_media_image
field_name: field_media_image
entity_type: media
type: image
settings:
default_image:
uuid: null
alt: ''
title: ''
width: null
height: null
target_type: file
display_field: false
display_default: false
uri_scheme: public
module: image
locked: true
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
......@@ -9,4 +9,4 @@ queue_thumbnail_downloads: false
new_revision: true
source_configuration:
source_field: field_media_file
field_map: { }
field_map: { }
langcode: en
status: true
dependencies: { }
id: image
label: Image
description: "Use local images for reusable media."
source: image
queue_thumbnail_downloads: false
new_revision: true
source_configuration:
source_field: field_media_image
field_map: { }
......@@ -48,6 +48,10 @@ media.source.file:
type: media.source.field_aware
label: '"File" media source configuration'
media.source.image:
type: media.source.field_aware
label: '"Image" media source configuration'
media.source.field_aware:
type: mapping
mapping:
......
<?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);
}
}
......@@ -3,6 +3,7 @@
namespace Drupal\Tests\media\Functional;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Entity\FieldConfig;
/**
* Tests the revisionability of media entities.
......@@ -44,6 +45,46 @@ public function testFileMediaRevision() {
$this->assertRevisionCount($media, 2);
}
/**
* Tests creating revisions of a Image media item.
*/
public function testImageMediaRevision() {
$assert = $this->assertSession();
/** @var \Drupal\field\FieldConfigInterface $field */
// Disable the alt text field, because this is not a JavaScript test and
// the alt text field will therefore not appear without a full page refresh.
$field = FieldConfig::load('media.image.field_media_image');
$settings = $field->getSettings();
$settings['alt_field'] = FALSE;
$settings['alt_field_required'] = FALSE;
$field->set('settings', $settings);
$field->save();
// Create a media item.
$this->drupalGet('/media/add/image');
$page = $this->getSession()->getPage();
$page->fillField('Name', 'Foobar');
$page->attachFileToField('Image', \Drupal::root() . '/core/modules/media/tests/fixtures/example_1.jpeg');
$page->pressButton('Save and publish');
$assert->addressMatches('/^\/media\/[0-9]+$/');
// The media item was just created, so it should only have one revision.
$media = $this->container
->get('entity_type.manager')
->getStorage('media')
->load(1);
$this->assertRevisionCount($media, 1);
// If we edit the item, we should get a new revision.
$this->drupalGet('/media/1/edit');
$assert->checkboxChecked('Create new revision');
$page = $this->getSession()->getPage();
$page->fillField('Name', 'Foobaz');
$page->pressButton('Save and keep published');
$this->assertRevisionCount($media, 2);
}
/**
* Asserts that an entity has a certain number of revisions.
*
......
......@@ -33,6 +33,7 @@ protected function setUp() {
// We need to test without any default configuration in place.
// @TODO: Remove this when https://www.drupal.org/node/2883813 lands.
MediaType::load('file')->delete();
MediaType::load('image')->delete();
}
/**
......
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\media\Plugin\media\Source\Image;
/**
* Tests the image media source.
*
* @group media
*/
class MediaSourceImageTest extends MediaSourceTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// We need to test without any default configuration in place.
// @TODO: Remove this as part of https://www.drupal.org/node/2883813.
MediaType::load('file')->delete();
MediaType::load('image')->delete();
}
/**
* Tests the image media source.
*/
public function testMediaImageSource() {
$media_type_id = 'test_media_image_type';
$source_field_id = 'field_media_image';
$provided_fields = [
Image::METADATA_ATTRIBUTE_WIDTH,
Image::METADATA_ATTRIBUTE_HEIGHT,
];
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->doTestCreateMediaType($media_type_id, 'image', $provided_fields);
// Create custom fields for the media type to store metadata attributes.
$fields = [
'field_string_width' => 'string',
'field_string_height' => 'string',
];
$this->createMediaTypeFields($fields, $media_type_id);
// Hide the name field widget to test default name generation.
$this->hideMediaTypeFieldWidget('name', $media_type_id);
$this->drupalGet("admin/structure/media/manage/{$media_type_id}");
$page->selectFieldOption("field_map[" . Image::METADATA_ATTRIBUTE_WIDTH . "]", 'field_string_width');
$page->selectFieldOption("field_map[" . Image::METADATA_ATTRIBUTE_HEIGHT . "]", 'field_string_height');
$page->pressButton('Save');
// Create a media item.
$this->drupalGet("media/add/{$media_type_id}");
$page->attachFileToField("files[{$source_field_id}_0]", \Drupal::root() . '/core/modules/media/tests/fixtures/example_1.jpeg');
$assert_session->assertWaitOnAjaxRequest();
$page->fillField("{$source_field_id}[0][alt]", 'Image Alt Text 1');
$page->pressButton('Save and publish');
$assert_session->addressEquals('media/1');
// Make sure the thumbnail is displayed from uploaded image.
$assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', 'example_1.jpeg');
// Load the media and check that all fields are properly populated.
$media = Media::load(1);
$this->assertEquals('example_1.jpeg', $media->label());
$this->assertEquals('200', $media->get('field_string_width')->value);
$this->assertEquals('89', $media->get('field_string_height')->value);
}
}
......@@ -37,10 +37,22 @@ protected function createMediaTypeField($field_name, $field_type, $media_type_id
// Make the field widget visible in the form display.
$component = \Drupal::service('plugin.manager.field.widget')
->prepareConfiguration($field_type, []);
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity_form_display */
// @todo Replace entity_get_form_display() when #2367933 is done.
// https://www.drupal.org/node/2872159.
$entity_form_display = entity_get_form_display('media', $media_type_id, 'default');
$entity_form_display->setComponent($field_name, $component)
->save();
// 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_display = entity_get_display('media', $media_type_id, 'default');
$entity_display->setComponent($field_name, $component)
->save();
}
/**
......
......@@ -42,6 +42,7 @@ protected function setUp() {
// We need to test without any default configuration in place.
// @TODO: Remove this as part of https://www.drupal.org/node/2883813.
MediaType::load('file')->delete();
MediaType::load('image')->delete();
}
/**
......
......@@ -20,6 +20,7 @@ protected function setUp() {
// We need to test without any default configuration in place.
// @TODO: Remove this as part of https://www.drupal.org/node/2883813.
MediaType::load('file')->delete();
MediaType::load('image')->delete();
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment