896d24bf64c994941ae30bad661e12992f53d981
[yaffs-website] / web / core / modules / views / src / Plugin / views / argument_validator / Entity.php
1 <?php
2
3 namespace Drupal\views\Plugin\views\argument_validator;
4
5 use Drupal\Core\Entity\EntityInterface;
6 use Drupal\Core\Entity\EntityManagerInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\Plugin\Context\ContextDefinition;
9 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
11
12 /**
13  * Defines a argument validator plugin for each entity type.
14  *
15  * @ViewsArgumentValidator(
16  *   id = "entity",
17  *   deriver = "Drupal\views\Plugin\Derivative\ViewsEntityArgumentValidator"
18  * )
19  *
20  * @see \Drupal\views\Plugin\Derivative\ViewsEntityArgumentValidator
21  */
22 class Entity extends ArgumentValidatorPluginBase {
23
24   /**
25    * The entity manager.
26    *
27    * @var \Drupal\Core\Entity\EntityManagerInterface
28    */
29   protected $entityManager;
30
31   /**
32    * If this validator can handle multiple arguments.
33    *
34    * @var bool
35    */
36   protected $multipleCapable = TRUE;
37
38   /**
39    * Constructs an \Drupal\views\Plugin\views\argument_validator\Entity object.
40    *
41    * @param array $configuration
42    *   A configuration array containing information about the plugin instance.
43    * @param string $plugin_id
44    *   The plugin_id for the plugin instance.
45    * @param mixed $plugin_definition
46    *   The plugin implementation definition.
47    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
48    *   The entity manager.
49    */
50   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
51     parent::__construct($configuration, $plugin_id, $plugin_definition);
52
53     $this->entityManager = $entity_manager;
54   }
55
56   /**
57    * {@inheritdoc}
58    */
59   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
60     return new static(
61       $configuration,
62       $plugin_id,
63       $plugin_definition,
64       $container->get('entity.manager')
65     );
66   }
67
68   /**
69    * {@inheritdoc}
70    */
71   protected function defineOptions() {
72     $options = parent::defineOptions();
73
74     $options['bundles'] = ['default' => []];
75     $options['access'] = ['default' => FALSE];
76     $options['operation'] = ['default' => 'view'];
77     $options['multiple'] = ['default' => FALSE];
78
79     return $options;
80   }
81
82   /**
83    * {@inheritdoc}
84    */
85   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
86     parent::buildOptionsForm($form, $form_state);
87
88     $entity_type_id = $this->definition['entity_type'];
89     // Derivative IDs are all entity:entity_type. Sanitized for js.
90     // The ID is converted back on submission.
91     $sanitized_id = ArgumentPluginBase::encodeValidatorId($this->definition['id']);
92     $entity_type = $this->entityManager->getDefinition($entity_type_id);
93
94     // If the entity has bundles, allow option to restrict to bundle(s).
95     if ($entity_type->hasKey('bundle')) {
96       $bundle_options = [];
97       foreach ($this->entityManager->getBundleInfo($entity_type_id) as $bundle_id => $bundle_info) {
98         $bundle_options[$bundle_id] = $bundle_info['label'];
99       }
100
101       $form['bundles'] = [
102         '#title' => $entity_type->getBundleLabel() ?: $this->t('Bundles'),
103         '#default_value' => $this->options['bundles'],
104         '#type' => 'checkboxes',
105         '#options' => $bundle_options,
106         '#description' => $this->t('If none are selected, all are allowed.'),
107       ];
108     }
109
110     // Offer the option to filter by access to the entity in the argument.
111     $form['access'] = [
112       '#type' => 'checkbox',
113       '#title' => $this->t('Validate user has access to the %name', ['%name' => $entity_type->getLabel()]),
114       '#default_value' => $this->options['access'],
115     ];
116     $form['operation'] = [
117       '#type' => 'radios',
118       '#title' => $this->t('Access operation to check'),
119       '#options' => [
120         'view' => $this->t('View'),
121         'update' => $this->t('Edit'),
122         'delete' => $this->t('Delete'),
123       ],
124       '#default_value' => $this->options['operation'],
125       '#states' => [
126         'visible' => [
127           ':input[name="options[validate][options][' . $sanitized_id . '][access]"]' => ['checked' => TRUE],
128         ],
129       ],
130     ];
131
132     // If class is multiple capable give the option to validate single/multiple.
133     if ($this->multipleCapable) {
134       $form['multiple'] = [
135         '#type' => 'radios',
136         '#title' => $this->t('Multiple arguments'),
137         '#options' => [
138           0 => $this->t('Single ID', ['%type' => $entity_type->getLabel()]),
139           1 => $this->t('One or more IDs separated by , or +', ['%type' => $entity_type->getLabel()]),
140         ],
141         '#default_value' => (string) $this->options['multiple'],
142       ];
143     }
144   }
145
146   /**
147    * {@inheritdoc}
148    */
149   public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = []) {
150     // Filter out unused options so we don't store giant unnecessary arrays.
151     $options['bundles'] = array_filter($options['bundles']);
152   }
153
154   /**
155    * {@inheritdoc}
156    */
157   public function validateArgument($argument) {
158     $entity_type = $this->definition['entity_type'];
159
160     if ($this->multipleCapable && $this->options['multiple']) {
161       // At this point only interested in individual IDs no matter what type,
162       // just splitting by the allowed delimiters.
163       $ids = array_filter(preg_split('/[,+ ]/', $argument));
164     }
165     elseif ($argument) {
166       $ids = [$argument];
167     }
168     // No specified argument should be invalid.
169     else {
170       return FALSE;
171     }
172
173     $entities = $this->entityManager->getStorage($entity_type)->loadMultiple($ids);
174     // Validate each id => entity. If any fails break out and return false.
175     foreach ($ids as $id) {
176       // There is no entity for this ID.
177       if (!isset($entities[$id])) {
178         return FALSE;
179       }
180       if (!$this->validateEntity($entities[$id])) {
181         return FALSE;
182       }
183     }
184
185     return TRUE;
186   }
187
188   /**
189    * Validates an individual entity against class access settings.
190    *
191    * @param \Drupal\Core\Entity\EntityInterface $entity
192    *
193    * @return bool
194    *   True if validated.
195    */
196   protected function validateEntity(EntityInterface $entity) {
197     // If access restricted by entity operation.
198     if ($this->options['access'] && !$entity->access($this->options['operation'])) {
199       return FALSE;
200     }
201     // If restricted by bundle.
202     $bundles = $this->options['bundles'];
203     if (count($bundles) && empty($bundles[$entity->bundle()])) {
204       return FALSE;
205     }
206
207     return TRUE;
208   }
209
210   /**
211    * {@inheritdoc}
212    */
213   public function calculateDependencies() {
214     $dependencies = parent::calculateDependencies();
215
216     $entity_type_id = $this->definition['entity_type'];
217     $bundle_entity_type = $this->entityManager->getDefinition($entity_type_id)->getBundleEntityType();
218
219     // The bundle entity type might not exist. For example, users do not have
220     // bundles.
221     if ($this->entityManager->hasHandler($bundle_entity_type, 'storage')) {
222       $bundle_entity_storage = $this->entityManager->getStorage($bundle_entity_type);
223
224       foreach ($bundle_entity_storage->loadMultiple(array_keys($this->options['bundles'])) as $bundle_entity) {
225         $dependencies[$bundle_entity->getConfigDependencyKey()][] = $bundle_entity->getConfigDependencyName();
226       }
227     }
228
229     return $dependencies;
230   }
231
232   /**
233    * {@inheritdoc}
234    */
235   public function getContextDefinition() {
236     return new ContextDefinition('entity:' . $this->definition['entity_type'], $this->argument->adminLabel(), FALSE);
237   }
238
239 }