#1 Basic support of torrent list ordering added. Search slightly refactored and now does not create full search QueryBuilder in the repository.

This commit is contained in:
Alexey Skobkin 2018-06-29 03:24:16 +03:00
parent e7d9fdaecd
commit b6bd4f211a
4 changed files with 93 additions and 27 deletions

View file

@ -38,4 +38,9 @@ services:
class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
public: false
tags:
- { name: serializer.normalizer, priority: 1 }
- { name: serializer.normalizer, priority: 1 }
# Torrent searcher
App\Search\TorrentSearcher:
arguments:
$metadataFactory: '@doctrine.orm.magneticod_entity_manager.metadata_factory'

View file

@ -3,7 +3,7 @@
namespace App\Controller;
use App\Magnetico\Entity\Torrent;
use App\Magnetico\Repository\TorrentRepository;
use App\Search\TorrentSearcher;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Pagerfanta\Pagerfanta;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
@ -13,12 +13,14 @@ class TorrentController extends Controller
{
private const PER_PAGE = 20;
public function searchTorrent(Request $request, TorrentRepository $repo): Response
public function searchTorrent(Request $request, TorrentSearcher $searcher): Response
{
$query = $request->query->get('query', '');
$page = (int) $request->query->get('page', '1');
$orderBy = $request->query->get('order-by');
$order = $request->query->get('order', 'asc');
$pagerAdapter = new DoctrineORMAdapter($repo->createFindLikeQueryBuilder($query));
$pagerAdapter = new DoctrineORMAdapter($searcher->createSearchQueryBuilder($query, $orderBy, $order));
$pager = new Pagerfanta($pagerAdapter);
$pager
->setCurrentPage($page)

View file

@ -2,15 +2,15 @@
namespace App\Magnetico\Repository;
use App\Magnetico\Entity\Torrent;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\RegistryInterface;
class TorrentRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, \App\Magnetico\Entity\Torrent::class);
parent::__construct($registry, Torrent::class);
}
public function getTorrentsTotalCount(): int
@ -25,25 +25,4 @@ class TorrentRepository extends ServiceEntityRepository
return 0;
}
}
public function createFindLikeQueryBuilder(string $query): QueryBuilder
{
$qb = $this->createQueryBuilder('t');
$where = $qb->expr()->andX();
$query = trim($query);
$query = preg_replace('/\s+/', ' ', $query);
$parts = explode(' ', $query);
foreach ($parts as $idx => $part) {
$where->add($qb->expr()->like('LOWER(t.name)', ':part_'.$idx));
$qb->setParameter('part_'.$idx, '%'.strtolower($part).'%');
}
$qb->where($where);
return $qb;
}
}

View file

@ -0,0 +1,80 @@
<?php
namespace App\Search;
use App\Magnetico\Entity\Torrent;
use App\Magnetico\Repository\TorrentRepository;
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
use Doctrine\ORM\QueryBuilder;
class TorrentSearcher
{
private const ORDER_DISABLED_FIELDS = ['infoHash'];
/** @var TorrentRepository */
private $torrentRepo;
/** @var ClassMetadataFactory */
private $metadataFactory;
public function __construct(TorrentRepository $torrentRepo, ClassMetadataFactory $metadataFactory)
{
$this->torrentRepo = $torrentRepo;
$this->metadataFactory = $metadataFactory;
}
public function createSearchQueryBuilder(string $query, string $orderBy = null, string $order = 'asc'): QueryBuilder
{
$qb = $this->createFindLikeSplitPartsQueryBuilder($query);
if ($orderBy) {
$this->addOrder($qb, $orderBy, $order);
}
return $qb;
}
private function createFindLikeSplitPartsQueryBuilder(string $query): QueryBuilder
{
$qb = $this->torrentRepo->createQueryBuilder('t');
$where = $qb->expr()->andX();
foreach ($this->splitQueryToParts($query) as $idx => $part) {
$where->add($qb->expr()->like('LOWER(t.name)', ':part_'.$idx));
$qb->setParameter('part_'.$idx, '%'.strtolower($part).'%');
}
$qb->where($where);
return $qb;
}
private function addOrder(QueryBuilder $qb, string $orderBy, string $order): void
{
if (!\in_array(strtolower($order), ['asc', 'desc'])) {
throw new \InvalidArgumentException('Invalid sort order');
}
if ($this->canOrderBy($orderBy)) {
$qb->orderBy('t.'.$orderBy, $order);
}
}
private function canOrderBy(string $orderBy): bool
{
return (
!\in_array($orderBy, self::ORDER_DISABLED_FIELDS, true)
&& $this->metadataFactory->getMetadataFor(Torrent::class)->hasField($orderBy)
);
}
/** @return string[] */
private function splitQueryToParts(string $query): array
{
$query = trim($query);
$query = preg_replace('/\s+/', ' ', $query);
return explode(' ', $query);
}
}