Using DQL 'ILIKE' implementation instead of 'LIKE' for search.

This commit is contained in:
Alexey Skobkin 2019-10-21 00:29:08 +03:00
parent 7d6b777603
commit 5109227b25
No known key found for this signature in database
GPG key ID: 5D5CEF6F221278E7
4 changed files with 102 additions and 1 deletions

View file

@ -41,3 +41,6 @@ doctrine:
dir: '%kernel.project_dir%/src/Magnetico/Entity' dir: '%kernel.project_dir%/src/Magnetico/Entity'
prefix: 'App\Magnetico' prefix: 'App\Magnetico'
alias: Magnetico alias: Magnetico
dql:
string_functions:
ILIKE: 'App\Doctrine\ORM\AST\Ilike'

View file

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace App\Doctrine\ORM\AST;
use Doctrine\ORM\Query\{AST\Functions\FunctionNode, AST\Node, Lexer, Parser, SqlWalker};
/**
* @since 0.1
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
* @see https://github.com/martin-georgiev/postgresql-for-doctrine
*/
abstract class BaseFunction extends FunctionNode
{
/** @var string */
protected $functionPrototype;
/** @var string[] */
protected $nodesMapping = [];
/** @var Node[] */
protected $nodes = [];
abstract protected function customiseFunction(): void;
protected function setFunctionPrototype(string $functionPrototype): void
{
$this->functionPrototype = $functionPrototype;
}
protected function addNodeMapping(string $parserMethod): void
{
$this->nodesMapping[] = $parserMethod;
}
public function parse(Parser $parser): void
{
$this->customiseFunction();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->feedParserWithNodes($parser);
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* Feeds given parser with previously set nodes.
*/
protected function feedParserWithNodes(Parser $parser): void
{
$nodesMappingCount = \count($this->nodesMapping);
$lastNode = $nodesMappingCount - 1;
for ($i = 0; $i < $nodesMappingCount; $i++) {
$parserMethod = $this->nodesMapping[$i];
$this->nodes[$i] = $parser->{$parserMethod}();
if ($i < $lastNode) {
$parser->match(Lexer::T_COMMA);
}
}
}
public function getSql(SqlWalker $sqlWalker): string
{
$dispatched = [];
foreach ($this->nodes as $node) {
$dispatched[] = $node->dispatch($sqlWalker);
}
return \vsprintf($this->functionPrototype, $dispatched);
}
}

View file

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Doctrine\ORM\AST;
/**
* Implementation of PostgreSql ILIKE().
*
* For usage example @see https://github.com/martin-georgiev/postgresql-for-doctrine/blob/master/docs/USE-CASES-AND-EXAMPLES.md
*
* @see https://www.postgresql.org/docs/9.3/functions-matching.html
*
* @author llaakkkk <lenakirichokv@gmail.com>
* @see https://github.com/martin-georgiev/postgresql-for-doctrine
*/
class Ilike extends BaseFunction
{
protected function customiseFunction(): void
{
$this->setFunctionPrototype('%s ilike %s');
$this->addNodeMapping('StringPrimary');
$this->addNodeMapping('StringPrimary');
}
}

View file

@ -39,7 +39,7 @@ class TorrentSearcher
$where = $qb->expr()->andX(); $where = $qb->expr()->andX();
foreach ($this->splitQueryToParts($query) as $idx => $part) { foreach ($this->splitQueryToParts($query) as $idx => $part) {
$where->add($qb->expr()->like('LOWER(t.name)', ':part_'.$idx)); $where->add('ILIKE(t.name , :part_'.$idx.') = TRUE');
$qb->setParameter('part_'.$idx, '%'.strtolower($part).'%'); $qb->setParameter('part_'.$idx, '%'.strtolower($part).'%');
} }