feat(doctors): enhance doctor listing with bookable sorting and filtering, add JSON_EXTRACT DQL function
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Doctor\Repository;
|
||||
|
||||
use App\Appointment\Entity\WeeklySchedule;
|
||||
use App\Auth\Entity\User;
|
||||
use App\Clinic\Entity\Clinic;
|
||||
use App\Doctor\Entity\Doctor;
|
||||
@@ -88,13 +89,31 @@ class DoctorRepository extends ServiceEntityRepository
|
||||
if (!empty($filters['name'])) {
|
||||
$qb->andWhere('d.name LIKE :name')->setParameter('name', '%' . $filters['name'] . '%');
|
||||
}
|
||||
// Public list shows only doctors with appointment enabled unless the
|
||||
// caller explicitly asks otherwise (e.g. admin passing active=0).
|
||||
$active = isset($filters['active']) ? (bool) $filters['active'] : true;
|
||||
$qb->andWhere('d.activeDoctorAppointment = :active')
|
||||
->setParameter('active', $active);
|
||||
// "دارای نوبت" = appointment flag on AND a weekly schedule exists with
|
||||
// online booking not disabled AND at least one active session — same
|
||||
// definition as the `active` field in Doctor::toListArray(), so
|
||||
// filter/sort match what the doctor card shows.
|
||||
$bookable = fn(string $alias): string => sprintf(
|
||||
'd.activeDoctorAppointment = true AND EXISTS(SELECT %1$s.id FROM %2$s %1$s WHERE %1$s.doctor = d'
|
||||
. ' AND (JSON_EXTRACT(%1$s.setting, \'$.meta.online_booking_enabled\') IS NULL OR JSON_EXTRACT(%1$s.setting, \'$.meta.online_booking_enabled\') != \'false\')'
|
||||
. ' AND JSON_CONTAINS(JSON_EXTRACT(%1$s.setting, \'$**.sessions[*].active\'), \'true\') = 1)',
|
||||
$alias,
|
||||
WeeklySchedule::class
|
||||
);
|
||||
|
||||
$qb->orderBy('d.doctorRate', $sort);
|
||||
if (isset($filters['active'])) {
|
||||
if ((bool) $filters['active']) {
|
||||
$qb->andWhere($bookable('wsf'));
|
||||
} else {
|
||||
// Legacy admin escape hatch: active=0 → flag explicitly off.
|
||||
$qb->andWhere('d.activeDoctorAppointment = false');
|
||||
}
|
||||
}
|
||||
|
||||
// Bookable doctors always rank above non-bookable ones.
|
||||
$qb->addSelect('(CASE WHEN ' . $bookable('wss') . ' THEN 1 ELSE 0 END) AS HIDDEN bookableRank')
|
||||
->orderBy('bookableRank', 'DESC')
|
||||
->addOrderBy('d.doctorRate', $sort);
|
||||
|
||||
$total = (new Paginator($qb))->count();
|
||||
$results = $qb->setFirstResult(($page - 1) * $limit)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Shared\Doctrine;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* JSON_EXTRACT(json_doc, path) DQL function for MariaDB/MySQL.
|
||||
* Usage: WHERE JSON_EXTRACT(ws.setting, '$.meta.online_booking_enabled') != 'false'
|
||||
*/
|
||||
class JsonExtract extends FunctionNode
|
||||
{
|
||||
private Node $jsonDoc;
|
||||
private Node $path;
|
||||
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
$this->jsonDoc = $parser->StringPrimary();
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$this->path = $parser->StringPrimary();
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
return sprintf(
|
||||
'JSON_EXTRACT(%s, %s)',
|
||||
$this->jsonDoc->dispatch($sqlWalker),
|
||||
$this->path->dispatch($sqlWalker)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user