Commit 5cc27d94 authored by alexpott's avatar alexpott

Issue #2216071 by dawehner, damiankloip, Gaelan: Views plugins need a way to...

Issue #2216071 by dawehner, damiankloip, Gaelan: Views plugins need a way to store additional dependencies.
parent da91e5a9
......@@ -376,6 +376,31 @@ protected function addDependency($type, $name) {
return $this;
}
/**
* Adds multiple dependencies.
*
* @param array $dependencies.
* An array of dependencies keyed by the type of dependency. One example:
* @code
* array(
* 'module' => array(
* 'node',
* 'field',
* 'image'
* ),
* );
* @endcode
*
* @see ::addDependency
*/
protected function addDependencies(array $dependencies) {
foreach ($dependencies as $dependency_type => $list) {
foreach ($list as $name) {
$this->addDependency($dependency_type, $name);
}
}
}
/**
* {@inheritdoc}
*/
......
......@@ -51,7 +51,12 @@ class Field extends FieldPluginBase {
*
* @var \Drupal\Core\Field\FieldDefinitionInterface
*/
public $field_info;
protected $fieldDefinition;
/**
* The field config.
*/
protected $fieldConfig;
/**
* Does the field supports multiple field values.
......@@ -140,19 +145,44 @@ public static function create(ContainerInterface $container, array $configuratio
);
}
/**
* Gets the field definition.
*
* @return \Drupal\Core\Field\FieldDefinitionInterface
* The field definition used by this handler.
*/
protected function getFieldDefinition() {
if (!$this->fieldDefinition) {
$field_config = $this->getFieldConfig();
$this->fieldDefinition = FieldDefinition::createFromFieldStorageDefinition($field_config);
}
return $this->fieldDefinition;
}
/**
* Gets the field configuration.
*
* @return \Drupal\field\FieldConfigInterface
*/
protected function getFieldConfig() {
if (!$this->fieldConfig) {
$this->fieldConfig = FieldHelper::fieldInfo()->getField($this->definition['entity_type'], $this->definition['field_name']);
}
return $this->fieldConfig;
}
/**
* Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::init().
*/
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
parent::init($view, $display, $options);
$field_storage_definition = FieldHelper::fieldInfo()->getField($this->definition['entity_type'], $this->definition['field_name']);
$this->field_info = FieldDefinition::createFromFieldStorageDefinition($field_storage_definition);
$this->multiple = FALSE;
$this->limit_values = FALSE;
$cardinality = $this->field_info->getCardinality();
if ($this->field_info->isMultiple()) {
$field_info = $this->getFieldDefinition();
$cardinality = $field_info->getCardinality();
if ($field_info->isMultiple()) {
$this->multiple = TRUE;
// If "Display all values in the same row" is FALSE, then we always limit
......@@ -180,7 +210,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
public function access(AccountInterface $account) {
$base_table = $this->get_base_table();
$access_controller = $this->entityManager->getAccessController($this->definition['entity_tables'][$base_table]);
return $access_controller->fieldAccess('view', $this->field_info, $account);
return $access_controller->fieldAccess('view', $this->getFieldDefinition(), $account);
}
/**
......@@ -227,6 +257,7 @@ public function query($use_groupby = FALSE) {
unset($fields[$entity_type_key]);
}
$field_definition = $this->getFieldDefinition();
if ($use_groupby) {
// Add the fields that we're actually grouping on.
$options = array();
......@@ -240,8 +271,8 @@ public function query($use_groupby = FALSE) {
// Go through the list and determine the actual column name from field api.
foreach ($options as $column) {
$name = $column;
if (isset($this->field_info['storage_details']['sql'][$rkey][$this->table][$column])) {
$name = $this->field_info['storage_details']['sql'][$rkey][$this->table][$column];
if (isset($field_definition['storage_details']['sql'][$rkey][$this->table][$column])) {
$name = $field_definition['storage_details']['sql'][$rkey][$this->table][$column];
}
$fields[$column] = $name;
......@@ -256,7 +287,7 @@ public function query($use_groupby = FALSE) {
$this->addAdditionalFields($fields);
// Filter by langcode, if field translation is enabled.
$field = $this->field_info;
$field = $field_definition;
if ($field->isTranslatable() && !empty($this->view->display_handler->options['field_langcode_add_to_query'])) {
$column = $this->tableAlias . '.langcode';
// By the same reason as field_language the field might be Language::LANGCODE_NOT_SPECIFIED in reality so allow it as well.
......@@ -401,7 +432,7 @@ protected function defineOptions() {
public function buildOptionsForm(&$form, &$form_state) {
parent::buildOptionsForm($form, $form_state);
$field = $this->field_info;
$field = $this->getFieldDefinition();
$formatters = $this->formatterPluginManager->getOptions($field->getType());
$column_names = array_keys($field->getColumns());
......@@ -480,7 +511,7 @@ public function buildOptionsForm(&$form, &$form_state) {
* Provide options for multiple value fields.
*/
function multiple_options_form(&$form, &$form_state) {
$field = $this->field_info;
$field = $this->getFieldDefinition();
$form['multiple_field_settings'] = array(
'#type' => 'details',
......@@ -607,7 +638,7 @@ public function buildGroupByForm(&$form, &$form_state) {
// With "field API" fields, the column target of the grouping function
// and any additional grouping columns must be specified.
$field_columns = array_keys($this->field_info->getColumns());
$field_columns = array_keys($this->getFieldDefinition()->getColumns());
$group_columns = array(
'entity_id' => t('Entity ID'),
) + array_map('ucfirst', array_combine($field_columns, $field_columns));
......@@ -832,14 +863,14 @@ function render_item($count, $item) {
}
protected function documentSelfTokens(&$tokens) {
$field = $this->field_info;
$field = $this->getFieldDefinition();
foreach ($field->getColumns() as $id => $column) {
$tokens['[' . $this->options['id'] . '-' . $id . ']'] = t('Raw @column', array('@column' => $id));
}
}
protected function addSelfTokens(&$tokens, $item) {
$field = $this->field_info;
$field = $this->getFieldDefinition();
foreach ($field->getColumns() as $id => $column) {
// Use \Drupal\Component\Utility\Xss::filterAdmin() because it's user data
// and we can't be sure it is safe. We know nothing about the data,
......@@ -866,7 +897,7 @@ protected function addSelfTokens(&$tokens, $item) {
* according to the settings.
*/
function field_langcode(EntityInterface $entity) {
if ($this->field_info->isTranslatable()) {
if ($this->getFieldDefinition()->isTranslatable()) {
$default_langcode = language_default()->id;
$langcode = str_replace(
array('***CURRENT_LANGUAGE***', '***DEFAULT_LANGUAGE***'),
......@@ -888,4 +919,13 @@ function field_langcode(EntityInterface $entity) {
}
}
/**
* {@inheritdoc}
*/
public function getDependencies() {
// Add the module providing the configured field as a dependency.
return array('entity' => array($this->getFieldConfig()->getConfigDependencyName()));
}
}
......@@ -12,7 +12,6 @@
use Drupal\views\Views;
use Drupal\views_ui\ViewUI;
use Drupal\views\ViewStorageInterface;
use Drupal\views\ViewExecutable;
/**
* Defines a View configuration entity class.
......@@ -273,28 +272,43 @@ public function calculateDependencies() {
// Ensure that the view is dependant on the module that implements the view.
$this->addDependency('module', $this->module);
// Ensure that the view is dependant on the module that provides the schema
// Ensure that the view is dependent on the module that provides the schema
// for the base table.
$schema = drupal_get_schema($this->base_table);
$schema = $this->drupalGetSchema($this->base_table);
if ($this->module != $schema['module']) {
$this->addDependency('module', $schema['module']);
}
$handler_types = array();
foreach (ViewExecutable::getHandlerTypes() as $type) {
foreach (Views::getHandlerTypes() as $type) {
$handler_types[] = $type['plural'];
}
foreach ($this->get('display') as $display) {
// Collect all dependencies of all handlers.
foreach ($handler_types as $handler_type) {
if (!empty($display['display_options'][$handler_type])) {
foreach ($display['display_options'][$handler_type] as $handler) {
// Add the provider as dependency.
if (isset($handler['provider']) && empty($handler['optional'])) {
$this->addDependency('module', $handler['provider']);
}
// Add the additional dependencies from the handler configuration.
if (!empty($handler['dependencies'])) {
$this->addDependencies($handler['dependencies']);
}
}
}
}
// Collect all dependencies of plugins.
foreach (Views::getPluginTypes('plugin') as $plugin_type) {
if (!empty($display['display_options'][$plugin_type]['options']['dependencies'])) {
$this->addDependencies($display['display_options'][$plugin_type]['options']['dependencies']);
}
}
}
return $this->dependencies;
}
......@@ -386,4 +400,11 @@ public function mergeDefaultDisplaysOptions() {
$this->set('display', $displays);
}
/**
* Wraps drupal_get_schema().
*/
protected function drupalGetSchema($table = NULL, $rebuild = FALSE) {
return drupal_get_schema($table, $rebuild);
}
}
......@@ -168,6 +168,7 @@ protected function defineOptions() {
$options['relationship'] = array('default' => 'none');
$options['group_type'] = array('default' => 'group');
$options['admin_label'] = array('default' => '', 'translatable' => TRUE);
$options['dependencies'] = array('default' => array());
return $options;
}
......
......@@ -424,4 +424,16 @@ public static function preRenderFlattenData($form) {
return $form;
}
/**
* Returns an array of module dependencies for this plugin.
*
* Dependencies are a list of module names, which might depend on the
* configuration.
*
* @return array
*/
public function getDependencies() {
return array();
}
}
......@@ -767,6 +767,7 @@ protected function defaultDisplayOptions() {
foreach ($display_options as &$options) {
$options['options'] = array();
$options['provider'] = 'views';
$options['dependencies'] = array();
}
// Add a least one field so the view validates and the user has a preview.
......
......@@ -29,4 +29,5 @@ public function &getDisplay($display_id);
* Add defaults to the display options.
*/
public function mergeDefaultDisplaysOptions();
}
<?php
/**
* @file
* Contains \Drupal\views\Tests\Entity\ViewTest.
*/
namespace Drupal\views\Tests\Entity {
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityType;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Entity\View;
/**
* Tests the view entity.
*
* @coversDefaultClass \Drupal\views\Entity\View
*/
class ViewTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'View entity test',
'description' => 'Tests the \Drupal\views\Entity\View class.',
'group' => 'Views',
);
}
/**
* {@inheritdoc}
*/
protected function setUp() {
// Setup the entity manager.
$entity_definition = new EntityType(array('id' => 'view'));
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$entity_manager->expects($this->any())
->method('getDefinition')
->will($this->returnValue($entity_definition));
$container_builder = new ContainerBuilder();
$container_builder->set('entity.manager', $entity_manager);
// Setup the string translation.
$string_translation = $this->getStringTranslationStub();
$container_builder->set('string_translation', $string_translation);
\Drupal::setContainer($container_builder);
}
/**
* Tests calculating dependencies.
*
* @covers ::calculateDependencies
* @dataProvider calculateDependenciesProvider
*/
public function testCalculateDependencies($values, $deps) {
$view = new TestView($values, 'view');
$this->assertEquals(array('module' => $deps), $view->calculateDependencies());
}
public function calculateDependenciesProvider(){
$handler['display']['default']['display_options']['fields']['example']['dependencies'] = array();
$handler['display']['default']['display_options']['fields']['example2']['dependencies']['module'] = array('views', 'field');
$handler['display']['default']['display_options']['fields']['example3']['dependencies']['module'] = array('views', 'image');
$plugin['display']['default']['display_options']['access']['options']['dependencies'] = array();
$plugin['display']['default']['display_options']['row']['options']['dependencies']['module'] = array('views', 'field');
$plugin['display']['default']['display_options']['style']['options']['dependencies']['module'] = array('views', 'image');
return array(
array(array(), array('node', 'views')),
array($handler, array('field', 'image', 'node', 'views')),
array($plugin, array('field', 'image', 'node', 'views')),
);
}
}
class TestView extends View {
/**
* {@inheritdoc}
*/
protected function drupalGetSchema($table = NULL, $rebuild = FALSE) {
$result = array();
if ($table == 'node') {
$result['module'] = 'node';
}
return $result;
}
}
}
......@@ -238,6 +238,14 @@ public function submitForm(array &$form, array &$form_state) {
// extra stuff on the form is not sent through.
$handler->unpackOptions($handler->options, $options, NULL, FALSE);
// Add any dependencies as the handler is saved. Put it here so
// it does not need to be declared in defineOptions().
if ($dependencies = $handler->getDependencies()) {
$handler->options['dependencies'] = $dependencies;
}
// Add the module providing the handler as a dependency as well.
$handler->options['dependencies']['module'][] = $handler->definition['provider'];
// Store the item back on the view
$executable->setHandler($form_state['display_id'], $form_state['type'], $form_state['id'], $handler->options);
......
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