Skip to content
This repository has been archived by the owner on Jan 5, 2018. It is now read-only.

Add Media Context and Media Bundle Condition plugins. #79

Open
wants to merge 1 commit into
base: 8.x-1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions config/schema/media_entity.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ action.configuration.media_unpublish_action:
type: action_configuration_default
label: 'Unpublish media configuration'

condition.plugin.media_bundle:
type: condition.plugin
mapping:
bundles:
type: sequence
sequence:
type: string

field.formatter.settings.media_thumbnail:
type: mapping
label: 'Media thumbnail field display format settings'
Expand All @@ -67,3 +75,4 @@ field.formatter.settings.media_thumbnail:
image_style:
type: string
label: 'Image style'

5 changes: 5 additions & 0 deletions media_entity.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ services:
plugin.manager.media_entity.type:
class: Drupal\media_entity\MediaTypeManager
parent: default_plugin_manager
media_entity.media_bundle_context:
class: Drupal\media_entity\ContextProvider\MediaRouteContext
arguments: ['@current_route_match']
tags:
- { name: 'context_provider' }
72 changes: 72 additions & 0 deletions src/ContextProvider/MediaRouteContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Drupal\media_entity\ContextProvider;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\ContextProviderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\media\Entity\Media;

/**
* Sets the current media as a context on media routes.
*/
class MediaRouteContext implements ContextProviderInterface {

use StringTranslationTrait;

/**
* The route match object.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;

/**
* Constructs a new MediaRouteContext.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match object.
*/
public function __construct(RouteMatchInterface $route_match) {
$this->routeMatch = $route_match;
}

/**
* {@inheritdoc}
*/
public function getRuntimeContexts(array $unqualified_context_ids) {
$result = [];
$context_definition = new ContextDefinition('entity:media', NULL, FALSE);
$value = NULL;
if (($route_object = $this->routeMatch->getRouteObject()) && ($route_contexts = $route_object->getOption('parameters')) && isset($route_contexts['media'])) {
if ($media = $this->routeMatch->getParameter('media')) {
$value = $media;
}
}
elseif ($this->routeMatch->getRouteName() == 'media.add') {
$media_type = $this->routeMatch->getParameter('media_bundle');
$value = Media::create(array('type' => $media_type->id()));
}

$cacheability = new CacheableMetadata();
$cacheability->setCacheContexts(['route']);

$context = new Context($context_definition, $value);
$context->addCacheableDependency($cacheability);
$result['media'] = $context;

return $result;
}

/**
* {@inheritdoc}
*/
public function getAvailableContexts() {
$context = new Context(new ContextDefinition('entity:media', $this->t('Media from URL')));
return ['media' => $context];
}

}
121 changes: 121 additions & 0 deletions src/Plugin/Condition/MediaBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace Drupal\media_entity\Plugin\Condition;

use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Provides a 'Media bundles' condition.
*
* @Condition(
* id = "media_bundle",
* label = @Translation("Media bundles"),
* context = {
* "media" = @ContextDefinition("entity:media", label = @Translation("Media"))
* }
* )
*/
class MediaBundle extends ConditionPluginBase implements ContainerFactoryPluginInterface {

/**
* The entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $entityStorage;

/**
* Creates a new MediaBundle instance.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
* The entity storage.
* @param array $configuration
* The plugin configuration, i.e. an array with configuration values keyed
* by configuration option name. The special key 'context' may be used to
* initialize the defined contexts by setting it to an array of context
* values keyed by context names.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
*/
public function __construct(EntityStorageInterface $entity_storage, array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityStorage = $entity_storage;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('entity.manager')->getStorage('media_bundle'),
$configuration,
$plugin_id,
$plugin_definition
);
}

/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$options = array();
$media_types = $this->entityStorage->loadMultiple();
foreach ($media_types as $type) {
$options[$type->id()] = $type->label();
}
$form['bundles'] = array(
'#title' => $this->t('Media bundles'),
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $this->configuration['bundles'],
);
return parent::buildConfigurationForm($form, $form_state);
}

/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['bundles'] = array_filter($form_state->getValue('bundles'));
parent::submitConfigurationForm($form, $form_state);
}

/**
* {@inheritdoc}
*/
public function summary() {
if (count($this->configuration['bundles']) > 1) {
$bundles = $this->configuration['bundles'];
$last = array_pop($bundles);
$bundles = implode(', ', $bundles);
return $this->t('The media bundle is @bundles or @last', array('@bundles' => $bundles, '@last' => $last));
}
$bundle = reset($this->configuration['bundles']);
return $this->t('The media bundle is @bundle', array('@bundle' => $bundle));
}

