33838206a4971eecdea6dd015d0f9d105b2782f7
[yaffs-website] / web / modules / contrib / linkit / src / Plugin / Linkit / Matcher / EntityMatcher.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\linkit\Plugin\Linkit\Matcher\EntityMatcher.
6  */
7
8 namespace Drupal\linkit\Plugin\Linkit\Matcher;
9
10 use Drupal\Component\Utility\Html;
11 use Drupal\Core\Database\Connection;
12 use Drupal\Core\Entity\EntityManagerInterface;
13 use Drupal\Core\Extension\ModuleHandlerInterface;
14 use Drupal\Core\Form\FormStateInterface;
15 use Drupal\Core\Session\AccountInterface;
16 use Drupal\linkit\ConfigurableMatcherBase;
17 use Drupal\linkit\MatcherTokensTrait;
18 use Drupal\linkit\Utility\LinkitXss;
19 use Symfony\Component\DependencyInjection\ContainerInterface;
20
21 /**
22  * @Matcher(
23  *   id = "entity",
24  *   label = @Translation("Entity"),
25  *   deriver = "\Drupal\linkit\Plugin\Derivative\EntityMatcherDeriver"
26  * )
27  */
28 class EntityMatcher extends ConfigurableMatcherBase {
29
30   use MatcherTokensTrait;
31
32   /**
33    * The database connection.
34    *
35    * @var \Drupal\Core\Database\Connection
36    */
37   protected $database;
38
39   /**
40    * The entity manager.
41    *
42    * @var \Drupal\Core\Entity\EntityManagerInterface
43    */
44   protected $entityManager;
45
46   /**
47    * The module handler service.
48    *
49    * @var \Drupal\Core\Extension\ModuleHandlerInterface
50    */
51   protected $moduleHandler;
52
53   /**
54    * The current user.
55    *
56    * @var \Drupal\Core\Session\AccountInterface
57    */
58   protected $currentUser;
59
60   /**
61    * The target entity type id
62    *
63    * @var string
64    */
65   protected $target_type;
66
67   /**
68    * {@inheritdoc}
69    */
70   public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler,   AccountInterface $current_user) {
71     parent::__construct($configuration, $plugin_id, $plugin_definition);
72
73     if (empty($plugin_definition['target_entity'])) {
74       throw new \InvalidArgumentException("Missing required 'target_entity' property for a matcher.");
75     }
76     $this->database = $database;
77     $this->entityManager = $entity_manager;
78     $this->moduleHandler = $module_handler;
79     $this->currentUser = $current_user;
80     $this->target_type = $plugin_definition['target_entity'];
81   }
82
83   /**
84    * {@inheritdoc}
85    */
86   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
87     return new static(
88       $configuration,
89       $plugin_id,
90       $plugin_definition,
91       $container->get('database'),
92       $container->get('entity.manager'),
93       $container->get('module_handler'),
94       $container->get('current_user')
95     );
96   }
97
98   /**
99    * {@inheritdoc}
100    */
101   public function getSummary() {
102     $summery = parent::getSummary();
103     $entity_type = $this->entityManager->getDefinition($this->target_type);
104
105     $result_description = $this->configuration['result_description'];
106     if (!empty($result_description)) {
107       $summery[] = $this->t('Result description: @result_description', [
108         '@result_description' => $result_description
109       ]);
110     }
111
112     if ($entity_type->hasKey('bundle')) {
113       $has_bundle_filter = !empty($this->configuration['bundles']);
114       $bundles = [];
115
116       if ($has_bundle_filter) {
117         $bundles_info = $this->entityManager->getBundleInfo($this->target_type);
118         foreach ($this->configuration['bundles'] as $bundle) {
119           $bundles[] = $bundles_info[$bundle]['label'];
120         }
121       }
122
123       $summery[] = $this->t('Bundle filter: @bundle_filter', [
124         '@bundle_filter' => $has_bundle_filter ? implode(', ', $bundles) : t('None'),
125       ]);
126
127       $summery[] = $this->t('Group by bundle: @bundle_grouping', [
128         '@bundle_grouping' => $this->configuration['group_by_bundle'] ? $this->t('Yes') : $this->t('No'),
129       ]);
130     }
131
132     return $summery;
133   }
134
135   /**
136    * {@inheritdoc}
137    */
138   public function defaultConfiguration() {
139     return parent::defaultConfiguration() + [
140       'result_description' => '',
141       'bundles' => [],
142       'group_by_bundle' => FALSE,
143     ];
144   }
145
146   /**
147    * {@inheritdoc}
148    */
149   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
150     $entity_type = $this->entityManager->getDefinition($this->target_type);
151     $form['result_description'] = [
152       '#title' => $this->t('Result description'),
153       '#type' => 'textfield',
154       '#default_value' => $this->configuration['result_description'],
155       '#size' => 120,
156       '#maxlength' => 255,
157       '#weight' => -100,
158     ];
159
160     $this->insertTokenList($form, [$this->target_type]);
161
162     // Filter the possible bundles to use if the entity has bundles.
163     if ($entity_type->hasKey('bundle')) {
164       $bundle_options = [];
165       foreach ($this->entityManager->getBundleInfo($this->target_type) as $bundle_name => $bundle_info) {
166         $bundle_options[$bundle_name] = $bundle_info['label'];
167       }
168
169       $form['bundles'] = [
170         '#type' => 'checkboxes',
171         '#title' => $this->t('Restrict to the selected bundles'),
172         '#options' => $bundle_options,
173         '#default_value' => $this->configuration['bundles'],
174         '#description' => $this->t('If none of the checkboxes is checked, allow all bundles.'),
175         '#element_validate' => [[get_class($this), 'elementValidateFilter']],
176         '#weight' => -50,
177       ];
178
179       // Group the results by bundle.
180       $form['group_by_bundle'] = [
181         '#type' => 'checkbox',
182         '#title' => $this->t('Group by bundle'),
183         '#default_value' => $this->configuration['group_by_bundle'],
184         '#weight' => -50,
185       ];
186     }
187
188     return $form;
189   }
190
191   /**
192    * {@inheritdoc}
193    */
194   public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
195   }
196
197   /**
198    * {@inheritdoc}
199    */
200   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
201     $this->configuration['result_description'] = $form_state->getValue('result_description');
202     $this->configuration['bundles'] = $form_state->getValue('bundles');
203     $this->configuration['group_by_bundle'] = $form_state->getValue('group_by_bundle');
204   }
205
206   /**
207    * Form element validation handler; Filters the #value property of an element.
208    */
209   public static function elementValidateFilter(&$element, FormStateInterface $form_state) {
210     $element['#value'] = array_filter($element['#value']);
211     $form_state->setValueForElement($element, $element['#value']);
212   }
213
214   /**
215    * {@inheritdoc}
216    */
217   public function getMatches($string) {
218     $query = $this->buildEntityQuery($string);
219     $result = $query->execute();
220
221     if (empty($result)) {
222       return [];
223     }
224
225     $matches = [];
226     $entities = $this->entityManager->getStorage($this->target_type)->loadMultiple($result);
227
228     foreach ($entities as $entity_id => $entity) {
229       // Check the access against the defined entity access handler.
230       /** @var \Drupal\Core\Access\AccessResultInterface $access */
231       $access = $entity->access('view', $this->currentUser, TRUE);
232       if (!$access->isAllowed()) {
233         continue;
234       }
235
236       $matches[] = [
237         'title' => $this->buildLabel($entity),
238         'description' => $this->buildDescription($entity),
239         'path' => $this->buildPath($entity),
240         'group' => $this->buildGroup($entity),
241       ];
242     }
243
244     return $matches;
245   }
246
247   /**
248    * Builds an EntityQuery to get entities.
249    *
250    * @param $match
251    *   Text to match the label against.
252    *
253    * @return \Drupal\Core\Entity\Query\QueryInterface
254    *   The EntityQuery object with the basic conditions and sorting applied to
255    *   it.
256    */
257   protected function buildEntityQuery($match) {
258     $match = $this->database->escapeLike($match);
259
260     $entity_type = $this->entityManager->getDefinition($this->target_type);
261     $query = $this->entityManager->getStorage($this->target_type)->getQuery();
262     $label_key = $entity_type->getKey('label');
263
264     if ($label_key) {
265       $query->condition($label_key, '%' . $match . '%', 'LIKE');
266       $query->sort($label_key, 'ASC');
267     }
268
269     // Bundle check.
270     if (!empty($this->configuration['bundles']) && $bundle_key = $entity_type->getKey('bundle')) {
271       $query->condition($bundle_key, $this->configuration['bundles'], 'IN');
272     }
273
274     // Add tags to let other modules alter the query.
275     $query->addTag('linkit_entity_autocomplete');
276     $query->addTag('linkit_entity_' . $this->target_type . '_autocomplete');
277
278     // Add access tag for the query.
279     $query->addTag('entity_access');
280     $query->addTag($this->target_type . '_access');
281
282     return $query;
283   }
284
285   /**
286    * Builds the label string used in the match array.
287    *
288    * @param \Drupal\Core\Entity\EntityInterface $entity
289    *   The matched entity.
290    *
291    * @return string
292    *   The label for this entity.
293    */
294   protected function buildLabel($entity) {
295     return Html::escape($entity->label());
296   }
297
298   /**
299    * Builds the description string used in the match array.
300    *
301    * @param \Drupal\Core\Entity\EntityInterface $entity
302    *   The matched entity.
303    *
304    * @return string
305    *    The description for this entity.
306    */
307   protected function buildDescription($entity) {
308     $description = \Drupal::token()->replace($this->configuration['result_description'], [$this->target_type => $entity], []);
309     return LinkitXss::descriptionFilter($description);
310   }
311
312   /**
313    * Builds the path string used in the match array.
314    *
315    * @param \Drupal\Core\Entity\EntityInterface $entity
316    *    The matched entity.
317    *
318    * @return string
319    *   The URL for this entity.
320    */
321   protected function buildPath($entity) {
322     return $entity->toUrl()->toString();
323   }
324
325   /**
326    * Builds the group string used in the match array.
327    *
328    * @param \Drupal\Core\Entity\EntityInterface $entity
329    *   The matched entity.
330    *
331    * @return string
332    *   The match group for this entity.
333    */
334   protected function buildGroup($entity) {
335     $group = $entity->getEntityType()->getLabel();
336
337     // If the entities by this entity should be grouped by bundle, get the
338     // name and append it to the group.
339     if ($this->configuration['group_by_bundle']) {
340       $bundles = $this->entityManager->getBundleInfo($entity->getEntityTypeId());
341       $bundle_label = $bundles[$entity->bundle()]['label'];
342       $group .= ' - ' . $bundle_label;
343     }
344
345     return $group;
346   }
347
348 }