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

Commit

Permalink
Add Media Context and Media Bundle Condition plugins.
Browse files Browse the repository at this point in the history
  • Loading branch information
steveoliver committed Aug 1, 2016
1 parent c2eef44 commit 4a8b1df
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config/schema/media_entity.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,11 @@ action.configuration.media_publish_action:
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
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

0 comments on commit 4a8b1df

Please sign in to comment.