checkContext($context); $report = $this->em->getClassMetadata(Report::class); [$where, $parameters] = $this->getWhereClause($context, $args); return TimelineSingleQuery::fromArray([ 'id' => $report->getTableName() .'.'.$report->getColumnName('id'), 'type' => 'report', 'date' => $report->getTableName() .'.'.$report->getColumnName('date'), 'FROM' => $this->getFromClause($context), 'WHERE' => $where, 'parameters' => $parameters, ]); } public function getEntities(array $ids) { $reports = $this->em->getRepository('ChillReportBundle:Report') ->findBy(['id' => $ids]); $result = []; foreach ($reports as $report) { $result[$report->getId()] = $report; } return $result; } public function getEntityTemplate($entity, $context, array $args) { $this->checkContext($context); return [ 'template' => '@ChillReport/Timeline/report.html.twig', 'template_data' => [ 'report' => $entity, 'context' => $context, 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context), ], ]; } public function supportsType($type) { return 'report' === $type; } protected function getFieldsToRender(Report $entity, $context, array $args = []) { // gather all custom fields which should appears in summary $gatheredFields = []; if (\array_key_exists('summary_fields', $entity->getCFGroup()->getOptions())) { // keep in memory title $title = null; $subtitle = null; foreach ($entity->getCFGroup()->getCustomFields() as $customField) { if ( \in_array( $customField->getSlug(), $entity->getCFGroup()->getOptions()['summary_fields'], true ) ) { // if we do not want to show empty values if (false === $this->showEmptyValues) { if ('title' === $customField->getType()) { $options = $customField->getOptions(); switch ($options['type']) { case 'title': $title = $customField; break; case 'subtitle': $subtitle = $customField; break; } } else { if ( false === $this->customFieldsHelper->isEmptyValue($entity->getCFData(), $customField) ) { if (null !== $title) { $gatheredFields[] = $title; $title = null; } if (null !== $subtitle) { $gatheredFields[] = $subtitle; $subtitle = null; } $gatheredFields[] = $customField; } } } else { $gatheredFields[] = $customField; } } } } return $gatheredFields; } /** * check if the context is supported. * * @param string $context * * @throws \LogicException if the context is not supported */ private function checkContext($context): void { if ('person' !== $context && 'center' !== $context) { throw new \LogicException("The context '{$context}' is not supported. Currently only 'person' and 'center' is supported"); } } private function getFromClause(string $context): string { $report = $this->em->getClassMetadata(Report::class); $person = $this->em->getClassMetadata(Person::class); $reportPersonId = $report ->getAssociationMapping('person')['joinColumns'][0]['name']; $personId = $report ->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; $clause = '{report} '. 'JOIN {person} ON {report}.{person_id} = {person}.{id_person} '; return \strtr( $clause, [ '{report}' => $report->getTableName(), '{person}' => $person->getTableName(), '{person_id}' => $reportPersonId, '{id_person}' => $personId, ] ); } private function getWhereClause(string $context, array $args): array { return match ($context) { 'person' => $this->getWhereClauseForPerson($context, $args), 'center' => $this->getWhereClauseForCenter($context, $args), default => throw new \UnexpectedValueException("This context {$context} is not implemented"), }; } private function getWhereClauseForCenter(string $context, array $args): array { $role = 'CHILL_REPORT_SEE'; $report = $this->em->getClassMetadata(Report::class); $person = $this->em->getClassMetadata(Person::class); $reachableCenters = $this->helper->getReachableCenters($this->security->getUser(), $role); $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name']; $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name']; // parameters for the query, will be filled later $parameters = []; // the clause, that will be joined with an "OR" $centerScopesClause = '({person}.{center_id} = ? '. 'AND {report}.{scopes_id} IN ({scopes_ids}))'; // container for formatted clauses $formattedClauses = []; $askedCenters = $args['centers']; foreach ($reachableCenters as $center) { if (false === \in_array($center, $askedCenters, true)) { continue; } // add the center id to the parameters $parameters[] = $center->getId(); // loop over scopes $scopeIds = []; foreach ($this->helper->getReachableScopes($this->security->getUser(), $role, $center) as $scope) { if (\in_array($scope->getId(), $scopeIds, true)) { continue; } $scopeIds[] = $scope->getId(); } $formattedClauses[] = \strtr($centerScopesClause, [ '{scopes_ids}' => \implode(', ', \array_fill(0, \count($scopeIds), '?')), ]); // append $scopeIds to parameters $parameters = [...$parameters, ...$scopeIds]; } if (0 === \count($formattedClauses)) { return ['FALSE = TRUE', []]; } return [ \strtr( \implode(' OR ', $formattedClauses), [ '{person}' => $person->getTableName(), '{center_id}' => $personCenterId, '{report}' => $report->getTableName(), '{scopes_id}' => $reportScopeId, ] ), $parameters, ]; } private function getWhereClauseForPerson(string $context, array $args): array { $role = 'CHILL_REPORT_SEE'; $report = $this->em->getClassMetadata(Report::class); $person = $this->em->getClassMetadata(Person::class); $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name']; $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name']; // parameters for the query, will be filled later $parameters = [$args['person']->getId()]; // this is the final clause that we are going to fill $clause = '{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})'; // iterate over reachable scopes $scopes = $this->helper->getReachableScopes($this->security->getUser(), $role, $args['person']->getCenter()); foreach ($scopes as $scope) { if (\in_array($scope->getId(), $parameters, true)) { continue; } $parameters[] = $scope->getId(); } if (1 === \count($parameters)) { // nothing change, we simplify the clause $clause = '{report}.{person_id} = ? AND FALSE = TRUE'; } return [ \strtr( $clause, [ '{report}' => $report->getTableName(), '{person_id}' => $reportPersonId, '{scopes_id}' => $reportScopeId, '{scopes_ids}' => \implode( ', ', \array_fill(0, \count($parameters) - 1, '?') ), ] ), $parameters, ]; } }