<?php
namespace App\Doctrine\Repository\Content;
use App\Doctrine\Repository\SearchableRepositoryInterface;
use App\Doctrine\Repository\SearchableRepositoryTrait;
use App\Doctrine\Repository\System\SchoolRepository;
use App\Entity\Content\AbstractObject;
use App\Entity\Feed\AbstractEntry;
use App\Entity\System\School;
use App\Model\Searching\AbstractSearch;
use App\Util\Querying;
use Cms\ContainerBundle\Entity\Container;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Platform\SecurityBundle\Entity\Identity\Account;
/**
* @method AbstractObject find($id, $lockMode = null, $lockVersion = null)
* @method array|AbstractObject[] findAll()
* @method array|AbstractObject[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
* @method AbstractObject findOneBy(array $criteria, array $orderBy = null)
*/
class ObjectRepository extends EntityRepository implements SearchableRepositoryInterface
{
use SearchableRepositoryTrait;
/**
* {@inheritDoc}
* @param ObjectSearch $search
*/
public function qbBySearch(
AbstractSearch $search,
?QueryBuilder $qb = null
): QueryBuilder
{
if ( ! $search instanceof ObjectSearch) {
throw new \LogicException();
}
$repo = $this->getEntityManager()->getRepository($this->_entityName);
if ( ! $repo instanceof self) {
throw new \RuntimeException();
}
$qb = $qb ?: $repo->createQueryBuilder('objects');
if ($this->_entityName === AbstractObject::class && $search->getTypes()) {
$qb->andWhere(sprintf(
'objects INSTANCE OF (%s)',
implode(', ', $search->getTypes())
));
}
if ($search->getVisibility()) {
$qb
->andWhere('objects.visibility = :visibility')
->setParameter('visibility', $search->getVisibility());
}
$search->filterCutoff($qb);
$search->filterWindow($qb);
if ($lookup = $search->getLookup()) {
$qb
->andWhere($qb->expr()->orX(
Querying::dqlLike('objects.headline LIKE :lookup')
))
->setParameter('lookup', Querying::likeAny($lookup));
}
if (
in_array($search->getFilter(), [ObjectSearch::FILTERS__MY_DRAFT, ObjectSearch::FILTERS__MY_PUBLISHED], true) &&
$search->getAccount() instanceof Account
) {
$qb
->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('objects.touchedBy', $search->getAccount()->getId()),
$qb->expr()->andX(
$qb->expr()->isNull('objects.touchedBy'),
$qb->expr()->eq('objects.updatedBy', $search->getAccount()->getId())
),
$qb->expr()->andX(
$qb->expr()->isNull('objects.touchedBy'),
$qb->expr()->isNull('objects.updatedBy'),
$qb->expr()->eq('objects.createdBy', $search->getAccount()->getId())
)
)
)
;
}
if (in_array($search->getFilter(), [ObjectSearch::FILTERS__MY_DRAFT, ObjectSearch::FILTERS__DRAFT], true)) {
$qb
->andWhere('objects.visibility != :visibility')
->setParameter('visibility', AbstractEntry::VISIBILITIES__PUBLISHED);
}
if (in_array($search->getFilter(), [ObjectSearch::FILTERS__MY_PUBLISHED, ObjectSearch::FILTERS__PUBLISHED], true)) {
$qb
->andWhere('objects.visibility = :visibility')
->setParameter('visibility', AbstractEntry::VISIBILITIES__PUBLISHED);
}
if ($search->getContainer() instanceof Container) {
/** @var SchoolRepository $schoolRepository */
$schoolRepository = $this->getEntityManager()->getRepository(School::class);
$school = $schoolRepository->findOneBy(['department' => $search->getContainer()]);
$schoolType = ($school instanceof School) ? $school->getType() : 0;
if ($search->isDeep()) {
$qb
->leftJoin('objects.department', 'departments')
->addSelect('departments')
->andWhere(
$qb->expr()->orX(
$qb->expr()->andX(
$qb->expr()->eq('departments.rt', ':rt'),
$qb->expr()->gte('departments.lft', ':lft'),
$qb->expr()->lte('departments.rgt', ':rgt'),
),
$qb->expr()->gt('BIT_AND(objects.schoolTypes, :schoolType)', 0),
)
)
->setParameter('rt', $search->getContainer()->getRoot())
->setParameter('lft', $search->getContainer()->getLeft())
->setParameter('rgt', $search->getContainer()->getRight())
->setParameter('schoolType', $schoolType)
;
} else {
$qb
->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('objects.department', ':department'),
$qb->expr()->gt('BIT_AND(objects.schoolTypes, :schoolType)', 0),
)
)
->setParameter('department', $search->getContainer())
->setParameter('schoolType', $schoolType)
;
}
}
if ($search->getChannels()) {
$qb
->andWhere('BIT_AND(objects.channels, :channels) = :channels')
->setParameter('channels', $search->getChannels());
}
switch ($search->getSort()) {
case ObjectSearch::SORTS__NAME:
$qb
->addOrderBy('objects.headline', $search->getDirection());
break;
case ObjectSearch::SORTS__TIMESTAMP:
$qb
->addOrderBy('objects.touchedAt', $search->getDirection())
->addOrderBy('objects.headline', 'ASC');
break;
}
return $qb;
}
}