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