Browse Source
* Condition for checking how a media is referenced. * Tests. Coding standards * Refining query to include content typepull/756/head
dannylamb
7 years ago
committed by
Jared Whiklo
3 changed files with 340 additions and 0 deletions
@ -0,0 +1,189 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace Drupal\islandora\Plugin\Condition; |
||||||
|
|
||||||
|
use Drupal\Core\Condition\ConditionPluginBase; |
||||||
|
use Drupal\Core\Entity\EntityStorageInterface; |
||||||
|
use Drupal\Core\Entity\EntityFieldManager; |
||||||
|
use Drupal\Core\Entity\Query\QueryFactory; |
||||||
|
use Drupal\Core\Form\FormStateInterface; |
||||||
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; |
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
||||||
|
|
||||||
|
/** |
||||||
|
* Condition to see if a Media is referenced by a Node using a particular field. |
||||||
|
* |
||||||
|
* @Condition( |
||||||
|
* id = "is_referenced_media", |
||||||
|
* label = @Translation("Is Referenced Media"), |
||||||
|
* context = { |
||||||
|
* "media" = @ContextDefinition("entity:media", label = @Translation("Media")) |
||||||
|
* } |
||||||
|
* ) |
||||||
|
*/ |
||||||
|
class IsReferencedMedia extends ConditionPluginBase implements ContainerFactoryPluginInterface { |
||||||
|
|
||||||
|
/** |
||||||
|
* Content type storage. |
||||||
|
* |
||||||
|
* @var \Drupal\Core\Entity\EntityStorageInterface |
||||||
|
*/ |
||||||
|
protected $contentTypeStorage; |
||||||
|
|
||||||
|
/** |
||||||
|
* The entity field manager. |
||||||
|
* |
||||||
|
* @var \Drupal\Core\Entity\EntityStorageInterface |
||||||
|
*/ |
||||||
|
protected $entityFieldManager; |
||||||
|
|
||||||
|
/** |
||||||
|
* Entity query service. |
||||||
|
* |
||||||
|
* @var \Drupal\Core\Entity\Query\QueryFactory |
||||||
|
*/ |
||||||
|
protected $entityQuery; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new IsReferencedMedia instance. |
||||||
|
* |
||||||
|
* @param \Drupal\Core\Entity\EntityStorageInterface $content_type_storage |
||||||
|
* Content type storage. |
||||||
|
* @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager |
||||||
|
* The entity field manager. |
||||||
|
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query |
||||||
|
* Entity query service. |
||||||
|
* @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 $content_type_storage, |
||||||
|
EntityFieldManager $entity_field_manager, |
||||||
|
QueryFactory $entity_query, |
||||||
|
array $configuration, |
||||||
|
$plugin_id, |
||||||
|
$plugin_definition |
||||||
|
) { |
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition); |
||||||
|
$this->contentTypeStorage = $content_type_storage; |
||||||
|
$this->entityFieldManager = $entity_field_manager; |
||||||
|
$this->entityQuery = $entity_query; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { |
||||||
|
return new static( |
||||||
|
$container->get('entity_type.manager')->getStorage('node_type'), |
||||||
|
$container->get('entity_field.manager'), |
||||||
|
$container->get('entity.query'), |
||||||
|
$configuration, |
||||||
|
$plugin_id, |
||||||
|
$plugin_definition |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function buildConfigurationForm(array $form, FormStateInterface $form_state) { |
||||||
|
// Get all entity reference fields that target Media. |
||||||
|
$media_reference_fields = $this->entityQuery->get('field_storage_config') |
||||||
|
->condition('entity_type', 'node') |
||||||
|
->condition('type', 'entity_reference') |
||||||
|
->condition('settings.target_type', 'media') |
||||||
|
->execute(); |
||||||
|
|
||||||
|
// Trim off the preceding 'node.'. |
||||||
|
$media_reference_fields = array_map( |
||||||
|
function ($field) { |
||||||
|
return ltrim($field, 'node.'); |
||||||
|
}, |
||||||
|
$media_reference_fields |
||||||
|
); |
||||||
|
|
||||||
|
// Flip the results so it can be used in an array_intersect_key later on. |
||||||
|
$media_reference_fields = array_flip($media_reference_fields); |
||||||
|
|
||||||
|
// Get all content types. |
||||||
|
$content_types = $this->contentTypeStorage->loadMultiple(); |
||||||
|
|
||||||
|
// Build up the 2D options array. |
||||||
|
$options = []; |
||||||
|
foreach ($content_types as $content_type) { |
||||||
|
// Filter fields to those we know are media references. |
||||||
|
$all_fields = $this->entityFieldManager->getFieldDefinitions('node', $content_type->id()); |
||||||
|
$reference_fields = array_intersect_key($all_fields, $media_reference_fields); |
||||||
|
|
||||||
|
// First dimension is keyed by the content type label. |
||||||
|
// Second dimension is keyed by the content_type machine name concatenated |
||||||
|
// with the field name. The content type machine name is needed for |
||||||
|
// disambiguation, otherwise fields attached to multiple content types |
||||||
|
// have unexpected behaviour when submitting the form. |
||||||
|
foreach ($reference_fields as $field_name => $field_definition) { |
||||||
|
$content_type_label = $content_type->label(); |
||||||
|
$field_key = $content_type->id() . '|' . $field_name; |
||||||
|
$field_label = $field_definition->getLabel(); |
||||||
|
$options[$content_type_label][$field_key] = $field_label; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Create the 2D select. |
||||||
|
$form['field'] = [ |
||||||
|
'#title' => $this->t('Referenced As'), |
||||||
|
'#description' => $this->t('The field that references the Media.'), |
||||||
|
'#type' => 'select', |
||||||
|
'#options' => $options, |
||||||
|
'#default_value' => isset($this->configuration['field']) ? $this->configuration['field'] : '', |
||||||
|
'#size' => 10, |
||||||
|
]; |
||||||
|
|
||||||
|
return parent::buildConfigurationForm($form, $form_state); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { |
||||||
|
$this->configuration['field'] = $form_state->getValue('field'); |
||||||
|
parent::submitConfigurationForm($form, $form_state); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function defaultConfiguration() { |
||||||
|
return ['field' => ''] + parent::defaultConfiguration(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function summary() { |
||||||
|
return $this->t('The Media is referenced by a Node using the specified field.'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function evaluate() { |
||||||
|
// Check to see that the media is referenced by a node of the specified |
||||||
|
// type using the specified field. |
||||||
|
$media = $this->getContextValue('media'); |
||||||
|
$field_key = $this->configuration['field']; |
||||||
|
list($content_type, $field) = explode('|', $field_key); |
||||||
|
return $this->entityQuery->get('node') |
||||||
|
->condition('type', $content_type) |
||||||
|
->condition("$field.target_id", $media->id()) |
||||||
|
->execute(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,144 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace Drupal\Tests\islandora\Functional; |
||||||
|
|
||||||
|
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait; |
||||||
|
use Drupal\Tests\media_entity\Functional\MediaEntityFunctionalTestTrait; |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests the IsReferencedMedia condition. |
||||||
|
* |
||||||
|
* @group islandora |
||||||
|
*/ |
||||||
|
class IsReferencedMediaTest extends IslandoraFunctionalTestBase { |
||||||
|
|
||||||
|
use EntityReferenceTestTrait; |
||||||
|
use MediaEntityFunctionalTestTrait; |
||||||
|
|
||||||
|
/** |
||||||
|
* Media to be referenced. |
||||||
|
* |
||||||
|
* @var \Drupal\media\MediaInterface |
||||||
|
*/ |
||||||
|
protected $referenced; |
||||||
|
|
||||||
|
/** |
||||||
|
* An unreferenced Media to use as a control. |
||||||
|
* |
||||||
|
* @var \Drupal\media\MediaInterface |
||||||
|
*/ |
||||||
|
protected $notReferenced; |
||||||
|
|
||||||
|
/** |
||||||
|
* A Media referenced by another type the Condition is not set to expect. |
||||||
|
* |
||||||
|
* @var \Drupal\media\MediaInterface |
||||||
|
*/ |
||||||
|
protected $referencedByAnother; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function setUp() { |
||||||
|
parent::setUp(); |
||||||
|
|
||||||
|
// Create a test content type with a media reference field. |
||||||
|
$test_type_with_reference = $this->container->get('entity_type.manager')->getStorage('node_type')->create([ |
||||||
|
'type' => 'test_type_with_reference', |
||||||
|
'label' => 'Test Type With Reference', |
||||||
|
]); |
||||||
|
$test_type_with_reference->save(); |
||||||
|
$this->createEntityReferenceField('node', 'test_type_with_reference', 'field_media', 'Media Entity', 'media', 'default', [], 2); |
||||||
|
|
||||||
|
$another_test_type_with_reference = $this->container->get('entity_type.manager')->getStorage('node_type')->create([ |
||||||
|
'type' => 'another_test_type_with_reference', |
||||||
|
'label' => 'Another Test Type With Reference', |
||||||
|
]); |
||||||
|
$another_test_type_with_reference->save(); |
||||||
|
$this->createEntityReferenceField('node', 'another_test_type_with_reference', 'field_media', 'Media Entity', 'media', 'default', [], 2); |
||||||
|
|
||||||
|
// Create the media. |
||||||
|
$media_bundle = $this->drupalCreateMediaBundle(); |
||||||
|
$this->referenced = $this->container->get('entity_type.manager')->getStorage('media')->create([ |
||||||
|
'bundle' => $media_bundle->id(), |
||||||
|
'name' => 'Referenced Media', |
||||||
|
]); |
||||||
|
$this->referenced->save(); |
||||||
|
|
||||||
|
$this->notReferenced = $this->container->get('entity_type.manager')->getStorage('media')->create([ |
||||||
|
'bundle' => $media_bundle->id(), |
||||||
|
'name' => 'Unreferenced Media', |
||||||
|
]); |
||||||
|
$this->notReferenced->save(); |
||||||
|
|
||||||
|
$this->referencedByAnother = $this->container->get('entity_type.manager')->getStorage('media')->create([ |
||||||
|
'bundle' => $media_bundle->id(), |
||||||
|
'name' => 'Referenced By Another', |
||||||
|
]); |
||||||
|
$this->referencedByAnother->save(); |
||||||
|
|
||||||
|
// Reference one by a node of the type we're expecting. |
||||||
|
$node = $this->container->get('entity_type.manager')->getStorage('node')->create([ |
||||||
|
'type' => 'test_type_with_reference', |
||||||
|
'title' => 'Referencer', |
||||||
|
'field_media' => [$this->referenced->id()], |
||||||
|
]); |
||||||
|
$node->save(); |
||||||
|
|
||||||
|
// Reference one by a node of the type we're not expecting. |
||||||
|
$another_node = $this->container->get('entity_type.manager')->getStorage('node')->create([ |
||||||
|
'type' => 'another_test_type_with_reference', |
||||||
|
'title' => 'Another Referencer', |
||||||
|
'field_media' => [$this->referencedByAnother->id()], |
||||||
|
]); |
||||||
|
$node->save(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @covers \Drupal\islandora\ContextProvider\MediaContextProvider::__construct |
||||||
|
* @covers \Drupal\islandora\ContextProvider\MediaContextProvider::getRuntimeContexts |
||||||
|
* @covers \Drupal\islandora\IslandoraContextManager::evaluateContexts |
||||||
|
* @covers \Drupal\islandora\IslandoraContextManager::applyContexts |
||||||
|
* @covers \Drupal\islandora\Plugin\Condition\IsReferencedMedia::buildConfigurationForm |
||||||
|
* @covers \Drupal\islandora\Plugin\Condition\IsReferencedMedia::submitConfigurationForm |
||||||
|
* @covers \Drupal\islandora\Plugin\Condition\IsReferencedMedia::evaluate |
||||||
|
* @covers \Drupal\islandora\PresetReaction\PresetReaction::buildConfigurationForm |
||||||
|
* @covers \Drupal\islandora\PresetReaction\PresetReaction::submitConfigurationForm |
||||||
|
* @covers \Drupal\islandora\PresetReaction\PresetReaction::execute |
||||||
|
* @covers \Drupal\islandora\IslandoraServiceProvider::alter |
||||||
|
*/ |
||||||
|
public function testIsReferencedMedia() { |
||||||
|
// Create a test user. |
||||||
|
$account = $this->drupalCreateUser([ |
||||||
|
'administer contexts', |
||||||
|
'view media', |
||||||
|
'update any media', |
||||||
|
]); |
||||||
|
$this->drupalLogin($account); |
||||||
|
|
||||||
|
$this->createContext('Test', 'test'); |
||||||
|
|
||||||
|
// Add the condition. |
||||||
|
$this->drupalGet("admin/structure/context/test/condition/add/is_referenced_media"); |
||||||
|
$this->getSession()->getPage()->findById("edit-conditions-is-referenced-media-field")->selectOption('test_type_with_reference|field_media'); |
||||||
|
$this->getSession()->getPage()->pressButton('Save and continue'); |
||||||
|
|
||||||
|
// Add the reaction to say "Hello World!". |
||||||
|
$this->addPresetReaction('test', 'index', 'hello_world'); |
||||||
|
|
||||||
|
// Edit the referenced node. "Hello World!" should be output to the screen. |
||||||
|
$this->postEntityEditForm("media/{$this->referenced->id()}", ['name[0][value]' => 'Referenced Media Changed'], 'Save and keep published'); |
||||||
|
$this->assertSession()->pageTextContains("Hello World!"); |
||||||
|
|
||||||
|
// Edit the unreferenced node. "Hello World!" should not be output to the |
||||||
|
// screen. |
||||||
|
$this->postEntityEditForm("media/{$this->notReferenced->id()}", ['name[0][value]' => 'Unreferenced Media Changed'], 'Save and keep published'); |
||||||
|
$this->assertSession()->pageTextNotContains("Hello World!"); |
||||||
|
|
||||||
|
// Edit the node referenced by a different type. "Hello World!" should not |
||||||
|
// be output to the screen. |
||||||
|
$this->postEntityEditForm("media/{$this->referencedByAnother->id()}", ['name[0][value]' => 'Referenced By Another Changed'], 'Save and keep published'); |
||||||
|
$this->assertSession()->pageTextNotContains("Hello World!"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue