4545ebbe866a2c51d7e2aefcb59dbf38c31edc07
[yaffs-website] / web / core / lib / Drupal / Core / Entity / Plugin / EntityReferenceSelection / PhpSelection.php
1 <?php
2
3 namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection;
4
5 use Drupal\Component\Utility\Html;
6 use Drupal\Component\Utility\Unicode;
7
8 /**
9  * Defines an alternative to the default Entity Reference Selection plugin.
10  *
11  * This selection plugin uses PHP for more advanced cases when the entity query
12  * cannot filter properly, for example when the target entity type has no
13  * 'label' key provided in the entity type plugin definition.
14  *
15  * @see \Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver
16  */
17 class PhpSelection extends DefaultSelection {
18
19   /**
20    * {@inheritdoc}
21    */
22   public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
23     // No input, return everything from the entity query.
24     if ($match === NULL || $match === '') {
25       return parent::getReferenceableEntities($match, $match_operator, $limit);
26     }
27
28     // Start with the selection results returned by the entity query. Don't use
29     // any limit because we have to apply a limit after filtering the items.
30     $options = parent::getReferenceableEntities($match, $match_operator);
31
32     // Always use a case-insensitive, escaped match. Entity labels returned by
33     // SelectionInterface::getReferenceableEntities() are already escaped, so
34     // the incoming $match needs to be escaped as well, making the comparison
35     // possible.
36     // @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface::getReferenceableEntities()
37     if (is_string($match)) {
38       $match = Html::escape(Unicode::strtolower($match));
39     }
40     elseif (is_array($match)) {
41       array_walk($match, function (&$item) {
42         $item = Html::escape(Unicode::strtolower($item));
43       });
44     }
45
46     $filtered = [];
47     $count = 0;
48     // Filter target entities by the output of their label() method.
49     foreach ($options as $bundle => &$items) {
50       foreach ($items as $entity_id => $label) {
51         if ($this->matchLabel($match, $match_operator, $label)) {
52           $filtered[$bundle][$entity_id] = $label;
53           $count++;
54
55           if ($limit && $count >= $limit) {
56             break 2;
57           }
58         }
59       }
60     }
61
62     return $filtered;
63   }
64
65   /**
66    * {@inheritdoc}
67    */
68   public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
69     $count = 0;
70     foreach ($this->getReferenceableEntities($match, $match_operator) as &$items) {
71       $count += count($items);
72     }
73
74     return $count;
75   }
76
77   /**
78    * Matches an entity label to an input string.
79    *
80    * @param mixed $match
81    *   The value to compare. This can be any valid entity query condition value.
82    * @param string $match_operator
83    *   The comparison operator.
84    * @param string $label
85    *   The entity label to match against.
86    *
87    * @return bool
88    *   TRUE when matches, FALSE otherwise.
89    */
90   protected function matchLabel($match, $match_operator, $label) {
91     // Always use a case-insensitive value.
92     $label = Unicode::strtolower($label);
93
94     switch ($match_operator) {
95       case '=':
96         return $label == $match;
97       case '>':
98         return $label > $match;
99       case '<':
100         return $label < $match;
101       case '>=':
102         return $label >= $match;
103       case '<=':
104         return $label <= $match;
105       case '<>':
106         return $label != $match;
107       case 'IN':
108         return array_search($label, $match) !== FALSE;
109       case 'NOT IN':
110         return array_search($label, $match) === FALSE;
111       case 'STARTS_WITH':
112         return strpos($label, $match) === 0;
113       case 'CONTAINS':
114         return strpos($label, $match) !== FALSE;
115       case 'ENDS_WITH':
116         return Unicode::substr($label, -Unicode::strlen($match)) === (string) $match;
117       case 'IS NOT NULL':
118         return TRUE;
119       case 'IS NULL':
120         return FALSE;
121       default:
122         // Invalid match operator.
123         return FALSE;
124     }
125   }
126
127 }