Fixed handling of cache keys as empty results caused cache keys to exist. :(
[core.git] / inc / classes / main / criteria / class_BaseCriteria.php
1 <?php
2 /**
3  * A general crtieria class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Core Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 class BaseCriteria extends BaseFrameworkSystem implements Criteria {
25         /**
26          * Wrapper class name stored in config entry
27          */
28         private $wrapperConfigEntry = '';
29
30         /**
31          * Criteria to handle
32          */
33         private $criteria = array(
34                 // Default
35                 'default' => array(),
36                 // Choice
37                 'choice'  => array(),
38                 // .. and exclude
39                 'exclude' => array(),
40         );
41
42         /**
43          * Protected constructor
44          *
45          * @param       $className      Name of the class
46          * @return      void
47          */
48         protected function __construct ($className) {
49                 // Call parent constructor
50                 parent::__construct($className);
51         }
52
53         /**
54          * Checks whether given key is set
55          *
56          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
57          * @param       $criteriaKey    Criteria key
58          * @return      $isSet                  Whether key is set
59          */
60         public function isKeySet ($criteriaType, $criteriaKey) {
61                 // Make sure no 'my-' or 'my_' passes this point
62                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE));
63
64                 // Determine it
65                 $isSet = isset($this->criteria[$criteriaType][$criteriaKey]);
66
67                 // Return it
68                 return $isSet;
69         }
70
71         /**
72          * Checks whether given key is set for 'choice' type
73          *
74          * @param       $criteriaKey    Criteria key
75          * @return      $isSet                  Whether key is set
76          */
77         public function isChoiceKeySet ($criteriaKey) {
78                 // Call inner method
79                 return $this->isKeySet('choice', $criteriaKey);
80         }
81
82         /**
83          * Checks whether given key is set for 'exclude' type
84          *
85          * @param       $criteriaKey    Criteria key
86          * @return      $isSet                  Whether key is set
87          */
88         public function isExcludeKeySet ($criteriaKey) {
89                 // Call inner method
90                 return $this->isKeySet('exclude', $criteriaKey);
91         }
92
93         /**
94          * Setter for wrapper class name
95          *
96          * @param       $wrapperConfigEntry             Configuration entry which hold the wrapper class' name
97          * @return      void
98          */
99         public final function setWrapperConfigEntry ($wrapperConfigEntry) {
100                 $this->wrapperConfigEntry = (string) $wrapperConfigEntry;
101         }
102
103         /**
104          * Getter for wrapper class name
105          *
106          * @return      $wrapperConfigEntry             Configuration entry which hold the wrapper class' name
107          */
108         public final function getWrapperConfigEntry () {
109                 return $this->wrapperConfigEntry;
110         }
111
112         /**
113          * Getter for criteria array
114          *
115          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
116          * @return      $criteria
117          */
118         public final function getCriteriaArray ($criteriaType = 'default') {
119                 return $this->criteria[$criteriaType];
120         }
121
122         /**
123          * Getter for criteria array 'choice' type
124          *
125          * @return      $criteria
126          */
127         public final function getCriteriaChoiceArray () {
128                 return $this->getCriteriaArray('choice');
129         }
130
131         /**
132          * Getter for criteria array 'exclude' type
133          *
134          * @return      $criteria
135          */
136         public final function getCriteriaExcludeArray () {
137                 return $this->getCriteriaArray('exclude');
138         }
139
140         /**
141          * Add criteria, this method converts dashes to underscores because dashes
142          * are not valid for criteria keys.
143          *
144          * @param       $criteriaKey    Criteria key
145          * @param       $criteriaValue  Criteria value
146          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
147          * @return      void
148          */
149         public final function addCriteria ($criteriaKey, $criteriaValue, $criteriaType = 'default') {
150                 // Make sure no 'my-' or 'my_' passes this point
151                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
152
153                 // Convert dashes to underscore
154                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
155
156                 // Debug message
157                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '(' . $this->__toString() . ')-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
158
159                 // Is it already there?
160                 if ($this->isKeySet($criteriaType, $criteriaKey)) {
161                         // Append it
162                         $this->criteria[$criteriaType][$criteriaKey] .= ',' . (string) $criteriaValue;
163                 } else {
164                         // Add it
165                         $this->criteria[$criteriaType][$criteriaKey] = (string) $criteriaValue;
166                 }
167         }
168
169         /**
170          * Add "choice" criteria, this method converts dashes to underscores because
171          * dashes are not valid for criteria keys.
172          *
173          * @param       $criteriaKey    Criteria key
174          * @param       $criteriaValue  Criteria value
175          * @return      void
176          */
177         public final function addChoiceCriteria ($criteriaKey, $criteriaValue) {
178                 // Make sure no 'my-' or 'my_' passes this point
179                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
180
181                 // Debug message
182                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '(' . $this->__toString() . ')-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
183
184                 // Add it
185                 $this->criteria['choice'][$this->convertDashesToUnderscores($criteriaKey)][] = (string) $criteriaValue;
186         }
187
188         /**
189          * Add "exclude" criteria, this method converts dashes to underscores because
190          * dashes are not valid for criteria keys.
191          *
192          * @param       $criteriaKey    Criteria key
193          * @param       $criteriaValue  Criteria value
194          * @return      void
195          */
196         public final function addExcludeCriteria ($criteriaKey, $criteriaValue) {
197                 // Add it with generic method
198                 $this->addCriteria($criteriaKey, $criteriaValue, 'exclude');
199         }
200
201         /**
202          * Add configured criteria
203          *
204          * @param       $criteriaKey    Criteria key
205          * @param       $configEntry    Configuration entry
206          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
207          * @return      void
208          */
209         public final function addConfiguredCriteria ($criteriaKey, $configEntry, $criteriaType = 'default') {
210                 // Add the configuration entry as a criteria
211                 $value = $this->getConfigInstance()->getConfigEntry($configEntry);
212                 $this->addCriteria($criteriaKey, $value, $criteriaType);
213         }
214
215         /**
216          * Get criteria element or FALSE if not found
217          *
218          * @param       $criteriaKey    The requested criteria key
219          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
220          * @return      $value                  Whether the value of the critera or FALSE
221          */
222         public function getCriteriaElemnent ($criteriaKey, $criteriaType = 'default') {
223                 // Make sure no 'my-' or 'my_' passes this point
224                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE));
225
226                 // Convert dashes to underscore
227                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
228
229                 // Debug message
230                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteria()=' . count($this->criteria[$criteriaType]));
231
232                 // Default is not found
233                 $value = FALSE;
234
235                 // Is the criteria there?
236                 if ($this->isKeySet($criteriaType, $criteriaKey)) {
237                         // Then use it
238                         $value = $this->criteria[$criteriaType][$criteriaKey];
239                 } // END - if
240
241                 // Return the value
242                 return $value;
243         }
244
245         /**
246          * Get criteria element or FALSE if not found for 'choice' type
247          *
248          * @param       $criteriaKey    The requested criteria key
249          * @return      $value                  Whether the value of the critera or FALSE
250          */
251         public function getCriteriaChoiceElemnent ($criteriaKey) {
252                 // Call inner method
253                 return $this->getCriteriaElemnent($criteriaKey, 'choice');
254         }
255
256         /**
257          * Get criteria element or FALSE if not found for 'exclude' type
258          *
259          * @param       $criteriaKey    The requested criteria key
260          * @return      $value                  Whether the value of the critera or FALSE
261          */
262         public function getCriteriaExcludeElemnent ($criteriaKey) {
263                 // Call inner method
264                 return $this->getCriteriaElemnent($criteriaKey, 'exclude');
265         }
266
267         /**
268          * Checks whether given array entry matches
269          *
270          * @param       $entryArray             Array with the entries to find
271          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
272          * @return      $matches                Whether the entry matches or not
273          */
274         public function ifEntryMatches (array $entryArray, $criteriaType = 'default') {
275                 // First nothing matches and nothing is counted
276                 $matches = false;
277                 $counted = 0;
278
279                 // Walk through all entries
280                 foreach ($entryArray as $key => $entry) {
281                         // Make sure no 'my-' or 'my_' passes this point
282                         assert((strpos($key, 'my-') === FALSE) && (strpos($key, 'my_') === FALSE));
283
284                         // Convert dashes to underscore
285                         $key = $this->convertDashesToUnderscores($key);
286
287                         // Then walk through all search criteria
288                         foreach ($this->criteria[$criteriaType] as $criteriaKey => $criteriaValue) {
289                                 // Make sure no 'my-' or 'my_' passes this point
290                                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
291
292                                 // Convert dashes to underscore
293                                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
294
295                                 // Is the element found and does it match?
296                                 if (($key == $criteriaKey) && ($criteriaValue == $entry)) {
297                                         // Then count this one up
298                                         $counted++;
299                                 } // END - if
300                         } // END - foreach
301                 } // END - foreach
302
303                 // Now check if expected criteria counts match
304                 $matches = ($counted == count($this->criteria[$criteriaType]));
305
306                 // Return the result
307                 return $matches;
308         }
309
310         /**
311          * Checks whether given array 'choice' entry matches
312          *
313          * @param       $entryArray             Array with the entries to find
314          * @return      $matches                Whether the entry matches or not
315          */
316         public function ifChoiceMatches (array $entryArray) {
317                 // Call inner method
318                 return $this->ifEntryMatches($entryArray, 'choice');
319         }
320
321         /**
322          * Checks whether given array 'exclude' entry matches
323          *
324          * @param       $entryArray             Array with the entries to find
325          * @return      $matches                Whether the entry matches or not
326          */
327         public function ifExcludeMatches (array $entryArray) {
328                 // Call inner method
329                 return $this->ifEntryMatches($entryArray, 'exclude');
330         }
331
332         /**
333          * "Getter" for a cache key
334          *
335          * @param       $onlyKeys       Only use these keys for a cache key
336          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
337          * @return      $cacheKey       The key suitable for the cache system
338          */
339         public function getCacheKey ($onlyKeys = array(), $criteriaType = 'default') {
340                 // Debug message
341                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($this->__toString() . ': criteriaType=' . $criteriaType . ',count()=' . count($this->criteria));
342
343                 // Make sure the criteria is there
344                 assert((isset($this->criteria[$criteriaType])) && (is_array($this->criteria[$criteriaType])));
345
346                 // Initialize the key
347                 $cacheKey = '';
348
349                 // Now walk through all criterias
350                 foreach ($this->criteria[$criteriaType] as $criteriaKey => $criteriaValue) {
351                         // Make sure no 'my-' or 'my_' passes this point
352                         assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
353
354                         // Convert dashes to underscore
355                         $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
356
357                         // Is the value in array or is $onlyKeys empty?
358                         if ((isset($onlyKeys[$criteriaKey])) || (count($onlyKeys) == 0)) {
359                                 // Add the value URL encoded to avoid any trouble with special characters
360                                 $cacheKey .= sprintf("%s=%s;",
361                                         $criteriaKey,
362                                         urlencode($criteriaValue)
363                                 );
364                         } // END - if
365                 } // END - foreach
366
367                 // Remove last semicolon
368                 $cacheKey = substr($cacheKey, 0, -1);
369
370                 // Is the instance SearchCriteria?
371                 if ($this instanceof SearchCriteria) {
372                         // Check if 'limit' and 'skip' are in
373                         if (((isset($onlyKeys['limit'])) && (isset($onlyKeys['skip']))) || (count($onlyKeys) == 0)) {
374                                 // Add limit and skip values
375                                 $cacheKey .= sprintf(";%%limit%%=%s;%%skip%%=%s",
376                                         $this->getLimit(),
377                                         $this->getSkip()
378                                 );
379                         } // END - if
380                 } // END - if
381
382                 // Return the cache key
383                 return $cacheKey;
384         }
385
386         /**
387          * "Getter" for a cache key ('choice' type)
388          *
389          * @param       $onlyKeys       Only use these keys for a cache key
390          * @return      $cacheKey       The key suitable for the cache system
391          */
392         public function getCacheKeyChoice ($onlyKeys = array()) {
393                 // Call inner method
394                 return $this->getCacheKey($onlyKeys, 'choice');
395         }
396
397         /**
398          * "Getter" for a cache key ('exclude' type)
399          *
400          * @param       $onlyKeys       Only use these keys for a cache key
401          * @return      $cacheKey       The key suitable for the cache system
402          */
403         public function getCacheKeyExclude ($onlyKeys = array()) {
404                 // Call inner method
405                 return $this->getCacheKey($onlyKeys, 'exclude');
406         }
407
408         /**
409          * Count the criteria, e.g. useful to find out if a database query has no
410          * limitation (search criteria).
411          *
412          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
413          * @return      $count  Count of all criteria entries
414          */
415         public final function count ($criteriaType = 'default') {
416                 // Return it
417                 return count($this->criteria[$criteriaType]);
418         }
419
420         /**
421          * Count 'choice' criteria, e.g. useful to find out if a database query
422          * has no limitation (search criteria).
423          *
424          * @return      $count  Count of all criteria entries
425          */
426         public final function countChoice () {
427                 return $this->count('choice');
428         }
429
430         /**
431          * Count 'exclude' criteria, e.g. useful to find out if a database query
432          * has no limitation (search criteria).
433          *
434          * @return      $count  Count of all criteria entries
435          */
436         public final function countExclude () {
437                 return $this->count('exclude');
438         }
439 }
440
441 // [EOF]
442 ?>