mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 03:08:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
/*
 | 
						|
 * Chill is a software for social workers
 | 
						|
 *
 | 
						|
 * For the full copyright and license information, please view
 | 
						|
 * the LICENSE file that was distributed with this source code.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Chill\ReportBundle\Timeline;
 | 
						|
 | 
						|
use Chill\CustomFieldsBundle\Service\CustomFieldsHelper;
 | 
						|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
						|
use Chill\MainBundle\Timeline\TimelineProviderInterface;
 | 
						|
use Chill\MainBundle\Timeline\TimelineSingleQuery;
 | 
						|
use Chill\PersonBundle\Entity\Person;
 | 
						|
use Chill\ReportBundle\Entity\Report;
 | 
						|
use Doctrine\ORM\EntityManager;
 | 
						|
use Symfony\Bundle\SecurityBundle\Security;
 | 
						|
 | 
						|
/**
 | 
						|
 * Provide report for inclusion in timeline.
 | 
						|
 */
 | 
						|
class TimelineReportProvider implements TimelineProviderInterface
 | 
						|
{
 | 
						|
    public function __construct(protected EntityManager $em, protected AuthorizationHelper $helper, private readonly Security $security, protected CustomFieldsHelper $customFieldsHelper, protected $showEmptyValues) {}
 | 
						|
 | 
						|
    public function fetchQuery($context, array $args): TimelineSingleQuery
 | 
						|
    {
 | 
						|
        $this->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(Report::class)
 | 
						|
            ->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,
 | 
						|
        ];
 | 
						|
    }
 | 
						|
}
 |