]> git.mxchange.org Git - core.git/blob - framework/main/classes/criteria/search/class_SearchCriteria.php
197fc6f19e394573042da97b83c3271a49349f9f
[core.git] / framework / main / classes / criteria / search / class_SearchCriteria.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Criteria\Search;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Criteria\BaseCriteria;
8 use Org\Mxchange\CoreFramework\Criteria\Local\LocalSearchCriteria;
9 use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
10
11 // Import SPL stuff
12 use \InvalidArgumentException;
13
14 /**
15  * Search criteria for e.g. searching in databases. Do not use this class if
16  * you are looking for a ship or company, or what ever. Instead use this class
17  * for looking in storages like the database.
18  *
19  * @author              Roland Haeder <webmaster@shipsimu.org>
20  * @version             0.0.0
21  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 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 class SearchCriteria extends BaseCriteria implements LocalSearchCriteria {
39         /**
40          * Criteria to handle
41          */
42         private $criteria = [];
43
44         /**
45          * Limitation for the search
46          */
47         private $limit = 0;
48
49         /**
50          * Skip these entries before using them
51          */
52         private $skip = 0;
53
54         /**
55          * Protected constructor
56          *
57          * @return      void
58          */
59         private function __construct () {
60                 // Call parent constructor
61                 parent::__construct(__CLASS__);
62         }
63
64         /**
65          * Create an instance of this class
66          *
67          * @return      $criteriaInstance       An instance of this criteria
68          */
69         public static final function createSearchCriteria () {
70                 // Get a new instance
71                 $criteriaInstance = new SearchCriteria();
72
73                 // Return this instance
74                 return $criteriaInstance;
75         }
76
77         /**
78          * Setter for limit
79          *
80          * @param       $limit  Search limit
81          * @return      void
82          * @todo        Find a nice casting here. (int) allows until and including 32766.
83          */
84         public final function setLimit (int $limit) {
85                 $this->limit = $limit;
86         }
87
88         /**
89          * "Setter" for limit from a configuration entry
90          *
91          * @param       $configEntry    The configuration entry which hold a number as limit
92          * @return      void
93          */
94         public final function setConfiguredLimit (string $configEntry) {
95                 // Get the limit from config entry and set it
96                 $limit = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($configEntry);
97                 $this->setLimit($limit);
98         }
99
100         /**
101          * Getter for limit
102          *
103          * @return      $limit  Search limit
104          */
105         public final function getLimit () {
106                 return $this->limit;
107         }
108
109         /**
110          * Setter for skip
111          *
112          * @param       $skip   Search skip
113          * @return      void
114          * @todo        Find a nice casting here. (int) allows until and including 32766.
115          */
116         public final function setSkip (int $skip) {
117                 $this->skip = $skip;
118         }
119
120         /**
121          * Getter for skip
122          *
123          * @return      $skip   Search skip
124          */
125         public final function getSkip () {
126                 return $this->skip;
127         }
128
129         /**
130          * Checks whether the given key/value pair is matching with 'default' and one of 'choice' and
131          * never with in 'exclude'.
132          *
133          * @param       $key                    Key element to check
134          * @param       $value                  Value to check
135          * @param       $separator              Separator for "exploding" $value (default: ',')
136          * @return      $isMatching             Whether the key/value is matching or excluded
137          * @throws      InvalidArgumentException        If a parameter is invalid
138          */
139         public function isCriteriaMatching (string $key, $value, string $separator = ',') {
140                 // $key/$value cannot be array/NULL/bool, value can be NULL but then NULL must be loocked for
141                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('SEARCH-CRITERIA: key=%s,value[]=%s,separator=%s - CALLED!', $key, gettype($value), $separator));
142                 if (empty($key)) {
143                         // Throw IAE
144                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
145                 } elseif (is_array($value) || is_bool($value) || is_bool($value) || is_object($value) || is_resource($value)) {
146                         // Throw it again
147                         throw new InvalidArgumentException(sprintf('value[]=%s is not supported/valid', gettype($value)));
148                 } elseif (empty($separator)) {
149                         // Throw IAE
150                         throw new InvalidArgumentException('Parameter "separator" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
151                 }
152
153                 // "Explode" value
154                 $valueArray = explode($separator, $value);
155
156                 // Get 'default' search value
157                 $searchDefault = $this->getCriteriaElemnent($key);
158
159                 // 'default' check
160                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaElement(' . $key . ')[' . gettype($searchDefault) . ']=' . $searchDefault);
161                 $isMatching = (
162                         (
163                                 (
164                                         ($searchDefault !== false) &&
165                                         ($searchDefault == $value)
166                                 ) || (
167                                         is_null($searchDefault) &&
168                                         is_null($value)
169                                 )
170                         ) || (
171                                 $searchDefault === false
172                         )
173                 );
174
175                 // Get 'choice' search value (can be NULL or $separator-separated string)
176                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaElement(' . $key . ')[' . gettype($searchDefault) . ']=' . $searchDefault . ',isMatching=' . intval($isMatching));
177                 $searchChoice = $this->getCriteriaChoiceElemnent($key);
178
179                 // May be false or array
180                 assert(($searchChoice === false) || (is_array($searchChoice)));
181
182                 // 'choice' check
183                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaChoiceElement(' . $key . ')[' . gettype($searchChoice) . ']=' . print_r($searchChoice, true));
184                 if ((is_array($searchChoice)) && (count($valueArray) == 1)) {
185                         // $value is a single-search value, so use in_[]
186                         $isMatching = ((($isMatching === true) || (($searchDefault === false) && (!is_null($value)))) && (in_array($value, $searchChoice)));
187
188                         // Debug message
189                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',value[' . gettype($value) . ']=' . $value . ',isMatching=' . intval($isMatching) . ' - SINGLE-MATCH');
190                 } elseif ((is_array($searchChoice)) && (count($valueArray) > 1)) {
191                         // Debug message
192                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',value[]=' . count($valueArray) . ',isMatching=' . intval($isMatching));
193
194                         // $value is choice-search value, so check all entries
195                         $isMatching = (($isMatching === true) || (($searchDefault === false) && (!is_null($value))));
196                         $idx = 0;
197                         foreach ($valueArray as $idx => $match) {
198                                 // Debug message
199                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: match=' . $match . ',count(searchChoice)=' . count($searchChoice));
200
201                                 // Is it found? (one is okay)
202                                 $isMatching = (($isMatching === true) && (in_array($match, $searchChoice)));
203
204                                 // Debug message
205                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: match=' . $match . ',isMatching=' . intval($isMatching));
206                         }
207
208                         // Debug message
209                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',value[]=' . count($valueArray) . ',idx=' . $idx . ',isMatching=' . intval($isMatching) . ' - CHOICE-MATCH');
210                 } else {
211                         // Choice-match is false
212                         // Debug message
213                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',value[' . gettype($value) . ']=' . $value . ',isMatching=' . intval($isMatching) . ' - false-MATCH');
214                 }
215
216                 // Get 'exclude' search value
217                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',isMatching=' . intval($isMatching));
218                 $searchExclude = $this->getCriteriaExcludeElemnent($key);
219
220                 // 'exclude' check
221                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: getCriteriaExcludeElement(' . $key . ')[' . gettype($searchExclude) . ']=' . $searchExclude);
222                 $isMatching = (
223                         (
224                                 (
225                                         $isMatching === true
226                                 ) && (
227                                         $searchExclude === false
228                                 )
229                         ) || (
230                                 (
231                                         (
232                                                 $isMatching === true
233                                         ) && (
234                                                 $searchExclude !== false
235                                         ) && (
236                                                 $searchExclude !== $value
237                                         )
238                                 )
239                         )
240                 );
241
242                 // Return result
243                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SEARCH-CRITERIA: key=' . $key . ',value[' . gettype($value) . ']=' . $value . ',isMatching=' . intval($isMatching) . ' - EXIT!');
244                 return $isMatching;
245         }
246
247 }