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