3 namespace Drupal\taxonomy\Plugin\views\relationship;
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\taxonomy\VocabularyStorageInterface;
7 use Drupal\views\ViewExecutable;
8 use Drupal\views\Plugin\views\display\DisplayPluginBase;
9 use Drupal\views\Plugin\views\relationship\RelationshipPluginBase;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
13 * Relationship handler to return the taxonomy terms of nodes.
15 * @ingroup views_relationship_handlers
17 * @ViewsRelationship("node_term_data")
19 class NodeTermData extends RelationshipPluginBase {
22 * The vocabulary storage.
24 * @var \Drupal\taxonomy\VocabularyStorageInterface
26 protected $vocabularyStorage;
29 * Constructs a NodeTermData object.
31 * @param array $configuration
32 * A configuration array containing information about the plugin instance.
33 * @param string $plugin_id
34 * The plugin_id for the plugin instance.
35 * @param mixed $plugin_definition
36 * The plugin implementation definition.
37 * @param \Drupal\taxonomy\VocabularyStorageInterface $vocabulary_storage
38 * The vocabulary storage.
40 public function __construct(array $configuration, $plugin_id, $plugin_definition, VocabularyStorageInterface $vocabulary_storage) {
41 parent::__construct($configuration, $plugin_id, $plugin_definition);
42 $this->vocabularyStorage = $vocabulary_storage;
48 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
53 $container->get('entity.manager')->getStorage('taxonomy_vocabulary')
60 public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
61 parent::init($view, $display, $options);
63 // @todo Remove the legacy code.
64 // Convert legacy vids option to machine name vocabularies.
65 if (!empty($this->options['vids'])) {
66 $vocabularies = taxonomy_vocabulary_get_names();
67 foreach ($this->options['vids'] as $vid) {
68 if (isset($vocabularies[$vid], $vocabularies[$vid]->machine_name)) {
69 $this->options['vocabularies'][$vocabularies[$vid]->machine_name] = $vocabularies[$vid]->machine_name;
75 protected function defineOptions() {
76 $options = parent::defineOptions();
77 $options['vids'] = ['default' => []];
81 public function buildOptionsForm(&$form, FormStateInterface $form_state) {
82 $vocabularies = $this->vocabularyStorage->loadMultiple();
84 foreach ($vocabularies as $voc) {
85 $options[$voc->id()] = $voc->label();
89 '#type' => 'checkboxes',
90 '#title' => $this->t('Vocabularies'),
91 '#options' => $options,
92 '#default_value' => $this->options['vids'],
93 '#description' => $this->t('Choose which vocabularies you wish to relate. Remember that every term found will create a new record, so this relationship is best used on just one vocabulary that has only one term per node.'),
95 parent::buildOptionsForm($form, $form_state);
101 public function submitOptionsForm(&$form, FormStateInterface $form_state) {
102 // Transform the #type = checkboxes value to a numerically indexed array,
103 // because the config schema expects a sequence, not a mapping.
104 $vids = $form_state->getValue(['options', 'vids']);
105 $form_state->setValue(['options', 'vids'], array_values(array_filter($vids)));
109 * Called to implement a relationship in a query.
111 public function query() {
112 $this->ensureMyTable();
114 $def = $this->definition;
115 $def['table'] = 'taxonomy_term_field_data';
117 if (!array_filter($this->options['vids'])) {
118 $taxonomy_index = $this->query->addTable('taxonomy_index', $this->relationship);
119 $def['left_table'] = $taxonomy_index;
120 $def['left_field'] = 'tid';
121 $def['field'] = 'tid';
122 $def['type'] = empty($this->options['required']) ? 'LEFT' : 'INNER';
125 // If vocabularies are supplied join a subselect instead
126 $def['left_table'] = $this->tableAlias;
127 $def['left_field'] = 'nid';
128 $def['field'] = 'nid';
129 $def['type'] = empty($this->options['required']) ? 'LEFT' : 'INNER';
130 $def['adjusted'] = TRUE;
132 $query = db_select('taxonomy_term_field_data', 'td');
133 $query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid');
134 $query->condition('td.vid', array_filter($this->options['vids']), 'IN');
135 $query->addTag('taxonomy_term_access');
136 $query->fields('td');
137 $query->fields('tn', ['nid']);
138 $def['table formula'] = $query;
141 $join = \Drupal::service('plugin.manager.views.join')->createInstance('standard', $def);
143 // use a short alias for this:
144 $alias = $def['table'] . '_' . $this->table;
146 $this->alias = $this->query->addRelationship($alias, $join, 'taxonomy_term_field_data', $this->relationship);
152 public function calculateDependencies() {
153 $dependencies = parent::calculateDependencies();
155 foreach ($this->options['vids'] as $vocabulary_id) {
156 if ($vocabulary = $this->vocabularyStorage->load($vocabulary_id)) {
157 $dependencies[$vocabulary->getConfigDependencyKey()][] = $vocabulary->getConfigDependencyName();
161 return $dependencies;