/**
* {@inheritdoc}
*/
public function evaluate() {
if (empty($this->configuration['bundles']) && !$this->isNegated()) {
return TRUE;
}
$media = $this->getContextValue('media');
return !empty($this->configuration['bundles'][$media->bundle()]);
}

/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array('bundles' => array()) + parent::defaultConfiguration();
}

}
164 changes: 164 additions & 0 deletions src/Tests/MediaContextConditionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?php

namespace Drupal\media_entity\Tests;

use Drupal\Component\Utility\Xss;
use Drupal\simpletest\WebTestBase;

/**
* Ensures that media context & media bundle condition work correctly.
*
* @group media_entity
*/
class MediaContextConditionTest extends WebTestBase {

use MediaTestTrait;

/**
* The test user.
*
* @var \Drupal\User\UserInterface
*/
protected $adminUser;

/**
* A non-admin test user.
*
* @var \Drupal\User\UserInterface
*/
protected $nonAdminUser;

/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['media_entity', 'media_entity_test_context', 'field_ui', 'views_ui', 'node', 'block', 'entity'];

/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_actions_block');
$this->drupalPlaceBlock('local_tasks_block');
$this->adminUser = $this->drupalCreateUser([
'administer media',
'administer media fields',
'administer media form display',
'administer media display',
'administer media bundles',
// Media entity permissions.
'view media',
'create media',
'update media',
'update any media',
'delete media',
'delete any media',
'access media overview',
// Other permissions.
'access administration pages',
'administer blocks',
'administer views',
'access content overview',
'view all revisions',
]);
$this->drupalLogin($this->adminUser);
}

/**
* Tests the behavior of media context-aware blocks.
*/
public function testMediaContextAwareBlocks() {
$bundle = $this->createMediaBundle();
$media = $this->createMediaItem($bundle);
$expected_text = 'Media ID: ' . $media['id'];

$this->drupalGet('');
$this->assertNoText('Test media context aware block');
$this->assertNoRaw($expected_text);

$block_url = 'admin/structure/block/add/test_media_context_block/classy';
$arguments = array(
':title' => 'Test media context aware block',
':category' => 'Media entity test context',
':href' => $block_url,
);
$pattern = '//tr[.//td/div[text()=:title] and .//td[text()=:category] and .//td//a[contains(@href, :href)]]';

$this->drupalGet('admin/structure/block');
$this->clickLinkPartialName('Place block');
$elements = $this->xpath($pattern, $arguments);
$this->assertTrue(!empty($elements), 'The media context-aware test block appears.');
$definition = \Drupal::service('plugin.manager.block')->getDefinition('test_media_context_block');
$this->assertTrue(!empty($definition), 'The media context-aware test block definition exists.');
$edit = [
'region' => 'content',
'visibility[media_bundle][bundles][' . $bundle['id'] . ']' => TRUE
];
$this->drupalPostForm($block_url, $edit, 'Save block');

$this->drupalGet('');
$this->assertNoText('Test media context aware block', 'Block not found because condition not met (bundle: ' . $bundle['id'] . ').');

$this->drupalGet('media/' . $media['id']);
$this->assertText('Test media context aware block');
$this->assertRaw($expected_text, 'Block found, with media context (condition met).');

}

/**
* Creates and tests a new media bundle.
*
* @return array
* Returns the media bundle fields.
*/
public function createMediaBundle() {
// Generates and holds all media bundle fields.
$name = $this->randomMachineName();
$edit = [
'id' => strtolower($name),
'label' => $name,
'type' => 'generic',
'description' => $this->randomMachineName(),
];

// Create new media bundle.
$this->drupalPostForm('admin/structure/media/add', $edit, t('Save media bundle'));
$this->assertText('The media bundle ' . $name . ' has been added.');

// Check if media bundle is successfully created.
$this->drupalGet('admin/structure/media');
$this->assertResponse(200);
$this->assertRaw($edit['label']);
$this->assertRaw(Xss::filterAdmin($edit['description']));

return $edit;
}

/**
* Creates a media item in the media bundle that is passed along.
*
* @param array $media_bundle
* The media bundle the media item should be assigned to.
*
* @return array
* Returns the
*/
public function createMediaItem($media_bundle) {
// Define the media item name.
$name = $this->randomMachineName();
$edit = [
'name[0][value]' => $name,
];
// Save it and retrieve new media item ID, then return all information.
$this->drupalPostForm('media/add/' . $media_bundle['id'], $edit, t('Save and publish'));
$this->assertTitle($edit['name[0][value]'] . ' | Drupal');
$media_id = \Drupal::entityQuery('media')->execute();
$media_id = reset($media_id);
$edit['id'] = $media_id;

return $edit;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: 'Media entity test context'
type: module
description: 'Provides test media context plugin to test context.'
core: 8.x
package: Testing
version: VERSION
Loading