]> 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$criteriaValue,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                 // Append it
299                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: Invoking this->appendStringToGenericArrayElement(criteria,%s,entries,%s,criteriaValue[]=%s) ...', strtoupper($criteriaType), $criteriaType, $criteriaKey, gettype($criteriaValue)));
300                 $this->appendStringToGenericArrayElement('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->setStringGenericArrayElement(criteria,%s,entries,%s,criteriaValue[]=%s) ...', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue)));
342                 $this->setStringGenericArrayElement('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,configEntry=%s,criteriaType=%s - CALLED!', strtoupper($criteriaType), $criteriaKey, $configEntry, $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('%s-CRITERIA: criteriaKey=%s - CALLED!', strtoupper($criteriaType), $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                 return $this->getCriteriaElemnent($criteriaKey, Criteria::CRITERIA_TYPE_CHOICE);
516         }
517
518         /**
519          * Get criteria element or false if not found for 'exclude' type
520          *
521          * @param       $criteriaKey    The requested criteria key
522          * @return      $value                  Whether the value of the critera or false
523          * @throws      InvalidArgumentException        If a parameter is not valid
524          */
525         public function getCriteriaExcludeElemnent (string $criteriaKey) {
526                 // Check parameter
527                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s - CALLED!', strtoupper($criteriaType), $criteriaKey));
528                 if (empty($criteriaKey)) {
529                         // Throw IAE
530                         throw new InvalidArgumentException('Parameter "criteriaKey" is empty');
531                 } elseif ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
532                         // Throw it again
533                         throw new InvalidArgumentException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
534                 }
535
536                 // Invoke inner method
537                 return $this->getCriteriaElemnent($criteriaKey, Criteria::CRITERIA_TYPE_EXCLUDE);
538         }
539
540         /**
541          * Checks whether given array entry matches
542          *
543          * @param       $entryArray             Array with the entries to find
544          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
545          * @return      $matches                Whether the entry matches or not
546          * @throws      InvalidArgumentException        If a parameter is not valid
547          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
548          */
549         public function ifEntryMatches (array $entryArray, string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
550                 // Check parameters
551                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: entryArray()=%d,criteriaType=%s - CALLED!', strtoupper($criteriaType), count($entryArray), $criteriaType));
552                 if (count($entryArray) == 0) {
553                         // Throw IAE
554                         throw new InvalidArgumentException('entryArray cannot be an empty array');
555                 } elseif (empty($criteriaType)) {
556                         // Throw it again
557                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
558                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
559                         // Throw it again
560                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
561                 }
562
563                 // First nothing matches and nothing is counted
564                 $matches = false;
565                 $counted = 0;
566
567                 // Walk through all entries
568                 foreach ($entryArray as $key => $entry) {
569                         // Make sure no 'my-' or 'my_' passes this point
570                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: key=%s,entry[%s]=%s', strtoupper($criteriaType), $key, gettype($entry), $entry));
571                         if ((strpos($key, 'my-') !== false) || (strpos($key, 'my_') !== false)) {
572                                 // Throw it again
573                                 throw new InvalidArgumentException(sprintf('key=%s has illegal prefix "my"', $key));
574                         }
575
576                         // Convert dashes to underscore
577                         $key = StringUtils::convertDashesToUnderscores($key);
578
579                         // Then walk through all search criteria
580                         foreach ($this->getGenericArrayKey('criteria', $criteriaType, 'entries') as $criteriaKey => $criteriaValue) {
581                                 // Make sure no 'my-' or 'my_' passes this point
582                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaValue[%s]=%s', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaValue));
583                                 if ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
584                                         // Throw it again
585                                         throw new UnexpectedValueException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
586                                 }
587
588                                 // Convert dashes to underscore
589                                 $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
590
591                                 // Is the element found and does it match?
592                                 if (($key == $criteriaKey) && ($criteriaValue == $entry)) {
593                                         // Then count this one up
594                                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: MATCHES!', strtoupper($criteriaType)));
595                                         $counted++;
596                                 }
597                         }
598                 }
599
600                 // Now check if expected criteria counts match
601                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: counted=%d', strtoupper($criteriaType), $counted));
602                 $matches = ($counted == $this->countGenericArrayGroup('criteria', $criteriaType));
603
604                 // Return the result
605                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: matches=%d - EXIT!', strtoupper($criteriaType), intval($matches)));
606                 return $matches;
607         }
608
609         /**
610          * Checks whether given array 'choice' entry matches
611          *
612          * @param       $entryArray             Array with the entries to find
613          * @return      $matches                Whether the entry matches or not
614          * @throws      InvalidArgumentException        If a parameter is not valid
615          */
616         public function ifChoiceMatches (array $entryArray) {
617                 // Check parameter
618                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: entryArray()=%d - CALLED!', count($entryArray)));
619                 if (count($entryArray) == 0) {
620                         // Throw IAE
621                         throw new InvalidArgumentException('entryArray cannot be an empty array');
622                 }
623
624                 // Invoke inner method
625                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->ifEntryMatches(%d,%s) ...', count($entryArray), Criteria::CRITERIA_TYPE_CHOICE));
626                 return $this->ifEntryMatches($entryArray, Criteria::CRITERIA_TYPE_CHOICE);
627         }
628
629         /**
630          * Checks whether given array 'exclude' entry matches
631          *
632          * @param       $entryArray             Array with the entries to find
633          * @return      $matches                Whether the entry matches or not
634          * @throws      InvalidArgumentException        If a parameter is not valid
635          */
636         public function ifExcludeMatches (array $entryArray) {
637                 // Check parameter
638                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: entryArray()=%d - CALLED!', count($entryArray)));
639                 if (count($entryArray) == 0) {
640                         // Throw IAE
641                         throw new InvalidArgumentException('entryArray cannot be an empty array');
642                 }
643
644                 // Invoke inner method
645                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->ifEntryMatches(%d,%s) ...', count($entryArray), Criteria::CRITERIA_TYPE_EXCLUDE));
646                 return $this->ifEntryMatches($entryArray, Criteria::CRITERIA_TYPE_EXCLUDE);
647         }
648
649         /**
650          * "Getter" for a cache key
651          *
652          * @param       $onlyKeys       Only use these keys for a cache key
653          * @param       $criteriaType   Type of this criteria, can be one of 'default' (default), 'choice' or 'exclude'
654          * @return      $cacheKey       The key suitable for the cache system
655          * @throws      InvalidArgumentException        If a parameter is not valid
656          * @throws      UnexpectedValueException        If a parameter contains an unexpected/unsupported value
657          * @throws      BadMethodCallException  If this method is invoked before $criteriaType has been initialized
658          */
659         public function getCacheKey (array $onlyKeys = [], string $criteriaType = Criteria::CRITERIA_TYPE_DEFAULT) {
660                 // Check parameters
661                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: onlyKeys()=%d,criteriaType=%s - CALLED!', strtoupper($criteriaType), count($onlyKeys), $criteriaType));
662                 if (empty($criteriaType)) {
663                         // Throw it again
664                         throw new InvalidArgumentException('Parameter "criteriaType" is empty');
665                 } elseif (!in_array($criteriaType, self::$CRITERIA_TYPES)) {
666                         // Throw it again
667                         throw new UnexpectedValueException(sprintf('criteriaType=%s is not supported', $criteriaType));
668                 } elseif (!$this->isValidGenericArrayGroup('criteria', $criteriaType)) {
669                         // Not intialized yet
670                         throw new BadMethodCallException(sprintf('Method cannot be invoked before criteriaType=%s is initialized!', $criteriaType));
671                 }
672
673                 // Initialize the key
674                 $cacheKey = '';
675
676                 // Now walk through all criterias
677                 foreach ($this->getGenericArrayKey('criteria', $criteriaType, 'entries') as $criteriaKey => $criteriaValue) {
678                         // Make sure no 'my-' or 'my_' passes this point
679                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s,criteriaValue[%s]=%s', strtoupper($criteriaType), $criteriaKey, gettype($criteriaValue), $criteriaValue));
680                         if ((strpos($criteriaKey, 'my-') !== false) || (strpos($criteriaKey, 'my_') !== false)) {
681                                 // Throw UAE
682                                 throw new UnexpectedValueException(sprintf('criteriaKey=%s has illegal prefix "my"', $criteriaKey));
683                         } elseif (is_array($criteriaValue) || is_bool($criteriaValue) || is_object($criteriaValue) || is_resource($criteriaValue)) {
684                                 // Throw it again
685                                 throw new UnexpectedValueException(sprintf('criteriaValue[]=%s is not supported', gettype($criteriaValue)));
686                         }
687
688                         // Convert dashes to underscore
689                         $criteriaKey = StringUtils::convertDashesToUnderscores($criteriaKey);
690
691                         // Is the value in array or is $onlyKeys empty?
692                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: criteriaKey=%s', strtoupper($criteriaType), $criteriaKey));
693                         if ((isset($onlyKeys[$criteriaKey])) || (count($onlyKeys) == 0)) {
694                                 // Add the value URL encoded to avoid any trouble with special characters
695                                 /* 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));
696                                 $cacheKey .= sprintf('%s=%s;',
697                                         $criteriaKey,
698                                         urlencode($criteriaValue)
699                                 );
700                         }
701                 }
702
703                 // Remove last semicolon
704                 $cacheKey = substr($cacheKey, 0, -1);
705
706                 // Is the instance SearchCriteria?
707                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: cacheKey=%s,this=%s', strtoupper($criteriaType), $cacheKey, $this->__toString()));
708                 if ($this instanceof SearchCriteria) {
709                         // Check if 'limit' and 'skip' are in
710                         if (((isset($onlyKeys['limit'])) && (isset($onlyKeys['skip']))) || (count($onlyKeys) == 0)) {
711                                 // Add limit and skip values
712                                 /* 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()));
713                                 $cacheKey .= sprintf(';%%limit%%=%s;%%skip%%=%s',
714                                         $this->getLimit(),
715                                         $this->getSkip()
716                                 );
717                         }
718                 }
719
720                 // Return the cache key
721                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-CRITERIA: cacheKey=%s - EXIT!', strtoupper($criteriaType), $cacheKey));
722                 return $cacheKey;
723         }
724
725         /**
726          * "Getter" for a cache key ('choice' type)
727          *
728          * @param       $onlyKeys       Only use these keys for a cache key
729          * @return      $cacheKey       The key suitable for the cache system
730          */
731         public function getCacheKeyChoice (array $onlyKeys = []) {
732                 // Trace message
733                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: onlyKeys()=%d - CALLED!', count($onlyKeys)));
734
735                 // Invoke inner method
736                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->getCacheKey(onlyKeys()=%d,%s) ...', count($onlyKeys),Criteria::CRITERIA_TYPE_CHOICE));
737                 return $this->getCacheKey($onlyKeys, Criteria::CRITERIA_TYPE_CHOICE);
738         }
739
740         /**
741          * "Getter" for a cache key ('exclude' type)
742          *
743          * @param       $onlyKeys       Only use these keys for a cache key
744          * @return      $cacheKey       The key suitable for the cache system
745          */
746         public function getCacheKeyExclude (array $onlyKeys = []) {
747                 // Trace message
748                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: onlyKeys()=%d - CALLED!', count($onlyKeys)));
749
750                 // Invoke inner method
751                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-CRITERIA: Invoking this->getCacheKey(onlyKeys()=%d,%s) ...', count($onlyKeys),Criteria::CRITERIA_TYPE_EXCLUDE));
752                 return $this->getCacheKey($onlyKeys, Criteria::CRITERIA_TYPE_EXCLUDE);
753         }
754
755         /**
756          * Count 'choice' criteria, e.g. useful to find out if a database query
757          * has no limitation (search criteria).
758          *
759          * @return      $count  Count of all criteria entries
760          */
761         public final function countChoice () {
762                 // Trace message
763                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: CALLED!');
764                 return $this->count(Criteria::CRITERIA_TYPE_CHOICE);
765         }
766
767         /**
768          * Count 'exclude' criteria, e.g. useful to find out if a database query
769          * has no limitation (search criteria).
770          *
771          * @return      $count  Count of all criteria entries
772          */
773         public final function countExclude () {
774                 // Trace message
775                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-CRITERIA: CALLED!');
776                 return $this->count(Criteria::CRITERIA_TYPE_EXCLUDE);
777         }
778
779 }