Skip to content

Commit

Permalink
Improve/cleanup backend block search functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Ioannis committed Mar 12, 2024
1 parent 6fc7615 commit d64f796
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 36 deletions.
21 changes: 9 additions & 12 deletions app/src/Controller/StandardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -572,40 +572,37 @@ public function index() {

// AutoViewVarsTrait
$this->populateAutoViewVars();


$query = $table->find($this->paginate['finder'] ?? 'all');
if(!empty($link->attr)) {
// If a link attribute is defined but no value is provided, then query
// where the link attribute is NULL
// "all" is the default finder. But since we are utilizing the paginator here, we will check the configuration
// for any custom finder.
$query = $table->find(
$this->paginate['finder'] ?? "all"
)->where([$table->getAlias().'.'.$link->attr => $link->value]);
} else {
$query = $table->find($this->paginate['finder'] ?? "all");
$query = $query->where([$table->getAlias().'.'.$link->attr => $link->value]);
}

// QueryModificationTrait
if(method_exists($table, "getIndexContains")
if(method_exists($table, 'getIndexContains')
&& $table->getIndexContains()) {
$query->contain($table->getIndexContains());
}

// SearchFilterTrait
if(method_exists($table, "getSearchableAttributes")) {
if(method_exists($table, 'getSearchableAttributes')) {
$searchableAttributes = $table->getSearchableAttributes($this->name, $this->viewBuilder()->getVar('vv_tz'));

if(!empty($searchableAttributes)) {
// Here we iterate over the attributes, and we add a new where clause for each one
foreach($searchableAttributes as $attribute => $options) {
if(!empty($this->request->getQuery($attribute))) {
$query = $table->whereFilter($query, $attribute, $this->request->getQuery($attribute));
} elseif (!empty($this->request->getQuery($attribute . "_starts_at"))
|| !empty($this->request->getQuery($attribute . "_ends_at"))) {
} elseif (!empty($this->request->getQuery($attribute . '_starts_at'))
|| !empty($this->request->getQuery($attribute . '_ends_at'))) {
$search_date = [];
// We allow empty for dates since we might refer to infinity (from whenever or to always)
$search_date[] = $this->request->getQuery($attribute . "_starts_at") ?? "";
$search_date[] = $this->request->getQuery($attribute . "_ends_at") ?? "";
$search_date[] = $this->request->getQuery($attribute . '_starts_at') ?? '';
$search_date[] = $this->request->getQuery($attribute . '_ends_at') ?? '';
$query = $table->whereFilter($query, $attribute, $search_date);
}
}
Expand Down
49 changes: 25 additions & 24 deletions app/src/Lib/Traits/SearchFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

namespace App\Lib\Traits;

use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
use Cake\Utility\Inflector;
use Cake\I18n\FrozenTime;

Expand Down Expand Up @@ -136,15 +138,15 @@ public function setFilterConfig(array $filterConfig): void {
/**
* Build a query where() clause for the configured attribute.
*
* @param \Cake\ORM\Query $query Cake ORM Query object
* @param Query $query Cake ORM Query object
* @param string $attribute Attribute to filter on (database name)
* @param string|array $q Value to filter on
*
* @return \Cake\ORM\Query Cake ORM Query object
* @return Query Cake ORM Query object
* @since COmanage Registry v5.0.0
*/

public function whereFilter(\Cake\ORM\Query $query, string $attribute, string|array $q): object {
public function whereFilter(Query $query, string $attribute, string|array $q): object {
// not a permitted attribute
if(empty($this->searchFilters[$attribute])) {
return $query;
Expand Down Expand Up @@ -175,48 +177,47 @@ public function whereFilter(\Cake\ORM\Query $query, string $attribute, string|ar
$sub = false;
// Primitive types
$search_types = ['integer', 'boolean'];
if( $this->searchFilters[$attribute]['type'] == "string") {
$search = "%" . $search . "%";
if( $this->searchFilters[$attribute]['type'] === 'string') {
$search = '%' . $search . '%';
$sub = true;
// Search type
} elseif(in_array($this->searchFilters[$attribute]['type'], $search_types, true)) {
return $query->where([$attributeWithModelPrefix => $search]);
// Date
} elseif($this->searchFilters[$attribute]['type'] == "date") {
} elseif($this->searchFilters[$attribute]['type'] === 'date') {
// Parse the date string with FrozenTime to improve error handling
return $query->where([$attributeWithModelPrefix => FrozenTime::parseDate($search, 'y-M-d')]);
// Timestamp
} elseif( $this->searchFilters[$attribute]['type'] == "timestamp") {
} elseif( $this->searchFilters[$attribute]['type'] === 'timestamp') {
// Date between dates
if(!empty($search[0])
&& !empty($search[1])) {
return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search) {
return $exp->between($attributeWithModelPrefix, "'" . $search[0] . "'", "'" . $search[1] . "'");
});
// The starts at is non-empty. So the data should be greater than the starts_at date
return $query->where(fn(QueryExpression $exp, Query $query) => $exp->between($attributeWithModelPrefix, "'" . $search[0] . "'", "'" . $search[1] . "'"));
// The starts_at is non-empty. So the data should be greater than the starts_at date
} elseif(!empty($search[0])
&& empty($search[1])) {
return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search) {
return $exp->gte("'" . FrozenTime::parse($search[0]) . "'", $attributeWithModelPrefix);
});
// The ends at is non-empty. So the data should be less than the ends at date
return $query->where(fn(QueryExpression $exp, Query $query) => $exp->gte("'" . FrozenTime::parse($search[0]) . "'", $attributeWithModelPrefix));
// The ends_at is non-empty. So the data should be less than the ends_at date
} elseif(!empty($search[1])
&& empty($search[0])) {
return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search) {
return $exp->lte("'" . FrozenTime::parse($search[1]) . "'", $attributeWithModelPrefix);
});
return $query->where(fn(QueryExpression $exp, Query $query) => $exp->lte("'" . FrozenTime::parse($search[1]) . "'", $attributeWithModelPrefix));
} else {
// We return everything
return $query;
}

}

// Use the `lower` function to apply uniformity for the search globally
$lower = $query->func()->lower([$attributeWithModelPrefix => 'identifier']);

// This is the case of the filtering block. We are `and`-ing the conditions
// The like function applies to all string searches
// The eq function applies to everything else
$conditionsCallback = static fn(QueryExpression $exp, Query $query) =>
($sub) ? $exp->like($lower, strtolower($search))
: $exp->eq($lower, strtolower($search));

// String values
return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search, $sub) {
$lower = $query->func()->lower([$attributeWithModelPrefix => 'identifier']);
return ($sub) ? $exp->like($lower, strtolower($search))
: $exp->eq($lower, strtolower($search));
});
return $query->where($conditionsCallback);
}
}

0 comments on commit d64f796

Please sign in to comment.