Completed
Push — master ( 0b4911...4851fa )
by Valentyn
04:19 queued 11s
created

MovieRecommendationController   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 40.63%

Importance

Changes 0
Metric Value
dl 0
loc 179
c 0
b 0
f 0
wmc 20
lcom 1
cbo 15
ccs 26
cts 64
cp 0.4063
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A deleteMoviesRecommendations() 0 28 4
A findRecommendedMovieById() 0 10 4
A findRecommendedMovieByTmdbId() 0 10 4
A getMoviesRecommendations() 0 19 2
A getSearch() 0 17 2
A postMoviesRecommendations() 0 35 4
1
<?php
2
3
namespace App\Movies\Controller;
4
5
use App\Controller\BaseController;
6
use App\Movies\Entity\Movie;
7
use App\Movies\Entity\MovieRecommendation;
8
use App\Movies\EventListener\AddRecommendationProcessor;
9
use App\Movies\Repository\MovieRecommendationRepository;
10
use App\Movies\Request\NewMovieRecommendationRequest;
11
use App\Movies\Request\RemoveMovieRecommendationRequest;
12
use App\Movies\Request\SearchRequest;
13
use App\Movies\Service\SearchService;
14
use App\Pagination\PaginatedCollection;
15
use App\Users\Entity\User;
16
use App\Users\Entity\UserRoles;
17
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Enqueue\Client\Message;
20
use Enqueue\Client\MessagePriority;
21
use Enqueue\Client\ProducerInterface;
22
use Symfony\Component\HttpFoundation\JsonResponse;
23
use Symfony\Component\HttpFoundation\Request;
24
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
25
use Symfony\Component\Routing\Annotation\Route;
26
27
class MovieRecommendationController extends BaseController
28
{
29
    /**
30
     * Add new recommendation.
31
     *
32
     * @Route("/api/movies/{id}/recommendations", methods={"POST"})
33
     *
34
     * @param NewMovieRecommendationRequest $request
35
     * @param Movie                         $originalMovie
36
     * @param EntityManagerInterface        $em
37
     * @param ProducerInterface             $producer
38
     *
39
     * @throws \Doctrine\ORM\ORMException
40
     *
41
     * @return JsonResponse
42
     */
43 7
    public function postMoviesRecommendations(NewMovieRecommendationRequest $request, Movie $originalMovie, EntityManagerInterface $em, ProducerInterface $producer)
44
    {
45 7
        $this->denyAccessUnlessGranted(UserRoles::ROLE_USER);
46
47 7
        $recommendation = $request->get('recommendation');
48 7
        $user = $this->getUser();
49
50 7
        if (empty($recommendation['movie_id'])) {
51 1
            $message = new Message(json_encode([
52 1
                'tmdb_id' => $recommendation['tmdb_id'],
53 1
                'movie_id' => $originalMovie->getId(),
54 1
                'user_id' => $user->getId(),
55
            ]));
56
            // todo redis doesnt support priority $message->setPriority(MessagePriority::VERY_LOW);
57 1
            $producer->sendEvent(AddRecommendationProcessor::ADD_RECOMMENDATION, $message);
58
59 1
            return new JsonResponse();
60
        }
61
62 6
        $recommendedMovie = $em->getReference(Movie::class, $recommendation['movie_id']);
63
64 6
        if ($recommendedMovie === null) {
65
            throw new NotFoundHttpException();
66
        }
67
68 6
        $originalMovie->addRecommendation($user, $recommendedMovie);
0 ignored issues
show
Documentation introduced by
$user is of type null|object, but the function expects a object<App\Users\Entity\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
69 6
        $em->persist($originalMovie);
70
        try {
71 6
            $em->flush();
72
        } catch (UniqueConstraintViolationException $exception) {
73
            // It's ok..
74
        }
75
76 6
        return new JsonResponse();
77
    }
78
79
    /**
80
     * Remove recommendation.
81
     *
82
     * @Route("/api/movies/{id}/recommendations", methods={"DELETE"})
83
     *
84
     * @param RemoveMovieRecommendationRequest $request
85
     * @param Movie                            $originalMovie
86
     * @param MovieRecommendationRepository    $repository
87
     * @param EntityManagerInterface           $em
88
     *
89
     * @return JsonResponse
90
     */
91
    public function deleteMoviesRecommendations(RemoveMovieRecommendationRequest $request, Movie $originalMovie, MovieRecommendationRepository $repository, EntityManagerInterface $em)
0 ignored issues
show
Unused Code introduced by
The parameter $repository is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
92
    {
93
        $this->denyAccessUnlessGranted(UserRoles::ROLE_USER);
94
95
        $user = $this->getUser();
96
97
        if (empty($request->get('movie_id'))) {
98
            $recommendedMovie = $this->findRecommendedMovieByTmdbId($originalMovie, $user, $request->get('tmdb_id'));
0 ignored issues
show
Documentation introduced by
$user is of type null|object, but the function expects a object<App\Users\Entity\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
99
            if ($recommendedMovie === null) {
100
                return new JsonResponse();
101
            }
102
103
            $em->remove($recommendedMovie);
104
            $em->flush();
105
106
            return new JsonResponse();
107
        }
108
109
        $recommendedMovie = $this->findRecommendedMovieById($originalMovie, $user, $request->get('movie_id'));
0 ignored issues
show
Documentation introduced by
$user is of type null|object, but the function expects a object<App\Users\Entity\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
110
        if ($recommendedMovie === null) {
111
            return new JsonResponse();
112
        }
113
114
        $em->remove($recommendedMovie);
115
        $em->flush();
116
117
        return new JsonResponse();
118
    }
119
120
    private function findRecommendedMovieById(Movie $originalMovie, User $user, int $id): ?MovieRecommendation
121
    {
122
        foreach ($originalMovie->getRecommendations() as $recommendation) {
123
            if ($recommendation->getUser()->getId() === $user->getId() && $recommendation->getRecommendedMovie()->getId() === $id) {
124
                return $recommendation;
125
            }
126
        }
127
128
        return null;
129
    }
130
131
    private function findRecommendedMovieByTmdbId(Movie $originalMovie, User $user, int $tmdbId): ?MovieRecommendation
132
    {
133
        foreach ($originalMovie->getRecommendations() as $recommendation) {
134
            if ($recommendation->getUser()->getId() === $user->getId() && $recommendation->getRecommendedMovie()->getTmdb()->getId() === $tmdbId) {
135
                return $recommendation;
136
            }
137
        }
138
139
        return null;
140
    }
141
142
    /**
143
     * @Route("/api/movies/{id}/recommendations", methods={"GET"})
144
     *
145
     * @param Request                       $request
146
     * @param Movie                         $movie
147
     * @param MovieRecommendationRepository $repository
148
     *
149
     * @return JsonResponse
150
     */
151 3
    public function getMoviesRecommendations(Request $request, Movie $movie, MovieRecommendationRepository $repository)
152
    {
153 3
        $user = $this->getUser();
154
155 3
        $offset = (int) $request->get('offset', 0);
156 3
        $limit = $request->get('limit', null);
157
158 3
        if ($user instanceof User) {
159 3
            $recommendedMovies = $repository->findAllByMovieAndUser($movie->getId(), $user->getId());
160
        } else {
161
            $recommendedMovies = $repository->findAllByMovie($movie->getId());
162
        }
163
164 3
        $recommendedMovies = new PaginatedCollection($recommendedMovies, $offset, $limit, false);
165
166 3
        return $this->response($recommendedMovies, 200, [], [
167 3
            'groups' => ['list'],
168
        ]);
169
    }
170
171
    /**
172
     * Get movies by title.
173
     *
174
     * @Route("/api/movies/{id}/recommendations/search", methods={"POST"})
175
     *
176
     * @param int           $id
177
     * @param SearchRequest $request
178
     * @param SearchService $searchService
179
     * @param Request       $currentRequest
180
     *
181
     * @throws \App\Movies\Exception\TmdbMovieNotFoundException
182
     * @throws \App\Movies\Exception\TmdbRequestLimitException
183
     * @throws \ErrorException
184
     * @throws \Psr\SimpleCache\InvalidArgumentException
185
     *
186
     * @return \Symfony\Component\HttpFoundation\JsonResponse
187
     */
188
    public function getSearch(int $id, SearchRequest $request, SearchService $searchService, Request $currentRequest)
189
    {
190
        $offset = (int) $request->get('offset', 0);
191
        $limit = $request->get('limit', null);
192
193
        $query = $request->get('query');
194
195
        if (null === $user = $this->getUser()) {
196
            $movies = $searchService->findByQuery($query, $currentRequest->getLocale(), $offset, $limit);
197
        } else {
198
            $movies = $searchService->findByQueryWithUserRecommendedMovie($query, $id, $user->getId(), $currentRequest->getLocale(), $offset, $limit);
199
        }
200
201
        return $this->response($movies, 200, [], [
202
            'groups' => ['list'],
203
        ]);
204
    }
205
}
206