ImageController::getLocationChoices()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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