test: enable Doctrine profiling in the test env and fix the N+1 it exposed

APP_DEBUG=0 in .env means doctrine.dbal.profiling, which defaults to
%kernel.debug%, was off in tests too, so doctrine.debug_data_holder was never
registered. Every test calling countQueries() errored out — all four N+1
regression tests had been dead for as long as they have existed. Turning
profiling on for when@test brings the harness back.

Three of the four passed immediately. The fourth was a real N+1: the
service-coverage endpoint batch-fetched its ServiceItem entities to avoid one
find() per row, but ServiceItem maps staffMembers as fetch: EAGER, so hydrating
N items fired N extra collection loads and the batch bought nothing. Six
coverage rows cost 11 queries where one row cost 6.

ServiceItemRepository::findUuidsByIds() returns the id => uuid map as a scalar
query, so no entity is hydrated and no eager collection is touched.

Also adds the query-count assertion for next_available_at that could not be
written while the harness was broken. Confirmed it fails against the previous
per-day implementation (40 queries for 2 locations, 113 for 6) and passes now.

Suite: 411 tests, 2 failures — both pre-existing and unrelated
(LowTierFixesTest, PatientWalletSessionSettleTest).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-18 14:06:38 +03:30
co-authored by Claude Opus 4.8
parent 9724504527
commit 8065ae3be1
4 changed files with 68 additions and 14 deletions
@@ -109,6 +109,32 @@ class ServiceItemRepository extends ServiceEntityRepository
->getResult();
}
/**
* نگاشت id → uuid برای مجموعه‌ای از خدمات.
*
* عمداً entity هیدریت نمی‌کند: ServiceItem رابطهٔ staffMembers را EAGER دارد،
* پس هر entity یک کوئری اضافه برای بارگذاری کارکنانش می‌زند و فهرستی که فقط
* uuid می‌خواهد به N+1 می‌افتد.
*
* @param int[] $ids
* @return array<int, string>
*/
public function findUuidsByIds(array $ids): array
{
if ($ids === []) {
return [];
}
$rows = $this->createQueryBuilder('i')
->select('i.id AS id, i.uuid AS uuid')
->where('i.id IN (:ids)')
->setParameter('ids', $ids)
->getQuery()
->getScalarResult();
return array_column($rows, 'uuid', 'id');
}
public function save(ServiceItem $item): void
{
$this->getEntityManager()->persist($item);