diff --git a/README.md b/README.md index a746052..041739c 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,57 @@ object(RapidWeb\Search\SearchResults)#731 (5) { float(0.33661985397339) } ``` +### Using operators in conditions + +Basic extra search conditions + +Operators that can be used: **==**, **!=**, **<**, **>**, **<=**, **>=**, **in**, **!in**, **email**, **!email** +```php + // Operators can be used when filter Enabled + ->enableFilter() +``` +Unique Key/FieldName can only be used ones! +```php + // Row with id = 50 will be selected, because it is the last (id) condition + ->enableFilter() + ->setConditions([ + 'product_live' => 1, + 'id:==' => 16, + 'id:==' => 50 + ]); +```` +Some condition examples +```php + // count larger than 500 + // created (timestamp) smaller or equal + ->enableFilter() + ->setConditions([ + 'product_live' => 1, + 'count:>' => 500, + 'created:<=' => 1581828542 + ]); + + // parent_id 17, 16 or 19 + ->enableFilter() + ->setConditions([ + 'product_live' => 1, + 'parent_id:in' => '17,16,9' + ]); + + // parent_id not 35, 45 or 89 + ->enableFilter() + ->setConditions([ + 'product_live' => 1, + 'id:!in' => '34,45,89' + ]); + + // Select invalid emailaddresses + ->enableFilter() + ->setConditions([ + 'emailaddress:!email' => '' + ]); +```` + ### Caching Source Data diff --git a/src/Search.php b/src/Search.php index 6407920..e1cc3cc 100644 --- a/src/Search.php +++ b/src/Search.php @@ -12,6 +12,9 @@ class Search { + use SearchExtendConditions; + + private $useFilter = false; private $pdo; private $table; private $primaryKey; @@ -45,6 +48,11 @@ public function setConditions(array $conditions = []) { return $this; } + public function enableFilter() { + $this->useFilter = true; + return $this; + } + public function setCache(CacheItemPoolInterface $cacheItemPool, $cacheExpiresAfter = 60*60*24) { $this->cacheItemPool = $cacheItemPool; $this->cacheExpiresAfter = $cacheExpiresAfter; @@ -68,9 +76,16 @@ private function sanityCheck() { $this->fields[] = $this->primaryKey; } - foreach($this->conditions as $fieldName => $value) { - if (!in_array($fieldName, $this->fields)) { - $this->fields[] = $fieldName; + if($this->useFilter && method_exists($this, 'setFields')) { + // Call method from SearchFilter Trait + $this->setFields(); + } + else { + // Handling without SearchFilter + foreach($this->conditions as $fieldName => $value) { + if (!in_array($fieldName, $this->fields)) { + $this->fields[] = $fieldName; + } } } } @@ -120,12 +135,21 @@ public function query($term, $limit = PHP_INT_MAX) { $migrator->setDataRowManipulator(function($dataRow) use ($terms, &$results) { - foreach($this->conditions as $fieldName => $value) { - $dataItem = $dataRow->getDataItemByFieldName($fieldName); - if ($dataItem->value != $value) { + if($this->useFilter && method_exists($this, 'setDataItems')) { + // Call method from SearchFilter Trait + if (!$this->setDataItems($dataRow)) { return; } } + else { + // Handling without SearchFilter + foreach($this->conditions as $fieldName => $value) { + $dataItem = $dataRow->getDataItemByFieldName($fieldName); + if ($dataItem->value != $value) { + return; + } + } + } $dataItems = $dataRow->getDataItems(); diff --git a/src/SearchExtendConditions.php b/src/SearchExtendConditions.php new file mode 100644 index 0000000..45da0d1 --- /dev/null +++ b/src/SearchExtendConditions.php @@ -0,0 +1,118 @@ +conditions as $fieldName => $value) { + // Undo fieldname from operators + $fieldName = $this->splitOperator($fieldName); + // No doubles + if (!in_array($fieldName, $this->fields)) { + $this->fields[] = $fieldName; + } + } + } + + /** + * Walk true conditions for each dataRow + * @param $dataRow + * @return bool + */ + public function setDataItems(&$dataRow):bool { + $methods = get_class_methods($this); + $methods = array_filter($methods, function($method) { + return preg_match("/^__.*Filter$/",$method); + }); + + $result = true; + foreach($this->conditions as $fieldName => $value) { + // Split fieldname and operator + list($fieldName, $operator) = $this->splitOperator($fieldName, true); + $dataItem = $dataRow->getDataItemByFieldName($fieldName); + + foreach ($methods as $filterMethod) { + if(method_exists($this, $filterMethod)) { + $result = $this->$filterMethod($dataItem, $operator, $value) ? $result : false; + } + } + } + return $result; + } + + /** + * When there is an operator in the Fieldname, split + * return only fieldname or both + * + * @param string $fieldName + * @param bool $return + * @return array|string + */ + private function splitOperator(string $fieldName, bool $return = false): array | string { + $operator = "=="; + if(preg_match("/:/",$fieldName)) { + // split fieldname and operator + list($fieldName, $operator) = preg_split("/:/", $fieldName); + } + + if(!$return) return $fieldName; + return [$fieldName,$operator]; + } + + /** + * match emailadres + * @param \RapidWeb\uxdm\Objects\DataItem $dataItem + * @param string $operator + * @param mixed $value + * @return bool + */ + private function __emailFilter(\RapidWeb\uxdm\Objects\DataItem $dataItem, string $operator, mixed $value):bool { + $result = true; + if(preg_match("/email/", $operator)) { + if ($operator == '!email' && filter_var($value, FILTER_VALIDATE_EMAIL)) { + $result = false; + } elseif ($operator == 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) { + $result = false; + } + } + return $result; + } + + /** + * in or not in list + * @param \RapidWeb\uxdm\Objects\DataItem $dataItem + * @param string $operator + * @param mixed $value + * @return bool + */ + private function __inFilter(\RapidWeb\uxdm\Objects\DataItem $dataItem, string $operator, mixed $value):bool { + $result = true; + if(preg_match("/in/", $operator)) { + if ($operator == '!in' && in_array($dataItem->value, explode(",", $value))) { + $result = false; + } elseif ($operator == 'in' && !in_array($dataItem->value, explode(",", $value))) { + $result = false; + } + } + return $result; + } + + /** + * value compare + * @param \RapidWeb\uxdm\Objects\DataItem $dataItem + * @param string $operator + * @param mixed $value + * @return bool + */ + private function __comparisonFilter(\RapidWeb\uxdm\Objects\DataItem $dataItem, string $operator, mixed $value):bool { + if(preg_match("/(<|>|==|\!=|<=|>=)/", $operator)) { + return eval('return (' . $dataItem->value . $operator . $value . ');'); + } + return true; + } +} \ No newline at end of file