Fixed more generic array handling, introduced unsetGenericArrayKey()
[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          * Protected constructor
32          *
33          * @param       $className      Name of the class
34          * @return      void
35          */
36         protected function __construct ($className) {
37                 // Call parent constructor
38                 parent::__construct($className);
39
40                 // Initialize all criteria arrays
41                 foreach (array('default', 'choice', 'exclude') as $criteriaType) {
42                         // Init it
43                         $this->initGenericArrayKey('criteria', $criteriaType, 'entries');
44                 } // END - foreach
45         }
46
47         /**
48          * Checks whether given key is set
49          *
50          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
51          * @param       $criteriaKey    Criteria key
52          * @return      $isSet                  Whether key is set
53          */
54         public function isKeySet ($criteriaType, $criteriaKey) {
55                 // Make sure no 'my-' or 'my_' passes this point
56                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE));
57
58                 // Determine it
59                 $isSet = $this->isGenericArrayElementSet('criteria', $criteriaType, 'entries', $criteriaKey);
60
61                 // Return it
62                 return $isSet;
63         }
64
65         /**
66          * Checks whether given key is set for 'choice' type
67          *
68          * @param       $criteriaKey    Criteria key
69          * @return      $isSet                  Whether key is set
70          */
71         public function isChoiceKeySet ($criteriaKey) {
72                 // Call inner method
73                 return $this->isKeySet('choice', $criteriaKey);
74         }
75
76         /**
77          * Checks whether given key is set for 'exclude' type
78          *
79          * @param       $criteriaKey    Criteria key
80          * @return      $isSet                  Whether key is set
81          */
82         public function isExcludeKeySet ($criteriaKey) {
83                 // Call inner method
84                 return $this->isKeySet('exclude', $criteriaKey);
85         }
86
87         /**
88          * Setter for wrapper class name
89          *
90          * @param       $wrapperConfigEntry             Configuration entry which hold the wrapper class' name
91          * @return      void
92          */
93         public final function setWrapperConfigEntry ($wrapperConfigEntry) {
94                 $this->wrapperConfigEntry = (string) $wrapperConfigEntry;
95         }
96
97         /**
98          * Getter for wrapper class name
99          *
100          * @return      $wrapperConfigEntry             Configuration entry which hold the wrapper class' name
101          */
102         public final function getWrapperConfigEntry () {
103                 return $this->wrapperConfigEntry;
104         }
105
106         /**
107          * Getter for criteria array
108          *
109          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
110          * @return      $criteria
111          */
112         public final function getCriteriaArray ($criteriaType = 'default') {
113                 return $this->getGenericArrayKey('criteria', $criteriaType, 'entries');
114         }
115
116         /**
117          * Getter for criteria array 'choice' type
118          *
119          * @return      $criteria
120          */
121         public final function getCriteriaChoiceArray () {
122                 return $this->getCriteriaArray('choice');
123         }
124
125         /**
126          * Getter for criteria array 'exclude' type
127          *
128          * @return      $criteria
129          */
130         public final function getCriteriaExcludeArray () {
131                 return $this->getCriteriaArray('exclude');
132         }
133
134         /**
135          * Unsets a criteria key from all criteria types
136          *
137          * @param       $criteriaKey    Criteria key to unset
138          * @return      void
139          */
140         public final function unsetCriteria ($criteriaKey) {
141                 // Make sure no 'my-' or 'my_' passes this point
142                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE));
143
144                 // Convert dashes to underscore
145                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
146
147                 // "Walk" through all criterias
148                 foreach ($this->getGenericArray('criteria') as $criteriaType => $dummy) {
149                         // Remove it
150                         $this->unsetGenericArrayElement('criteria', $criteriaType, 'entries', $criteriaKey);
151                 } // END - foreach
152         }
153
154         /**
155          * Add criteria, this method converts dashes to underscores because dashes
156          * are not valid for criteria keys.
157          *
158          * @param       $criteriaKey    Criteria key
159          * @param       $criteriaValue  Criteria value
160          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
161          * @return      void
162          */
163         public final function addCriteria ($criteriaKey, $criteriaValue, $criteriaType = 'default') {
164                 // Make sure no 'my-' or 'my_' passes this point
165                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
166
167                 // Convert dashes to underscore
168                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
169
170                 // Debug message
171                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '(' . $this->__toString() . ')-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
172
173                 // Append it
174                 $this->appendStringToGenericArrayElement('criteria', $criteriaType, $criteriaKey, $criteriaValue);
175         }
176
177         /**
178          * Add "choice" criteria, this method converts dashes to underscores because
179          * dashes are not valid for criteria keys.
180          *
181          * @param       $criteriaKey    Criteria key
182          * @param       $criteriaValue  Criteria value
183          * @return      void
184          */
185         public final function addChoiceCriteria ($criteriaKey, $criteriaValue) {
186                 // Make sure no 'my-' or 'my_' passes this point
187                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
188
189                 // Debug message
190                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '(' . $this->__toString() . ')-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
191
192                 // Add it
193                 $this->pushValueToGenericArrayElement('criteria', 'choice', $this->convertDashesToUnderscores($criteriaKey), (string) $criteriaValue);
194         }
195
196         /**
197          * Add "exclude" criteria, this method converts dashes to underscores because
198          * dashes are not valid for criteria keys.
199          *
200          * @param       $criteriaKey    Criteria key
201          * @param       $criteriaValue  Criteria value
202          * @return      void
203          */
204         public final function addExcludeCriteria ($criteriaKey, $criteriaValue) {
205                 // Add it with generic method
206                 $this->addCriteria($criteriaKey, $criteriaValue, 'exclude');
207         }
208
209         /**
210          * Add configured criteria
211          *
212          * @param       $criteriaKey    Criteria key
213          * @param       $configEntry    Configuration entry
214          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
215          * @return      void
216          */
217         public final function addConfiguredCriteria ($criteriaKey, $configEntry, $criteriaType = 'default') {
218                 // Add the configuration entry as a criteria
219                 $value = $this->getConfigInstance()->getConfigEntry($configEntry);
220                 $this->addCriteria($criteriaKey, $value, $criteriaType);
221         }
222
223         /**
224          * Get criteria element or FALSE if not found
225          *
226          * @param       $criteriaKey    The requested criteria key
227          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
228          * @return      $value                  Whether the value of the critera or FALSE
229          */
230         public function getCriteriaElemnent ($criteriaKey, $criteriaType = 'default') {
231                 // Make sure no 'my-' or 'my_' passes this point
232                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE));
233
234                 // Convert dashes to underscore
235                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
236
237                 // Debug message
238                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteria()=' . $this->countGenericArrayGroup('criteria', $criteriaType)));
239
240                 // Default is not found
241                 $value = FALSE;
242
243                 // Is the criteria there?
244                 if ($this->isKeySet($criteriaType, $criteriaKey)) {
245                         // Then use it
246                         $value = $this->getGenericArrayKey('criteria', $criteriaType, $criteriaKey);
247                 } // END - if
248
249                 // Return the value
250                 return $value;
251         }
252
253         /**
254          * Get criteria element or FALSE if not found for 'choice' type
255          *
256          * @param       $criteriaKey    The requested criteria key
257          * @return      $value                  Whether the value of the critera or FALSE
258          */
259         public function getCriteriaChoiceElemnent ($criteriaKey) {
260                 // Call inner method
261                 return $this->getCriteriaElemnent($criteriaKey, 'choice');
262         }
263
264         /**
265          * Get criteria element or FALSE if not found for 'exclude' type
266          *
267          * @param       $criteriaKey    The requested criteria key
268          * @return      $value                  Whether the value of the critera or FALSE
269          */
270         public function getCriteriaExcludeElemnent ($criteriaKey) {
271                 // Call inner method
272                 return $this->getCriteriaElemnent($criteriaKey, 'exclude');
273         }
274
275         /**
276          * Checks whether given array entry matches
277          *
278          * @param       $entryArray             Array with the entries to find
279          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
280          * @return      $matches                Whether the entry matches or not
281          */
282         public function ifEntryMatches (array $entryArray, $criteriaType = 'default') {
283                 // First nothing matches and nothing is counted
284                 $matches = FALSE;
285                 $counted = 0;
286
287                 // Walk through all entries
288                 foreach ($entryArray as $key => $entry) {
289                         // Make sure no 'my-' or 'my_' passes this point
290                         assert((strpos($key, 'my-') === FALSE) && (strpos($key, 'my_') === FALSE));
291
292                         // Convert dashes to underscore
293                         $key = $this->convertDashesToUnderscores($key);
294
295                         // Then walk through all search criteria
296                         foreach ($this->getGenericSubArray('criteria', $criteriaType) as $criteriaKey => $criteriaValue) {
297                                 // Make sure no 'my-' or 'my_' passes this point
298                                 assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
299
300                                 // Convert dashes to underscore
301                                 $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
302
303                                 // Is the element found and does it match?
304                                 if (($key == $criteriaKey) && ($criteriaValue == $entry)) {
305                                         // Then count this one up
306                                         $counted++;
307                                 } // END - if
308                         } // END - foreach
309                 } // END - foreach
310
311                 // Now check if expected criteria counts match
312                 $matches = ($counted == $this->countGenericArrayGroup('criteria', $criteriaType));
313
314                 // Return the result
315                 return $matches;
316         }
317
318         /**
319          * Checks whether given array 'choice' entry matches
320          *
321          * @param       $entryArray             Array with the entries to find
322          * @return      $matches                Whether the entry matches or not
323          */
324         public function ifChoiceMatches (array $entryArray) {
325                 // Call inner method
326                 return $this->ifEntryMatches($entryArray, 'choice');
327         }
328
329         /**
330          * Checks whether given array 'exclude' entry matches
331          *
332          * @param       $entryArray             Array with the entries to find
333          * @return      $matches                Whether the entry matches or not
334          */
335         public function ifExcludeMatches (array $entryArray) {
336                 // Call inner method
337                 return $this->ifEntryMatches($entryArray, 'exclude');
338         }
339
340         /**
341          * "Getter" for a cache key
342          *
343          * @param       $onlyKeys       Only use these keys for a cache key
344          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
345          * @return      $cacheKey       The key suitable for the cache system
346          */
347         public function getCacheKey ($onlyKeys = array(), $criteriaType = 'default') {
348                 // Debug message
349                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput($this->__toString() . ': criteriaType=' . $criteriaType . ',count()=' . $this->countGenericArray('criteria')));
350
351                 // Make sure the criteria is there
352                 assert($this->isValidGenericArrayGroup('criteria', $criteriaType));
353
354                 // Initialize the key
355                 $cacheKey = '';
356
357                 // Now walk through all criterias
358                 foreach ($this->getGenericSubArray('criteria', $criteriaType) as $criteriaKey => $criteriaValue) {
359                         // Make sure no 'my-' or 'my_' passes this point
360                         assert((strpos($criteriaKey, 'my-') === FALSE) && (strpos($criteriaKey, 'my_') === FALSE) && (!is_bool($criteriaValue)));
361
362                         // Convert dashes to underscore
363                         $criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
364
365                         // Is the value in array or is $onlyKeys empty?
366                         if ((isset($onlyKeys[$criteriaKey])) || (count($onlyKeys) == 0)) {
367                                 // Add the value URL encoded to avoid any trouble with special characters
368                                 $cacheKey .= sprintf("%s=%s;",
369                                         $criteriaKey,
370                                         urlencode($criteriaValue)
371                                 );
372                         } // END - if
373                 } // END - foreach
374
375                 // Remove last semicolon
376                 $cacheKey = substr($cacheKey, 0, -1);
377
378                 // Is the instance SearchCriteria?
379                 if ($this instanceof SearchCriteria) {
380                         // Check if 'limit' and 'skip' are in
381                         if (((isset($onlyKeys['limit'])) && (isset($onlyKeys['skip']))) || (count($onlyKeys) == 0)) {
382                                 // Add limit and skip values
383                                 $cacheKey .= sprintf(";%%limit%%=%s;%%skip%%=%s",
384                                         $this->getLimit(),
385                                         $this->getSkip()
386                                 );
387                         } // END - if
388                 } // END - if
389
390                 // Return the cache key
391                 return $cacheKey;
392         }
393
394         /**
395          * "Getter" for a cache key ('choice' type)
396          *
397          * @param       $onlyKeys       Only use these keys for a cache key
398          * @return      $cacheKey       The key suitable for the cache system
399          */
400         public function getCacheKeyChoice ($onlyKeys = array()) {
401                 // Call inner method
402                 return $this->getCacheKey($onlyKeys, 'choice');
403         }
404
405         /**
406          * "Getter" for a cache key ('exclude' type)
407          *
408          * @param       $onlyKeys       Only use these keys for a cache key
409          * @return      $cacheKey       The key suitable for the cache system
410          */
411         public function getCacheKeyExclude ($onlyKeys = array()) {
412                 // Call inner method
413                 return $this->getCacheKey($onlyKeys, 'exclude');
414         }
415
416         /**
417          * Count the criteria, e.g. useful to find out if a database query has no
418          * limitation (search criteria).
419          *
420          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
421          * @return      $count  Count of all criteria entries
422          */
423         public final function count ($criteriaType = 'default') {
424                 // Return it
425                 return $this->countGenericArrayGroup('criteria', $criteriaType);
426         }
427
428         /**
429          * Count 'choice' criteria, e.g. useful to find out if a database query
430          * has no limitation (search criteria).
431          *
432          * @return      $count  Count of all criteria entries
433          */
434         public final function countChoice () {
435                 return $this->count('choice');
436         }
437
438         /**
439          * Count 'exclude' criteria, e.g. useful to find out if a database query
440          * has no limitation (search criteria).
441          *
442          * @return      $count  Count of all criteria entries
443          */
444         public final function countExclude () {
445                 return $this->count('exclude');
446         }
447 }
448
449 // [EOF]
450 ?>