* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Chill\PersonBundle\Timeline; use Chill\MainBundle\Timeline\TimelineProviderInterface; use Doctrine\ORM\EntityManager; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\MainBundle\Entity\Center; use Chill\PersonBundle\Security\Authorization\PersonVoter; use Symfony\Component\Security\Core\Security; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Timeline\TimelineSingleQuery; /** * Provide method to build timeline for accompanying periods * * This class is resued by TimelineAccompanyingPeriodOpening (for opening) * and TimelineAccompanyingPeriodClosing (for closing) * */ abstract class AbstractTimelineAccompanyingPeriod implements TimelineProviderInterface { protected EntityManager $em; private Security $security; private AuthorizationHelper $authorizationHelper; private const SUPPORTED_CONTEXTS = [ 'person', 'center' ]; public function __construct(EntityManager $em, Security $security, AuthorizationHelper $authorizationHelper) { $this->em = $em; $this->security = $security; $this->authorizationHelper = $authorizationHelper; } /** * * {@inheritDoc} */ public function getEntities(array $ids) { $periods = $this->em ->getRepository('ChillPersonBundle:AccompanyingPeriod') ->findBy(array('id' => $ids)); //set results in an associative array with id as indexes $results = array(); foreach($periods as $period) { $results[$period->getId()] = $period; } return $results; } /** * prepare fetchQuery without `WHERE` and `TYPE` clause * * @param string $context * @param array $args * @return array * @throws \LogicException */ protected function basicFetchQuery($context, array $args) { if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { throw new \LogicException('TimelineAccompanyingPeriod is not able ' . 'to render context '.$context); } $metadata = $this->em ->getClassMetadata(AccompanyingPeriod::class) ; [$where, $parameters] = $this->buildWhereClause($context, $args); return TimelineSingleQuery::fromArray([ 'id' => "{$metadata->getTableName()}.{$metadata->getColumnName('id')}", 'FROM' => $this->buildFromClause($context), 'WHERE' => $where, 'parameters' => $parameters ]); } private function buildFromClause($context) { $period = $this->em->getClassMetadata(AccompanyingPeriod::class); $participation = $this->em->getClassMetadata(AccompanyingPeriodParticipation::class); $person = $this->em->getClassMetadata(Person::class); $join = $participation->getAssociationMapping('accompanyingPeriod')['joinColumns'][0]; $joinPerson = $participation->getAssociationMapping('person')['joinColumns'][0]; if ($context === 'person') { return "{$period->getTableName()} ". "JOIN {$participation->getTableName()} ". "ON {$participation->getTableName()}.{$join['name']} = ". "{$period->getTableName()}.{$join['referencedColumnName']}"; } else { return "{$period->getTableName()} ". "JOIN {$participation->getTableName()} ". "ON {$participation->getTableName()}.{$join['name']} = ". "{$period->getTableName()}.{$join['referencedColumnName']} ". "JOIN {$person->getTableName()} ". "ON {$participation->getTableName()}.{$joinPerson['name']} = ". "{$person->getTableName()}.{$joinPerson['referencedColumnName']}" ; } } protected function buildWhereClause($context, array $args): array { $participation = $this->em->getClassMetadata(AccompanyingPeriodParticipation::class); $join = $participation->getAssociationMapping('person')['joinColumns'][0]; $person = $this->em->getClassMetadata(Person::class); $joinCenter = $person->getAssociationMapping('center')['joinColumns'][0]; if ($context === 'center') { $allowedCenters = $this->authorizationHelper->filterReachableCenters($this->security->getUser(), $args['centers'], PersonVoter::SEE); $params = []; $questionMarks = []; $query = "{$person->getTableName()}.{$joinCenter['name']} IN ("; foreach ($allowedCenters as $c) { $questionMarks[] = '?'; $params[] = $c->getId(); } $query .= \implode(", ", $questionMarks).")"; return [$query, $params]; } elseif ($context === 'person') { return [ "{$participation->getTableName()}.{$join['name']} = ?", [ $args['person']->getId() ]]; } throw new \LogicException("this context is not supported: $context"); } /** * return the expected response for TimelineProviderInterface::getEntityTemplate * * @param string $template the template for rendering * @param mixed $entity * @param string $context * @param array $args * @return array */ protected function getBasicEntityTemplate($template, $entity, $context, array $args) { return array( 'template' => $template, 'template_data' => ['period' => $entity, 'context' => $context] ); } }