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