Yaffs site version 1.1
[yaffs-website] / vendor / doctrine / collections / lib / Doctrine / Common / Collections / Expr / ClosureExpressionVisitor.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\Common\Collections\Expr;
21
22 /**
23  * Walks an expression graph and turns it into a PHP closure.
24  *
25  * This closure can be used with {@Collection#filter()} and is used internally
26  * by {@ArrayCollection#select()}.
27  *
28  * @author Benjamin Eberlei <kontakt@beberlei.de>
29  * @since  2.3
30  */
31 class ClosureExpressionVisitor extends ExpressionVisitor
32 {
33     /**
34      * Accesses the field of a given object. This field has to be public
35      * directly or indirectly (through an accessor get*, is*, or a magic
36      * method, __get, __call).
37      *
38      * @param object $object
39      * @param string $field
40      *
41      * @return mixed
42      */
43     public static function getObjectFieldValue($object, $field)
44     {
45         if (is_array($object)) {
46             return $object[$field];
47         }
48
49         $accessors = array('get', 'is');
50
51         foreach ($accessors as $accessor) {
52             $accessor .= $field;
53
54             if ( ! method_exists($object, $accessor)) {
55                 continue;
56             }
57
58             return $object->$accessor();
59         }
60
61         // __call should be triggered for get.
62         $accessor = $accessors[0] . $field;
63
64         if (method_exists($object, '__call')) {
65             return $object->$accessor();
66         }
67
68         if ($object instanceof \ArrayAccess) {
69             return $object[$field];
70         }
71
72         if (isset($object->$field)) {
73             return $object->$field;
74         }
75
76         // camelcase field name to support different variable naming conventions
77         $ccField   = preg_replace_callback('/_(.?)/', function($matches) { return strtoupper($matches[1]); }, $field);
78
79         foreach ($accessors as $accessor) {
80             $accessor .= $ccField;
81
82
83             if ( ! method_exists($object, $accessor)) {
84                 continue;
85             }
86
87             return $object->$accessor();
88         }
89
90         return $object->$field;
91     }
92
93     /**
94      * Helper for sorting arrays of objects based on multiple fields + orientations.
95      *
96      * @param string   $name
97      * @param int      $orientation
98      * @param \Closure $next
99      *
100      * @return \Closure
101      */
102     public static function sortByField($name, $orientation = 1, \Closure $next = null)
103     {
104         if ( ! $next) {
105             $next = function() {
106                 return 0;
107             };
108         }
109
110         return function ($a, $b) use ($name, $next, $orientation) {
111             $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name);
112             $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name);
113
114             if ($aValue === $bValue) {
115                 return $next($a, $b);
116             }
117
118             return (($aValue > $bValue) ? 1 : -1) * $orientation;
119         };
120     }
121
122     /**
123      * {@inheritDoc}
124      */
125     public function walkComparison(Comparison $comparison)
126     {
127         $field = $comparison->getField();
128         $value = $comparison->getValue()->getValue(); // shortcut for walkValue()
129
130         switch ($comparison->getOperator()) {
131             case Comparison::EQ:
132                 return function ($object) use ($field, $value) {
133                     return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
134                 };
135
136             case Comparison::NEQ:
137                 return function ($object) use ($field, $value) {
138                     return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
139                 };
140
141             case Comparison::LT:
142                 return function ($object) use ($field, $value) {
143                     return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
144                 };
145
146             case Comparison::LTE:
147                 return function ($object) use ($field, $value) {
148                     return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
149                 };
150
151             case Comparison::GT:
152                 return function ($object) use ($field, $value) {
153                     return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
154                 };
155
156             case Comparison::GTE:
157                 return function ($object) use ($field, $value) {
158                     return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
159                 };
160
161             case Comparison::IN:
162                 return function ($object) use ($field, $value) {
163                     return in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
164                 };
165
166             case Comparison::NIN:
167                 return function ($object) use ($field, $value) {
168                     return ! in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
169                 };
170
171             case Comparison::CONTAINS:
172                 return function ($object) use ($field, $value) {
173                     return false !== strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
174                 };
175
176             case Comparison::MEMBER_OF:
177                 return function ($object) use ($field, $value) {
178                     $fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
179                     if (!is_array($fieldValues)) {
180                         $fieldValues = iterator_to_array($fieldValues);
181                     }
182                     return in_array($value, $fieldValues);
183                 };
184
185             case Comparison::STARTS_WITH:
186                 return function ($object) use ($field, $value) {
187                     return 0 === strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
188                 };
189
190             case Comparison::ENDS_WITH:
191                 return function ($object) use ($field, $value) {
192                     return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value));
193                 };
194
195
196             default:
197                 throw new \RuntimeException("Unknown comparison operator: " . $comparison->getOperator());
198         }
199     }
200
201     /**
202      * {@inheritDoc}
203      */
204     public function walkValue(Value $value)
205     {
206         return $value->getValue();
207     }
208
209     /**
210      * {@inheritDoc}
211      */
212     public function walkCompositeExpression(CompositeExpression $expr)
213     {
214         $expressionList = array();
215
216         foreach ($expr->getExpressionList() as $child) {
217             $expressionList[] = $this->dispatch($child);
218         }
219
220         switch($expr->getType()) {
221             case CompositeExpression::TYPE_AND:
222                 return $this->andExpressions($expressionList);
223
224             case CompositeExpression::TYPE_OR:
225                 return $this->orExpressions($expressionList);
226
227             default:
228                 throw new \RuntimeException("Unknown composite " . $expr->getType());
229         }
230     }
231
232     /**
233      * @param array $expressions
234      *
235      * @return callable
236      */
237     private function andExpressions($expressions)
238     {
239         return function ($object) use ($expressions) {
240             foreach ($expressions as $expression) {
241                 if ( ! $expression($object)) {
242                     return false;
243                 }
244             }
245             return true;
246         };
247     }
248
249     /**
250      * @param array $expressions
251      *
252      * @return callable
253      */
254     private function orExpressions($expressions)
255     {
256         return function ($object) use ($expressions) {
257             foreach ($expressions as $expression) {
258                 if ($expression($object)) {
259                     return true;
260                 }
261             }
262             return false;
263         };
264     }
265 }