Completed
Push — master ( 8da5b1...2bf815 )
by Matt
14s queued 11s
created

ImageController::filterQuery()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
c 0
b 0
f 0
nc 16
nop 2
dl 0
loc 27
rs 9.3554
1
<?php
2
3
namespace App\Controller\Image;
4
5
use App\Entity\Image;
6
use App\Form\ImageFilterData;
7
use App\Form\ImageFilterType;
8
use App\Repository\ImageRepository;
9
use Carbon\Carbon;
10
use Carbon\CarbonImmutable;
11
use DateTime;
12
use Doctrine\ORM\QueryBuilder;
13
use Knp\Component\Pager\PaginatorInterface;
14
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
15
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
16
use Symfony\Component\HttpFoundation\InputBag;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\Routing\Annotation\Route;
20
21
/**
22
 * @Route("/image", name="image_")
23
 */
24
class ImageController extends AbstractController
25
{
26
    /**
27
     * @Route("/{id}", name="show", methods={"GET"})
28
     */
29
    public function show(Image $image, ImageRepository $imageRepository): Response
30
    {
31
        $prev = $imageRepository->findPrev($image);
32
        $next = $imageRepository->findNext($image);
33
        return $this->render('image/show.html.twig', [
34
            'image' => $image,
35
            'prev' => $prev,
36
            'next' => $next
37
        ]);
38
    }
39
40
    /**
41
     * @Route(
42
     *  "",
43
     *  name="index",
44
     *  methods={"GET"},
45
     * )
46
     */
47
    public function index(
48
        Request $request,
49
        ImageRepository $imageRepository,
50
        PaginatorInterface $paginator
51
    ): Response {
52
        /** @var ImageFilterData $filterData */
53
        $filterData = new ImageFilterData(
54
            $imageRepository->getEarliestImageCaptureDate(),
55
            $imageRepository->getLatestImageCaptureDate(),
56
        );
57
58
        // These are overrides that can be sent by links set up on our
59
        // charts on the Statistics page. If we get a location, star
60
        // rating or start & end dates via those, we override our defaults.
61
        $filterData->overrideLocationFromUrlParam((string) $request->query->get('location'));
62
        $filterData->overrideRatingFromUrlParam($request->query->getInt('rating', -1));
63
        $filterData->overrideStartDateFromUrlParam((string) $request->query->get('periodStartDate'));
64
        $filterData->overrideEndDateFromUrlParam((string) $request->query->get('periodEndDate'));
65
66
        // Filtering form for the top of the page
67
        $locationChoices = $this->getLocationChoices($imageRepository);
68
        $filterForm = $this->createForm(
69
            ImageFilterType::class,
70
            $filterData,
71
            [
72
                'locations' => array_combine($locationChoices, array_values($locationChoices)),
73
                'csrf_protection' => false // We're just a GET request, and nothing bad happens no matter what you do.
74
            ]
75
        );
76
77
        $filterForm->handleRequest($request);
78
        if ($filterForm->isSubmitted() && $filterForm->isValid()) {
79
            $filterData = $filterForm->getData();
80
        };
81
82
        $qb = $imageRepository->getReversePaginatorQueryBuilder();
83
84
        $this->filterQuery($filterData, $qb);
85
86
        $query = $qb->getQuery();
87
88
        $page = $request->query->getInt('page', 1);
89
        $pagination = $paginator->paginate(
90
            $query,
91
            $page,
92
            20
93
        );
94
95
        return $this->render('image/index.html.twig', [
96
            'image_pagination' => $pagination,
97
            'filter_form' => $filterForm->createView()
98
        ]);
99
    }
100
101
    /**
102
     * @return array<string>
103
     */
104
    private function getLocationChoices(ImageRepository $imageRepository)
105
    {
106
        return $imageRepository->getAllLocations();
107
    }
108
109
    private function filterQuery(ImageFilterData $filterData, QueryBuilder $qb): void
110
    {
111
        if ($filterData->hasRating()) {
112
            $this->filterQueryByRating(
113
                $filterData->getRating(),
114
                $filterData->getRatingComparison(),
115
                $qb
116
            );
117
        }
118
119
        if ($filterData->hasStartDate()) {
120
            $qb
121
                ->andWhere('i.capturedAt >= :startDate')
122
                ->setParameter('startDate', $filterData->getStartDate());
123
        }
124
125
        if ($filterData->hasEndDate()) {
126
            $endDate = (new CarbonImmutable($filterData->getEndDate()))->addDays(1);
127
            $qb
128
                ->andWhere('i.capturedAt < :endDate')
129
                ->setParameter('endDate', $endDate);
130
        }
131
132
        if ($filterData->hasLocation()) {
133
            $qb
134
                ->andWhere('i.location = :location')
135
                ->setParameter('location', $filterData->getLocation());
136
        }
137
138
    }
139
140
    private function filterQueryByRating(?int $rating, string $ratingComparison, QueryBuilder &$qb): QueryBuilder
141
    {
142
        if ($rating !== null) {
143
            switch ($ratingComparison) {
144
                case 'lte':
145
                    $qb->andWhere($qb->expr()->lte('i.rating', ':rating'));
146
                    break;
147
                case 'gte':
148
                    $qb->andWhere($qb->expr()->gte('i.rating', ':rating'));
149
                    break;
150
                default:
151
                    // 'eq'
152
                    $qb->andWhere($qb->expr()->eq('i.rating', ':rating'));
153
                    break;
154
            }
155
            $qb->setParameter('rating', $rating);
156
        }
157
        return $qb;
158
    }
159
}
160