em ->getClassMetadata(SingleTaskPlaceEvent::class); [ $where, $parameters ] = match ($context) { 'person' => $this->getWhereClauseForPerson($args['person']), 'center' => $this->getWhereClauseForCenter($args['centers']), default => throw new UnexpectedValueException("context {$context} is not supported"), }; return TimelineSingleQuery::fromArray([ 'id' => sprintf('%s.%s.%s', $metadata->getSchemaName(), $metadata->getTableName(), $metadata->getColumnName('id')), 'type' => self::TYPE, 'date' => $metadata->getColumnName('datetime'), 'FROM' => $this->getFromClause($context), 'WHERE' => $where, 'parameters' => $parameters, ]); } public function getEntities(array $ids) { $events = $this->em ->getRepository(SingleTaskPlaceEvent::class) ->findBy(['id' => $ids]); return array_combine( array_map(static fn ($e) => $e->getId(), $events), $events ); } public function getEntityTemplate($entity, $context, array $args) { $workflow = $this->registry->get( $entity->getTask(), $entity->getData()['workflow'] ?? null ); // sf4 check: prevent error message: // `Notice: Undefined property: Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent::$getData` // * fix syntax error on $entity->getData['workflow'] // * return null if not set $transition = $this->getTransitionByName($entity->getTransition(), $workflow); return [ 'template' => '@ChillTask/Timeline/single_task_transition.html.twig', 'template_data' => [ 'context' => $context, 'event' => $entity, 'task' => $entity->getTask(), 'transition' => $transition, ], ]; } public function supportsType($type): bool { return self::TYPE === $type; } /** * @param string $name * * @return \Symfony\Component\Workflow\Transition */ protected function getTransitionByName($name, Workflow $workflow) { foreach ($workflow->getDefinition()->getTransitions() as $transition) { if ($transition->getName() === $name) { return $transition; } } } private function getFromClause(string $context) { $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); $singleTask = $this->em->getClassMetadata(SingleTask::class); $person = $this->em->getClassMetadata(Person::class); $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name']; $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name']; $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; $from = '{single_task_event} ' . 'JOIN {single_task} ON {single_task}.{task_pk} = {single_task_event}.{event_fk_task} ' . 'JOIN {person} ON {single_task}.{task_person_fk} = {person}.{person_pk}'; return strtr( $from, [ '{single_task}' => sprintf('%s.%s', $singleTask->getSchemaName(), $singleTask->getTableName()), '{single_task_event}' => sprintf('%s.%s', $taskEvent->getSchemaName(), $taskEvent->getTableName()), '{task_pk}' => $singleTask->getColumnName('id'), '{event_fk_task}' => $eventFkTask, '{person}' => $person->getTableName(), '{task_person_fk}' => $taskFkPerson, '{person_pk}' => $personPk, ] ); } private function getWhereClauseForCenter(array $centers): array { $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); $singleTask = $this->em->getClassMetadata(SingleTask::class); $person = $this->em->getClassMetadata(Person::class); $personFkCenter = $person->getAssociationMapping('center')['joinColumns'][0]['name']; $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name']; // the parameters $parameters = []; // the clause that we will repeat for each center, joined by 'OR' $clause = '{person}.{center_id} = ? AND {task}.{circle} IN ({circle_ids})'; // array to gather clauses $clauses = []; // loop over centers foreach ( $this->authorizationHelper->getReachableCenters( $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS) ) as $center ) { if (false === in_array($center, $centers, true)) { continue; } // fill center parameter $parameters[] = $center->getId(); // we loop over circles $circles = $this->authorizationHelper->getReachableCircles( $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS), $center ); $circleIds = []; foreach ($circles as $circle) { $parameters[] = $circleIds[] = $circle->getId(); } $clauses[] = strtr( $clause, [ '{person}' => $person->getTableName(), '{center_id}' => $personFkCenter, '{task}' => $singleTask->getSchemaName() . '.' . $singleTask->getTableName(), '{circle}' => $taskFkCircle, '{circle_ids}' => implode(', ', array_fill(0, count($circleIds), '?')), ] ); } if (0 === count($clauses)) { return ['FALSE = TRUE', []]; } return [ implode(' OR ', $clauses), $parameters, ]; } private function getWhereClauseForPerson(Person $personArg): array { $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); $singleTask = $this->em->getClassMetadata(SingleTask::class); $person = $this->em->getClassMetadata(Person::class); $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name']; $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name']; $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name']; // the parameters $parameters = $circleIds = []; // the clause that we will fill $clause = '{person}.{person_id} = ? AND {task}.{circle} IN ({circle_ids})'; // person is the first parameter $parameters[] = $personArg->getId(); // we loop over circles $circles = $this->authorizationHelper->getReachableCircles( $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS), $personArg->getCenter() ); if (0 === count($circles)) { // go fast to block access to every tasks return ['FALSE = TRUE', []]; } foreach ($circles as $circle) { $parameters[] = $circleIds[] = $circle->getId(); } return [ strtr( $clause, [ '{person}' => $person->getTableName(), '{person_id}' => $person->getColumnName('id'), '{task}' => $singleTask->getSchemaName() . '.' . $singleTask->getTableName(), '{circle}' => $taskFkCircle, '{circle_ids}' => implode(', ', array_fill(0, count($circleIds), '?')), ] ), $parameters, ]; } }