diff --git a/src/Plugin/views/join/CastedFieldJoin.php b/src/Plugin/views/join/CastedFieldJoin.php new file mode 100644 index 0000000..2549894 --- /dev/null +++ b/src/Plugin/views/join/CastedFieldJoin.php @@ -0,0 +1,76 @@ +configuration['table formula'])) { + $right_table = $this->table; + } + else { + $right_table = $this->configuration['table formula']; + } + + if ($this->leftTable) { + $left_table = $view_query->getTableInfo($this->leftTable); + $left_field = "$left_table[alias].$this->leftField"; + } + else { + // This can be used if left_field is a formula or something. It should be + // used only *very* rarely. + $left_field = $this->leftField; + $left_table = NULL; + } + + $right_field = "{$table['alias']}.$this->field"; + + // Determine whether the left field of the relationship is an integer so we + // know whether a CAST() is needed for the right field. + if (isset($this->configuration['entity_type'])) { + $field_storage_definition = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($this->configuration['entity_type'])[$this->leftField]; + if (is_a($field_storage_definition->getItemDefinition()->getClass(), IntegerItem::class, TRUE)) { + switch (\Drupal::database()->databaseType()) { + case 'mysql': + $cast_data_type = 'UNSIGNED'; + break; + + default: + $cast_data_type = 'INTEGER'; + break; + } + + $right_field = "CAST($right_field AS $cast_data_type)"; + } + } + + $condition = "$left_field = $right_field"; + $arguments = []; + + // Tack on the extra. + if (isset($this->extra)) { + $this->joinAddExtra($arguments, $condition, $table, $select_query, $left_table); + } + + $select_query->addJoin($this->type, $right_table, $table['alias'], $condition, $arguments); + } + +} diff --git a/src/Plugin/views/relationship/EntityQueueRelationship.php b/src/Plugin/views/relationship/EntityQueueRelationship.php index 691a766..d0e7995 100644 --- a/src/Plugin/views/relationship/EntityQueueRelationship.php +++ b/src/Plugin/views/relationship/EntityQueueRelationship.php @@ -7,8 +7,11 @@ use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\entityqueue\Entity\EntityQueue; use Drupal\views\Plugin\views\display\DisplayPluginBase; -use Drupal\views\Plugin\views\relationship\EntityReverse; +use Drupal\views\Plugin\views\relationship\RelationshipPluginBase; +use Drupal\views\Plugin\ViewsHandlerManager; use Drupal\views\ViewExecutable; +use Drupal\views\Views; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * A relationship handler for entity queues. @@ -17,7 +20,43 @@ use Drupal\views\ViewExecutable; * * @ViewsRelationship("entity_queue") */ -class EntityQueueRelationship extends EntityReverse implements CacheableDependencyInterface { +class EntityQueueRelationship extends RelationshipPluginBase implements CacheableDependencyInterface { + + /** + * The Views join manager. + * + * @var \Drupal\views\Plugin\ViewsHandlerManager + */ + protected $joinManager; + + /** + * Constructs an EntityQueueRelationship object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\views\Plugin\ViewsHandlerManager $join_manager + * The views plugin join manager. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, ViewsHandlerManager $join_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->joinManager = $join_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.views.join') + ); + } /** * {@inheritdoc} @@ -128,7 +167,65 @@ class EntityQueueRelationship extends EntityReverse implements CacheableDependen } // Now - let's build the query. - parent::query(); + // @todo We can't simply call parent::query() because the parent class does + // not handle the 'join_id' configuration correctly, so we can't use our + // custom 'casted_field_join' plugin. + $this->ensureMyTable(); + + // First, relate our base table to the current base table to the + // field, using the base table's id field to the field's column. + $views_data = Views::viewsData()->get($this->table); + $left_field = $views_data['table']['base']['field']; + + $first = [ + 'left_table' => $this->tableAlias, + 'left_field' => $left_field, + 'table' => $this->definition['field table'], + 'field' => $this->definition['field field'], + 'adjusted' => TRUE, + 'entity_type' => isset($views_data['table']['entity type']) ? $views_data['table']['entity type'] : NULL, + ]; + if (!empty($this->options['required'])) { + $first['type'] = 'INNER'; + } + + if (!empty($this->definition['join_extra'])) { + $first['extra'] = $this->definition['join_extra']; + } + + // Use our custom 'casted_field_join' handler in order to handle + // relationships to integers and strings IDs from the same table properly. + $first_join = $this->joinManager->createInstance('casted_field_join', $first); + + $this->first_alias = $this->query->addTable($this->definition['field table'], $this->relationship, $first_join); + + // Second, relate the field table to the entity specified using + // the entity id on the field table and the entity's id field. + $second = [ + 'left_table' => $this->first_alias, + 'left_field' => 'entity_id', + 'table' => $this->definition['base'], + 'field' => $this->definition['base field'], + 'adjusted' => TRUE, + ]; + + if (!empty($this->options['required'])) { + $second['type'] = 'INNER'; + } + + if (!empty($this->definition['join_id'])) { + $id = $this->definition['join_id']; + } + else { + $id = 'standard'; + } + $second_join = $this->joinManager->createInstance($id, $second); + $second_join->adjusted = TRUE; + + // use a short alias for this: + $alias = $this->definition['field_name'] . '_' . $this->table; + + $this->alias = $this->query->addRelationship($alias, $second_join, $this->definition['base'], $this->relationship); } }