File: /home/timetracker.panomity.com/src/Repository/RepositorySearchTrait.php
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository;
use App\Repository\Query\BaseQuery;
use Doctrine\ORM\QueryBuilder;
trait RepositorySearchTrait
{
private function getMetaFieldClass(): ?string
{
return null;
}
private function getMetaFieldName(): ?string
{
return null;
}
/**
* @return array<string>
*/
private function getSearchableFields(): array
{
return [];
}
private function supportsMetaFields(): bool
{
/* @phpstan-ignore-next-line */
return $this->getMetaFieldClass() !== null && $this->getMetaFieldName() !== null;
}
private function addSearchTerm(QueryBuilder $qb, BaseQuery $query): void
{
if (!$query->hasSearchTerm()) {
return;
}
$searchTerm = $query->getSearchTerm();
if (!$this->supportsMetaFields() && !$searchTerm->hasSearchTerm()) {
return;
}
$aliases = $qb->getRootAliases();
if (!isset($aliases[0])) {
throw new RepositoryException('No alias was set before invoking addSearchTerm().');
}
$rootAlias = $aliases[0];
$searchAnd = $qb->expr()->andX();
if ($this->supportsMetaFields()) {
$i = 0;
$a = 0;
$c = 0;
foreach ($searchTerm->getSearchFields() as $metaName => $metaValue) {
$and = $qb->expr()->andX();
/** @var non-falsy-string&literal-string $alias */
$alias = 'meta' . $a++;
$paramName = 'metaName' . $i++;
$paramValue = 'metaValue' . $c++;
if ($metaValue === '*') {
$qb->leftJoin($rootAlias . '.meta', $alias);
$and->add($qb->expr()->eq($alias . '.name', ':' . $paramName));
$qb->setParameter($paramName, $metaName);
$and->add($qb->expr()->isNotNull($alias . '.value'));
} elseif ($metaValue === '~') {
$and->add(
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
);
} elseif ($metaValue === '' || $metaValue === null) {
$qb->leftJoin($rootAlias . '.meta', $alias);
$and->add(
$qb->expr()->orX(
$qb->expr()->andX(
$qb->expr()->eq($alias . '.name', ':' . $paramName),
$qb->expr()->isNull($alias . '.value')
),
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
)
);
$qb->setParameter($paramName, $metaName);
} else {
$qb->leftJoin($rootAlias . '.meta', $alias);
$and->add($qb->expr()->eq($alias . '.name', ':' . $paramName));
$and->add($qb->expr()->like($alias . '.value', ':' . $paramValue));
$qb->setParameter($paramName, $metaName);
$qb->setParameter($paramValue, '%' . $metaValue . '%');
}
$searchAnd->add($and);
}
}
$fields = $this->getSearchableFields();
if ($searchTerm->hasSearchTerm() && \count($fields) > 0) {
$or = $qb->expr()->orX();
$i = 0;
foreach ($fields as $field) {
$param = 'searchTerm' . $i++;
if (stripos($field, '.') === false) {
$field = $rootAlias . '.' . $field;
}
$or->add(
$qb->expr()->like($field, ':' . $param),
);
$qb->setParameter($param, '%' . $searchTerm->getSearchTerm() . '%');
}
$searchAnd->add($or);
}
if ($searchAnd->count() > 0) {
$qb->andWhere($searchAnd);
}
}
}