SaleService.php 7,03 ko
Newer Older
namespace App\Service;
use App\Dto\BarChartInput;
use App\Dto\BarChartOutput;
use App\Dto\MonthlyAveragePriceEvolution;
use App\Entity\Sale;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
class SaleService
    private EntityManagerInterface $entityManager;
    public function __construct(EntityManagerInterface $entityManager, CacheInterface $cache)
        $this->entityManager = $entityManager;
    public function updateTimeSerisCache(): void
        $this->cache->delete('time_series');
    }

    public function updateBartChartCache($input): void
    {
        $cacheKey = 'bar-chart' . $input;
        if ($this->cache->has($cacheKey)) {
            $this->cache->delete($cacheKey);
        }
    public function updateDonutChartCache($year): void
        if ($this->cache->has($cacheKey)) {
            $this->cache->delete($cacheKey);

    public function getTimeSeries(): array
    {
        return $this->cache->get('time_series', function (ItemInterface $item) {
            try {
                $queryBuilder = $this->entityManager->createQueryBuilder();

                $result = $queryBuilder
                    ->select('MONTH(s.date) as month', 'YEAR(s.date) as year', 'AVG(CASE WHEN s.surface <> 0 THEN s.amount / s.surface ELSE 0 END) as average_price')
                    ->from(Sale::class, 's')
                    ->groupBy('year, month')
                    ->orderBy('year, month')
                    ->getQuery()
                    ->getResult(Query::HYDRATE_ARRAY);

                $monthlyAveragePriceEvolutions = [];
                foreach ($result as $row) {
                    #$row['average_price'] = $row['total_surface'] != 0 ? $row['total_price'] / $row['total_surface'] : 0;
                    $monthlyAveragePriceEvolutions[] = new MonthlyAveragePriceEvolution(
                        (int)$row['month'],
                        (int)$row['year'],
                        (float)$row['average_price']
                    );
                }

                $item->expiresAfter(600);

                return $monthlyAveragePriceEvolutions;
            } catch (\Exception $exception){
                throw $exception;
    private function generateCacheKey(BarChartInput $input): string
    {
        $inputArray = [
            'start' => $input->start,
            'end' => $input->end,
            'granularity' => $input->granularity,
        ];

        $jsonEncodedInput = json_encode($inputArray);

        $cleanedKey = preg_replace('/[^A-Za-z0-9]/', '_', $jsonEncodedInput);
        return $cleanedKey;
    }
    public function getBarChartData(BarChartInput $input): array
    {
        $cacheKey = 'bar-chart' . $this->generateCacheKey($input);

        return $this->cache->get($cacheKey, function (ItemInterface $item) use ($input) {
            try {
                $startDate = new \DateTime($input->start);
                $endDate = new \DateTime($input->end);

                $queryBuilder = $this->entityManager->createQueryBuilder();
                $output = [];

                if ($input->granularity == 'month') {
                    $result = $queryBuilder
                        ->select('YEAR(s.date) as year', 'MONTH(s.date) as month', 'COUNT(s.id) as occurrences')
                        ->from(Sale::class, 's')
                        ->where('s.date BETWEEN :start AND :end')
                        ->setParameter('start', $startDate)
                        ->setParameter('end', $endDate)
                        ->groupBy('year', 'month')
                        ->orderBy('year')
                        ->getQuery()
                        ->getResult(Query::HYDRATE_ARRAY);
                } else {
                    switch ($input->granularity) {
                        case 'day':
                            $groupByExpression = 's.date';
                            $groupByAlias = 'date';
                            $dateFormat = 'Y-m-d';
                            break;
                        case 'year':
                            $groupByExpression = 'YEAR(s.date)';
                            $groupByAlias = 'year';
                            $dateFormat = 'Y';
                            break;
                        default:
                            throw new \InvalidArgumentException('Invalid granularity');
                    }

                    $result = $queryBuilder
                        ->select("{$groupByExpression} as {$groupByAlias}", 'COUNT(s.id) as occurrences')
                        ->from(Sale::class, 's')
                        ->where('s.date BETWEEN :start AND :end')
                        ->setParameter('start', $startDate)
                        ->setParameter('end', $endDate)
                        ->groupBy("{$groupByAlias}")
                        ->orderBy("{$groupByAlias}")
                        ->getQuery()
                        ->getResult(Query::HYDRATE_ARRAY);
                }

                foreach ($result as $row) {
                    if ($input->granularity == 'month') {
                        $month = $row['month'];
                        $year = $row['year'];
                        $dateString = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT);
                    } else {
                        $dateString = $row[$groupByAlias] instanceof \DateTimeInterface ? $row[$groupByAlias]->format($dateFormat) : $row[$groupByAlias];
                    }

                    $output[] = new BarChartOutput($dateString, (int)$row['occurrences']);
                }

                $item->expiresAfter(600);

                return $output;
            } catch (\Exception $exception){
                throw $exception;
            }
        });
        $cacheKey = 'donut-chart' . $year;

        return $this->cache->get($cacheKey, function (ItemInterface $item) use ($year) {

            try {
                $repository = $this->entityManager->getRepository(Sale::class);

                $result = $repository->createQueryBuilder('s')
                    ->select('s.region', 'COUNT(s.id) as occurrences')
                    ->andWhere('YEAR(s.date) = :year')
                    ->setParameter('year', $year)
                    ->groupBy('s.region')
                    ->getQuery()
                    ->getResult(Query::HYDRATE_ARRAY);
                    $data[] = new DonutChartOutput(
                        $row['region'],
                        (int)$row['occurrences'],
                    );
                }

                $item->expiresAfter(600);

                return $data;
            }catch (\Exception $exception){
                throw $exception;
            }
        });