]> git.mxchange.org Git - core.git/blob - framework/main/classes/criteria/class_BaseCriteria.php
Continued:
[core.git] / framework / main / classes / criteria / class_BaseCriteria.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Criteria;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Criteria\Search\SearchCriteria;
8 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
9 use Org\Mxchange\CoreFramework\Utils\Strings\StringUtils;
10
11 // Import SPL stuff
12 use \BadMethodCallException;
13 use \InvalidArgumentException;
14 use \UnexpectedValueException;
15
16 /**
17  * A general crtieria class
18  *
19  * @author              Roland Haeder <webmaster@shipsimu.org>
20  * @version             0.0.0
21  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2022 Core Developer Team
22  * @license             GNU GPL 3.0 or any newer version
23  * @link                http://www.shipsimu.org
24  *
25  * This program is free software: you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation, either version 3 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
37  */
38 abstract class BaseCriteria extends BaseFrameworkSystem implements Criteria {
39         /**
40          * Frontend class name stored in config entry
41          */
42         private $frontendConfigEntry = '';
43
44         /**
45          * All supported criteria types
46          */
47         private static $CRITERIA_TYPES = [];
48
49         /**
50          * Protected constructor
51          *
52          * @param       $className      Name of the class
53          * @return      void
54          */
55         protected function __construct (string $className) {
56                 // Call parent constructor
57                 parent::__construct($className);
58
59                 // Initialize valid criteria types array
60                 self::$CRITERIA_TYPES = [Criteria::CRITERIA_TYPE_DEFAULT, Criteria::CRITERIA_TYPE_CHOICE, Criteria::CRITERIA_TYPE_EXCLUDE];
61
62                 // Initialize all criteria arrays
63                 foreach (self::$CRITERIA_TYPES as $criteriaType) {
64                         // Init it
65                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Initializing criteriaType=%s ...', $criteriaType));
66                         $this->initGenericArrayKey('criteria', $criteriaType, 'entries');
67                 }
68         }
69
70         /**
71          * Count the criteria, e.g. useful to find out if a database query has no
72          * limitation (search criteria).
73          *
74          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
75          * @return      $count  Count of all criteria entries
76          * @throws      InvalidArgumentException        If a parameter is not valid
77          */
78         protected final function count (string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
79                 // Check parameter
80                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaType));
81                 if (empty($criteriaType)) {
82                         // Throw it again
83                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
84                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
85                         // Throw it again
86                         throw new InvalidArgumentException(sprintf('criteriaType=%s is not supported', $criteriaType));
87                 }
88
89                 // Invoke inner method
90                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->countGenericArrayGroup(criteria, %s) ...', strtoupper($criteriaType), $criteriaType));
91                 return $this->countGenericArrayGroup('criteria', $criteriaType);
92         }
93
94         /**
95          * Checks whether given key is set
96          *
97          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
98          * @param       $criteriaKey    Criteria key
99          * @return      $isset                  Whether key is set
100          * @throws      InvalidArgumentException        If a parameter is not valid
101          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
102          */
103         public function isKeySet (string $criteriaType, string $criteriaKey) {
104                 // Check parameters
105                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaType=%s,criteriaKey=%s - CALLED!', strtoupper($criteriaType), $criteriaType, $criteriaKey));
106                 if (empty($criteriaType)) {
107                         // Throw it again
108                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
109                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
110                         // Throw it again
111                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
112                 } elseif (empty($criteriaKey)) {
113                         // Throw it again
114                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
115                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
116                         // Throw it again
117                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
118                 }
119
120                 // Determine it
121                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->isGenericArrayElementSet(criteria,%s,entries,%s) ...', strtoupper($criteriaType), $criteriaType, $criteriaKey));
122                 $isset = $this->isGenericArrayElementSet('criteria', $criteriaType, 'entries', $criteriaKey);
123
124                 // Return it
125                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: isset=%d - EXIT!', strtoupper($criteriaType), intval($isset)));
126                 return $isset;
127         }
128
129         /**
130          * Checks whether given key is set for 'choice' type
131          *
132          * @param       $criteriaKey    Criteria key
133          * @return      $isset                  Whether key is set
134          * @throws      InvalidArgumentException        If a parameter is not valid
135          */
136         public function isChoiceKeySet (string $criteriaKey) {
137                 // Validate parameter
138                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s - CALLED!', $criteriaKey));
139                 if (empty($criteriaKey)) {
140                         // Throw it again
141                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
142                 }
143
144                 // Invoke inner method
145                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->isKeySet(%s,%s) ...', Criteria::CRITERIA_TYPE_CHOICE, $criteriaKey));
146                 return $this->isKeySet(Criteria::CRITERIA_TYPE_CHOICE, $criteriaKey);
147         }
148
149         /**
150          * Checks whether given key is set for 'exclude' type
151          *
152          * @param       $criteriaKey    Criteria key
153          * @return      $isset                  Whether key is set
154          * @throws      InvalidArgumentException        If a parameter is not valid
155          */
156         public function isExcludeKeySet (string $criteriaKey) {
157                 // Validate parameter
158                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s - CALLED!', $criteriaKey));
159                 if (empty($criteriaKey)) {
160                         // Throw it again
161                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
162                 }
163
164                 // Invoke inner method
165                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->isKeySet(%s,%s) ...', Criteria::CRITERIA_TYPE_EXCLUDE, $criteriaKey));
166                 return $this->isKeySet(Criteria::CRITERIA_TYPE_EXCLUDE, $criteriaKey);
167         }
168
169         /**
170          * Setter for frontend class name
171          *
172          * @param       $frontendConfigEntry            Configuration entry which hold the frontend class' name
173          * @return      void
174          */
175         public final function setFrontendConfigEntry (string $frontendConfigEntry) {
176                 $this->frontendConfigEntry = $frontendConfigEntry;
177         }
178
179         /**
180          * Getter for frontend class name
181          *
182          * @return      $frontendConfigEntry            Configuration entry which hold the frontend class' name
183          */
184         public final function getFrontendConfigEntry () {
185                 return $this->frontendConfigEntry;
186         }
187
188         /**
189          * Getter for criteria array
190          *
191          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
192          * @return      $criteria
193          * @throws      InvalidArgumentException        If a parameter is not valid
194          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
195          */
196         public final function getCriteriaArray (string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
197                 // Check parameters
198                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaType));
199                 if (empty($criteriaType)) {
200                         // Throw it again
201                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
202                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
203                         // Throw it again
204                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
205                 }
206
207                 // Invoke inner method
208                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->getGenericArrayKey(criteria,%s,entries) ...', strtoupper($criteriaType), $criteriaType));
209                 return $this->getGenericArrayKey('criteria', $criteriaType, 'entries');
210         }
211
212         /**
213          * Getter for criteria array 'choice' type
214          *
215          * @return      $criteria
216          */
217         public final function getCriteriaChoiceArray () {
218                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: CALLED!', strtoupper($criteriaType)));
219                 return $this->getCriteriaArray(Criteria::CRITERIA_TYPE_CHOICE);
220         }
221
222         /**
223          * Getter for criteria array 'exclude' type
224          *
225          * @return      $criteria
226          */
227         public final function getCriteriaExcludeArray () {
228                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: CALLED!', strtoupper($criteriaType)));
229                 return $this->getCriteriaArray(Criteria::CRITERIA_TYPE_EXCLUDE);
230         }
231
232         /**
233          * Unsets a criteria key from all criteria types
234          *
235          * @param       $criteriaKey    Criteria key to unset
236          * @return      void
237          */
238         public final function unsetCriteria (string $criteriaKey) {
239                 // Check parameter
240                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s - CALLED!', $criteriaKey));
241                 if (empty($criteriaKey)) {
242                         // Throw it again
243                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
244                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
245                         // Throw it again
246                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
247                 }
248
249                 // Convert dashes to underscore
250                 $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
251
252                 // "Walk" through all criterias
253                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s', strtoupper($criteriaType), $criteriaKey));
254                 foreach ($this->getGenericArray('criteria') as $criteriaType => $dummy) {
255                         // Remove it
256                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Removing criteriaType=%s,criteriaKey=%s ...', strtoupper($criteriaType), $criteriaType, $criteriaKey));
257                         $this->unsetGenericArrayElement('criteria', $criteriaType, 'entries', $criteriaKey);
258                 }
259
260                 // Trace message
261                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: EXIT!');
262         }
263
264         /**
265          * Add criteria, this method converts dashes to underscores because dashes
266          * are not valid for criteria keys.
267          *
268          * @param       $criteriaKey    Criteria key
269          * @param       $criteriaValue  Criteria value
270          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
271          * @return      void
272          * @throws      InvalidArgumentException        If a parameter is not valid
273          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
274          */
275         public final function addCriteria (string $criteriaKey, $criteriaValue, string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
276                 // Check parameter
277                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaValue[]=%s,criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaType));
278                 if (empty($criteriaKey)) {
279                         // Throw IAE
280                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
281                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
282                         // Throw it again
283                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
284                 } elseif (is_array($criteriaValue) || is_bool($criteriaValue) || is_object($criteriaValue) || is_resource($criteriaValue)) {
285                         // Throw it again
286                         throw new InvalidArgumentException(sprintf('value[]=%s is not supported', gettype($criteriaValue)));
287                 } elseif (empty($criteriaType)) {
288                         // Throw it again
289                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
290                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
291                         // Throw it again
292                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
293                 }
294
295                 // Convert dashes to underscore
296                 $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
297
298                 // Set it
299                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->setGenericArrayElement(criteria,%s,entries,%s,criteriaValue[]=%s) ...', strtoupper($criteriaType), $criteriaType, $criteriaKey, gettype($criteriaValue)));
300                 $this->setGenericArrayElement('criteria', $criteriaType, 'entries', $criteriaKey, $criteriaValue);
301
302                 // Trace message
303                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: EXIT!', strtoupper($criteriaType)));
304         }
305
306         /**
307          * Set criteria, this method converts dashes to underscores because dashes
308          * are not valid for criteria keys.
309          *
310          * @param       $criteriaKey    Criteria key
311          * @param       $criteriaValue  Criteria value
312          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
313          * @return      void
314          * @throws      InvalidArgumentException        If a parameter is not valid
315          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
316          */
317         public final function setCriteria (string $criteriaKey, $criteriaValue, string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
318                 // Check parameter
319                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaValue[]=%s$criteriaValue,criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaType));
320                 if (empty($criteriaKey)) {
321                         // Throw IAE
322                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
323                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
324                         // Throw it again
325                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
326                 } elseif (is_array($criteriaValue) || is_bool($criteriaValue) || is_object($criteriaValue) || is_resource($criteriaValue)) {
327                         // Throw it again
328                         throw new InvalidArgumentException(sprintf('value[]=%s is not supported', gettype($criteriaValue)));
329                 } elseif (empty($criteriaType)) {
330                         // Throw it again
331                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
332                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
333                         // Throw it again
334                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
335                 }
336
337                 // Convert dashes to underscore
338                 $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
339
340                 // Set it
341                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->setGenericArrayElement(criteria,%s,entries,%s,criteriaValue[]=%s) ...', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue)));
342                 $this->setGenericArrayElement('criteria', $criteriaType, 'entries', $criteriaKey, $criteriaValue);
343
344                 // Trace message
345                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: EXIT!');
346         }
347
348         /**
349          * Add "choice" criteria, this method converts dashes to underscores because
350          * dashes are not valid for criteria keys.
351          *
352          * @param       $criteriaKey    Criteria key
353          * @param       $criteriaValue  Criteria value
354          * @return      void
355          * @throws      InvalidArgumentException        If a parameter is not valid
356          * @throws      UnexpectedValueException        If $criteriaValue has an unexpected type
357          */
358         public final function addChoiceCriteria (string $criteriaKey, $criteriaValue) {
359                 // Check parameter
360                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s,criteriaValue[]=%s - CALLED!', $criteriaKey, gettype($criteriaValue)));
361                 if (empty($criteriaKey)) {
362                         // Throw IAE
363                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
364                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
365                         // Throw it again
366                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
367                 } elseif (is_array($criteriaValue) || is_bool($criteriaValue) || is_object($criteriaValue) || is_resource($criteriaValue)) {
368                         // Throw UAE
369                         throw new UnexpectedValueException(sprintf('criteriaValue[]=%s is not accepted', gettype($criteriaValue)));
370                 }
371
372                 // Add it
373                 $this->pushValueToGenericArrayElement('criteria', Criteria::CRITERIA_TYPE_CHOICE, 'entries', StringUtils::convertDashesToUnderscores($criteriaKey), (string) $criteriaValue);
374
375                 // Trace message
376                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: EXIT!');
377         }
378
379         /**
380          * Add "exclude" criteria, this method converts dashes to underscores because
381          * dashes are not valid for criteria keys.
382          *
383          * @param       $criteriaKey    Criteria key
384          * @param       $criteriaValue  Criteria value
385          * @return      void
386          * @throws      InvalidArgumentException        If a parameter is not valid
387          * @throws      UnexpectedValueException        If $criteriaValue has an unexpected type
388          */
389         public final function addExcludeCriteria (string $criteriaKey, $criteriaValue) {
390                 // Check parameter
391                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s,criteriaValue[%s]=%s - CALLED!', $criteriaKey, gettype($criteriaValue), $criteriaValue));
392                 if (empty($criteriaKey)) {
393                         // Throw IAE
394                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
395                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
396                         // Throw it again
397                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
398                 } elseif (is_array($criteriaValue) || is_bool($criteriaValue) || is_object($criteriaValue) || is_resource($criteriaValue)) {
399                         // Throw UAE
400                         throw new UnexpectedValueException(sprintf('criteriaValue[]=%s is not accepted', gettype($criteriaValue)));
401                 }
402
403                 // Add it with generic method
404                 $this->addCriteria($criteriaKey, $criteriaValue, Criteria::CRITERIA_TYPE_EXCLUDE);
405
406                 // Trace message
407                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: EXIT!');
408         }
409
410         /**
411          * Add configured criteria
412          *
413          * @param       $criteriaKey    Criteria key
414          * @param       $configEntry    Configuration entry
415          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
416          * @return      void
417          * @throws      InvalidArgumentException        If a parameter is not valid
418          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
419          */
420         public final function addConfiguredCriteria (string $criteriaKey, string $configEntry, string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
421                 // Check parameter
422                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,configEntry=%s,criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaKey, $configEntry, $criteriaType));
423                 if (empty($criteriaKey)) {
424                         // Throw IAE
425                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
426                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
427                         // Throw it again
428                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
429                 } elseif (empty($configEntry)) {
430                         // Throw it again
431                         throw new InvalidArgumentException('Parameter "configEntry" is empty');
432                 } elseif (empty($criteriaType)) {
433                         // Throw it again
434                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
435                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
436                         // Throw it again
437                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
438                 }
439
440                 // Add the configuration entry as a criteria
441                 $value = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($configEntry);
442
443                 // Invoke inner method
444                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->addCriteria(%s,value[%s]=%s,%s) ...', strtoupper($criteriaType), $criteriaKey, gettype($value), $value, $criteriaType));
445                 $this->addCriteria($criteriaKey, $value, $criteriaType);
446
447                 // Trace message
448                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: EXIT!', strtoupper($criteriaType)));
449         }
450
451         /**
452          * Get criteria element or false if not found
453          *
454          * @param       $criteriaKey    The requested criteria key
455          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
456          * @return      $value                  Whether the value of the critera or false
457          * @throws      InvalidArgumentException        If a parameter is not valid
458          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
459          */
460         public function getCriteriaElemnent (string $criteriaKey, string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
461                 // Check parameter
462                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaKey, $criteriaType));
463                 if (empty($criteriaKey)) {
464                         // Throw IAE
465                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
466                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
467                         // Throw it again
468                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
469                 } elseif (empty($criteriaType)) {
470                         // Throw it again
471                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
472                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
473                         // Throw it again
474                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
475                 }
476
477                 // Convert dashes to underscore
478                 $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
479
480                 // Default is not found
481                 $value = false;
482
483                 // Is the criteria there?
484                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteria()=%d', strtoupper($criteriaType), $criteriaKey, $this->countGenericArrayGroup('criteria', $criteriaType)));
485                 if ($this->isKeySet($criteriaType, $criteriaKey)) {
486                         // Then use it
487                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->getGenericArrayElement(criteria,%s,entries,%s) ...', strtoupper($criteriaType), $criteriaType, $criteriaKey));
488                         $value = $this->getGenericArrayElement('criteria', $criteriaType, 'entries', $criteriaKey);
489                 }
490
491                 // Return the value
492                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: value[]=%s - EXIT!', strtoupper($criteriaType), gettype($value)));
493                 return $value;
494         }
495
496         /**
497          * Get criteria element or false if not found for 'choice' type
498          *
499          * @param       $criteriaKey    The requested criteria key
500          * @return      $value                  Whether the value of the critera or false
501          * @throws      InvalidArgumentException        If a parameter is not valid
502          */
503         public function getCriteriaChoiceElemnent (string $criteriaKey) {
504                 // Check parameter
505                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s - CALLED!', $criteriaKey));
506                 if (empty($criteriaKey)) {
507                         // Throw IAE
508                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
509                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
510                         // Throw it again
511                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
512                 }
513
514                 // Invoke inner method
515                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->getCriteriaElemnent(%s,%s) ...', $criteriaKey, Criteria::CRITERIA_TYPE_CHOICE));
516                 return $this->getCriteriaElemnent($criteriaKey, Criteria::CRITERIA_TYPE_CHOICE);
517         }
518
519         /**
520          * Get criteria element or false if not found for 'exclude' type
521          *
522          * @param       $criteriaKey    The requested criteria key
523          * @return      $value                  Whether the value of the critera or false
524          * @throws      InvalidArgumentException        If a parameter is not valid
525          */
526         public function getCriteriaExcludeElemnent (string $criteriaKey) {
527                 // Check parameter
528                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: criteriaKey=%s - CALLED!', $criteriaKey));
529                 if (empty($criteriaKey)) {
530                         // Throw IAE
531                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
532                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
533                         // Throw it again
534                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
535                 }
536
537                 // Invoke inner method
538                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->getCriteriaElemnent(%s,%s) ...', $criteriaKey, Criteria::CRITERIA_TYPE_EXCLUDE));
539                 return $this->getCriteriaElemnent($criteriaKey, Criteria::CRITERIA_TYPE_EXCLUDE);
540         }
541
542         /**
543          * Checks whether given array entry matches
544          *
545          * @param       $entryArray             Array with the entries to find
546          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
547          * @return      $matches                Whether the entry matches or not
548          * @throws      InvalidArgumentException        If a parameter is not valid
549          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
550          */
551         public function ifEntryMatches (array $entryArray, string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
552                 // Check parameters
553                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: entryArray()=%d,criteriaType=%s - CALLED!', strtoupper($criteriaType), count($entryArray), $criteriaType));
554                 if (count($entryArray) == 0) {
555                         // Throw IAE
556                         throw new InvalidArgumentException('entryArray cannot be an empty array');
557                 } elseif (empty($criteriaType)) {
558                         // Throw it again
559                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
560                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
561                         // Throw it again
562                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
563                 }
564
565                 // First nothing matches and nothing is counted
566                 $matches = false;
567                 $counted = 0;
568
569                 // Walk through all entries
570                 foreach ($entryArray as $key => $entry) {
571                         // Make sure no 'my-' or 'my_' passes this point
572                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: key=%s,entry[%s]=%s', strtoupper($criteriaType), $key, gettype($entry), $entry));
573                         if ((strpos($key, 'my-') !== false) || (strpos($key, 'my_') !== false)) {
574                                 // Throw it again
575                                 throw new InvalidArgumentException(sprintf('key=%s has illegal prefix "my"', $key));
576                         }
577
578                         // Convert dashes to underscore
579                         $key = StringUtils::convertDashesToUnderscores($key);
580
581                         // Then walk through all search criteria
582                         foreach ($this->getGenericArrayKey('criteria', $criteriaType, 'entries') as $criteriaKey => $criteriaValue) {
583                                 // Make sure no 'my-' or 'my_' passes this point
584                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaValue[%s]=%s', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaValue));
585                                 if ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
586                                         // Throw it again
587                                         throw new UnexpectedValueException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
588                                 }
589
590                                 // Convert dashes to underscore
591                                 $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
592
593                                 // Is the element found and does it match?
594                                 if (($key == $criteriaKey) && ($criteriaValue == $entry)) {
595                                         // Then count this one up
596                                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: MATCHES!', strtoupper($criteriaType)));
597                                         $counted++;
598                                 }
599                         }
600                 }
601
602                 // Now check if expected criteria counts match
603                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: counted=%d', strtoupper($criteriaType), $counted));
604                 $matches = ($counted == $this->countGenericArrayGroup('criteria', $criteriaType));
605
606                 // Return the result
607                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: matches=%d - EXIT!', strtoupper($criteriaType), intval($matches)));
608                 return $matches;
609         }
610
611         /**
612          * Checks whether given array 'choice' entry matches
613          *
614          * @param       $entryArray             Array with the entries to find
615          * @return      $matches                Whether the entry matches or not
616          * @throws      InvalidArgumentException        If a parameter is not valid
617          */
618         public function ifChoiceMatches (array $entryArray) {
619                 // Check parameter
620                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: entryArray()=%d - CALLED!', count($entryArray)));
621                 if (count($entryArray) == 0) {
622                         // Throw IAE
623                         throw new InvalidArgumentException('entryArray cannot be an empty array');
624                 }
625
626                 // Invoke inner method
627                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->ifEntryMatches(%d,%s) ...', count($entryArray), Criteria::CRITERIA_TYPE_CHOICE));
628                 return $this->ifEntryMatches($entryArray, Criteria::CRITERIA_TYPE_CHOICE);
629         }
630
631         /**
632          * Checks whether given array 'exclude' entry matches
633          *
634          * @param       $entryArray             Array with the entries to find
635          * @return      $matches                Whether the entry matches or not
636          * @throws      InvalidArgumentException        If a parameter is not valid
637          */
638         public function ifExcludeMatches (array $entryArray) {
639                 // Check parameter
640                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: entryArray()=%d - CALLED!', count($entryArray)));
641                 if (count($entryArray) == 0) {
642                         // Throw IAE
643                         throw new InvalidArgumentException('entryArray cannot be an empty array');
644                 }
645
646                 // Invoke inner method
647                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->ifEntryMatches(%d,%s) ...', count($entryArray), Criteria::CRITERIA_TYPE_EXCLUDE));
648                 return $this->ifEntryMatches($entryArray, Criteria::CRITERIA_TYPE_EXCLUDE);
649         }
650
651         /**
652          * "Getter" for a cache key
653          *
654          * @param       $onlyKeys       Only use these keys for a cache key
655          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
656          * @return      $cacheKey       The key suitable for the cache system
657          * @throws      InvalidArgumentException        If a parameter is not valid
658          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
659          * @throws      BadMethodCallException  If this method is invoked before $criteriaType has been initialized
660          */
661         public function getCacheKey (array $onlyKeys = [], string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
662                 // Check parameters
663                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: onlyKeys()=%d,criteriaType=%s - CALLED!', strtoupper($criteriaType), count($onlyKeys), $criteriaType));
664                 if (empty($criteriaType)) {
665                         // Throw it again
666                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
667                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
668                         // Throw it again
669                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
670                 } elseif (!$this->isValidGenericArrayGroup('criteria', $criteriaType)) {
671                         // Not intialized yet
672                         throw new BadMethodCallException(sprintf('Method cannot be invoked before criteriaType=%s is initialized!', $criteriaType));
673                 }
674
675                 // Initialize the key
676                 $cacheKey = '';
677
678                 // Now walk through all criterias
679                 foreach ($this->getGenericArrayKey('criteria', $criteriaType, 'entries') as $criteriaKey => $criteriaValue) {
680                         // Make sure no 'my-' or 'my_' passes this point
681                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaValue[%s]=%s', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaValue));
682                         if ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
683                                 // Throw UAE
684                                 throw new UnexpectedValueException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
685                         } elseif (is_array($criteriaValue) || is_bool($criteriaValue) || is_object($criteriaValue) || is_resource($criteriaValue)) {
686                                 // Throw it again
687                                 throw new UnexpectedValueException(sprintf('criteriaValue[]=%s is not supported', gettype($criteriaValue)));
688                         }
689
690                         // Convert dashes to underscore
691                         $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
692
693                         // Is the value in array or is $onlyKeys empty?
694                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s', strtoupper($criteriaType), $criteriaKey));
695                         if ((isset($onlyKeys[$criteriaKey])) || (count($onlyKeys) == 0)) {
696                                 // Add the value URL encoded to avoid any trouble with special characters
697                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Adding criteriaKey=%s,criteriaValue[%s]=%s to cache key ...', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaValue));
698                                 $cacheKey .= sprintf('%s=%s;',
699                                         $criteriaKey,
700                                         urlencode($criteriaValue)
701                                 );
702                         }
703                 }
704
705                 // Remove last semicolon
706                 $cacheKey = substr($cacheKey, 0, -1);
707
708                 // Is the instance SearchCriteria?
709                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: cacheKey=%s,this=%s', strtoupper($criteriaType), $cacheKey, $this->__toString()));
710                 if ($this instanceof SearchCriteria) {
711                         // Check if 'limit' and 'skip' are in
712                         if (((isset($onlyKeys['limit'])) && (isset($onlyKeys['skip']))) || (count($onlyKeys) == 0)) {
713                                 // Add limit and skip values
714                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Adding this->limit=%d,this->skip=%d to cache key ...', strtoupper($criteriaType), $this->getLimit(), $this->getSkip()));
715                                 $cacheKey .= sprintf(';%%limit%%=%s;%%skip%%=%s',
716                                         $this->getLimit(),
717                                         $this->getSkip()
718                                 );
719                         }
720                 }
721
722                 // Return the cache key
723                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: cacheKey=%s - EXIT!', strtoupper($criteriaType), $cacheKey));
724                 return $cacheKey;
725         }
726
727         /**
728          * "Getter" for a cache key ('choice' type)
729          *
730          * @param       $onlyKeys       Only use these keys for a cache key
731          * @return      $cacheKey       The key suitable for the cache system
732          */
733         public function getCacheKeyChoice (array $onlyKeys = []) {
734                 // Trace message
735                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: onlyKeys()=%d - CALLED!', count($onlyKeys)));
736
737                 // Invoke inner method
738                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->getCacheKey(onlyKeys()=%d,%s) ...', count($onlyKeys),Criteria::CRITERIA_TYPE_CHOICE));
739                 return $this->getCacheKey($onlyKeys, Criteria::CRITERIA_TYPE_CHOICE);
740         }
741
742         /**
743          * "Getter" for a cache key ('exclude' type)
744          *
745          * @param       $onlyKeys       Only use these keys for a cache key
746          * @return      $cacheKey       The key suitable for the cache system
747          */
748         public function getCacheKeyExclude (array $onlyKeys = []) {
749                 // Trace message
750                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: onlyKeys()=%d - CALLED!', count($onlyKeys)));
751
752                 // Invoke inner method
753                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->getCacheKey(onlyKeys()=%d,%s) ...', count($onlyKeys),Criteria::CRITERIA_TYPE_EXCLUDE));
754                 return $this->getCacheKey($onlyKeys, Criteria::CRITERIA_TYPE_EXCLUDE);
755         }
756
757         /**
758          * Count 'choice' criteria, e.g. useful to find out if a database query
759          * has no limitation (search criteria).
760          *
761          * @return      $count  Count of all criteria entries
762          */
763         public final function countChoice () {
764                 // Trace message
765                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: CALLED!');
766                 return $this->count(Criteria::CRITERIA_TYPE_CHOICE);
767         }
768
769         /**
770          * Count 'exclude' criteria, e.g. useful to find out if a database query
771          * has no limitation (search criteria).
772          *
773          * @return      $count  Count of all criteria entries
774          */
775         public final function countExclude () {
776                 // Trace message
777                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: CALLED!');
778                 return $this->count(Criteria::CRITERIA_TYPE_EXCLUDE);
779         }
780
781 }