<?php
namespace App\Doctrine\Repository\System;
use App\Doctrine\Repository\SearchableRepositoryInterface;
use App\Doctrine\Repository\SearchableRepositoryTrait;
use App\Entity\System\School;
use App\Model\Searching\AbstractSearch;
use App\Model\Searching\SchoolSearch;
use App\Util\Querying;
use Cms\TenantBundle\Entity\Tenant;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use JsonException;
/**
* @method School|null find($id, $lockMode = null, $lockVersion = null)
* @method School|null findOneBy(array $criteria, array $orderBy = null)
* @method array|School[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class SchoolRepository extends EntityRepository implements SearchableRepositoryInterface
{
use SearchableRepositoryTrait;
/**
* @param string|null $ulid
* @return School|null
*/
public function findOneByUlid(?string $ulid): ?School
{
return $ulid ? $this->findOneBy([
'ulid' => $ulid,
]) : null;
}
/**
* {@inheritDoc}
* @return array|School[]
*/
public function findAll(): array
{
return $this->findBy(
[],
[
'type' => 'ASC',
'name' => 'ASC',
]
);
}
/**
* @param Tenant $tenant
* @param int $schoolTypes
* @return School[]
*/
public function findAllForTenantAndSchoolTypes(Tenant $tenant, int $schoolTypes): array
{
return $this->createQueryBuilder('schools')
->andWhere('schools.tenant = :tenant')
->setParameter('tenant', $tenant)
->andWhere('BIT_AND(:types, schools.type) > 0')
->setParameter('types', $schoolTypes)
->getQuery()
->getResult();
}
/**
* @return array|School[]
*/
public function findAllForApp(bool $district = true): array
{
$qb = $this
->createQueryBuilder('schools')
->andWhere('schools.department IS NOT NULL');
if ($district) {
$qb
->addSelect('CASE WHEN schools.type = :type THEN 0 ELSE 1 END AS HIDDEN _sorting')
->addOrderBy('_sorting', 'ASC');
} else {
$qb->andWhere('schools.type != :type');
}
return $qb
->setParameter('type', School::TYPES__DISTRICT)
->addOrderBy('schools.name', 'ASC')
->getQuery()
->getResult();
}
/**
* @param array|string[] $schools
* @param bool $district
* @return array|School[]
*/
public function findAllForSchools(array $schools, ?bool $district = null): array
{
// init builder
$qb = $this
->createQueryBuilder('schools')
->andWhere('schools.department IS NOT NULL');
// custom sorting, district first, then by name no matter the type
$qb
->addSelect('CASE WHEN schools.type = :typesDistrict THEN 0 ELSE 1 END AS HIDDEN _sorting')
->setParameter('typesDistrict', School::TYPES__DISTRICT);
// handle district option
switch (true) {
// we don't care if the district naturally falls in the profiles list of schools
// i.e. the user may be directly associated with the district, such as a superintendent, etc.
case $district === null:
$qb
->andWhere('schools.oneRosterOrg IN (:schools)')
->setParameter('schools', $schools);
break;
// we want to ensure that the district is not in the results, no matter of direct associations or not
case $district === false:
$qb
->andWhere('schools.type != :type')
->setParameter('type', School::TYPES__DISTRICT)
->andWhere('schools.oneRosterOrg IN (:schools)')
->setParameter('schools', $schools);
break;
// we want to ensure that the district appears in the list of schools for the user
case $district === true:
$qb
->andWhere(
$qb->expr()->orX(
'schools.type = :type',
'schools.oneRosterOrg IN (:schools)',
)
)
->setParameter('type', School::TYPES__DISTRICT)
->setParameter('schools', $schools);
break;
}
// sort and return results
return $qb
->addOrderBy('_sorting', 'ASC')
->addOrderBy('schools.name', 'ASC')
->getQuery()
->getResult();
}
/**
* {@inheritDoc}
* @param SchoolSearch $search
*/
public function qbBySearch(
AbstractSearch $search,
?QueryBuilder $qb = null
): QueryBuilder
{
if ( ! $search instanceof SchoolSearch) {
throw new \Exception();
}
$qb = $qb ?: $this->createQueryBuilder('schools');
switch ($search->getSort()) {
case SchoolSearch::SORTS__NAME:
$qb->addOrderBy('schools.name', $search->getDirection());
break;
case SchoolSearch::SORTS__TYPE:
$qb
->addOrderBy('schools.type', Querying::dirFlip($search->getDirection()))
->addOrderBy('schools.name', 'ASC');
break;
case SchoolSearch::SORTS__TIMESTAMP:
$qb
->addOrderBy('schools.touchedAt', $search->getDirection())
->addOrderBy('schools.name', 'ASC');
break;
}
return $qb;
}
/**
* @param School ...$schools
* @return string
* @throws JsonException
*/
public static function getSchoolsOneRosterOrgsJson(School ...$schools): string
{
return json_encode(
array_map(
static function (School $school) {
return $school->getOneRosterOrg();
},
$schools
),
JSON_THROW_ON_ERROR
);
}
}