WatchedMovieProcessor::recreateGuestWatchedMovie()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
namespace App\Movies\EventListener;
4
5
use App\Genres\Entity\Genre;
6
use App\Guests\Entity\GuestSession;
7
use App\Guests\Entity\GuestWatchedMovie;
8
use App\Movies\Entity\Movie;
9
use App\Movies\Entity\WatchedMovie;
10
use App\Users\Entity\User;
11
use App\Users\Entity\UserWatchedMovie;
12
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Enqueue\Client\TopicSubscriberInterface;
15
use Interop\Queue\Context;
16
use Interop\Queue\Message as QMessage;
17
use Interop\Queue\Processor;
18
use Psr\Log\LoggerInterface;
19
20
// Looks like here some logic problem
21
// todo construct entities by params from message here instead of create each of them with correct associations
22
// TODO IMPORTANT
23
class WatchedMovieProcessor implements Processor, TopicSubscriberInterface
24
{
25
    public const ADD_WATCHED_MOVIE_TMDB = 'addWatchedMovieTMDB';
26
27
    private $em;
28
    private $logger;
29
30 1
    public function __construct(EntityManagerInterface $em, LoggerInterface $logger)
31
    {
32 1
        $this->em = $em;
33 1
        $this->logger = $logger;
34 1
    }
35
36
    /**
37
     * This method called when user or guest trying to add movie to own list of watched movies but we do not have this movie in our db yet.
38
     *
39
     * @param QMessage $message
40
     * @param Context  $session
41
     *
42
     * @throws \Doctrine\ORM\ORMException|\Exception
43
     *
44
     * @return object|string
45
     */
46 1
    public function process(QMessage $message, Context $session)
47
    {
48 1
        $watchedMovies = $message->getBody();
49 1
        $watchedMovies = unserialize($watchedMovies);
50 1
        $validClasses = [UserWatchedMovie::class, GuestWatchedMovie::class];
51
52 1
        if ($this->em->isOpen() === false) {
53
            throw new \ErrorException('em is closed');
54
        }
55
56
        /** @var $watchedMovies UserWatchedMovie[]|GuestWatchedMovie[] */
57 1
        foreach ($watchedMovies as $watchedMovie) {
58 1
            if (\in_array(\get_class($watchedMovie), $validClasses, true) === false) {
59
                $this->logger->error('Unexpected behavior: $watchedMovie not in range of valid classes', [
60
                    'actualClass' => \get_class($watchedMovie),
61
                ]);
62
                continue;
63
            }
64
65 1
            $movie = $watchedMovie->getMovie(); // Not saved movie
66 1
            $movie = $this->refreshGenresAssociations($movie);
67 1
            $newWatchedMovie = $this->recreateWatchedMovie($watchedMovie, $movie);
68
69 1
            $this->em->persist($movie);
70 1
            $this->em->persist($newWatchedMovie);
71
        }
72
73
        try {
74 1
            $this->em->flush();
75
        } catch (UniqueConstraintViolationException $exception) {
76
            $this->logger->error('UniqueConstraintViolationException when we are trying to save watched movie', [
77
                'message' => $exception->getMessage(),
78
            ]);
79 1
        } finally {
80 1
            $this->em->clear();
81
        }
82
83 1
        return self::ACK;
84
    }
85
86
    /**
87
     * @param WatchedMovie $watchedMovie
88
     * @param Movie        $movie
89
     *
90
     * @throws \Doctrine\ORM\ORMException
91
     *
92
     * @return WatchedMovie
93
     */
94 1
    private function recreateWatchedMovie(WatchedMovie $watchedMovie, Movie $movie): WatchedMovie
95
    {
96
        // Recreate *WatchedMovie entity with new managed by doctrine associations
97 1
        if ($watchedMovie instanceof UserWatchedMovie) {
98 1
            $newWatchedMovie = $this->recreateUserWatchedMovie($watchedMovie, $movie);
99
        }
100
101 1
        if ($watchedMovie instanceof GuestWatchedMovie) {
102
            $newWatchedMovie = $this->recreateGuestWatchedMovie($watchedMovie, $movie);
103
        }
104
105 1
        if (!isset($newWatchedMovie)) {
106
            throw new \LogicException('Watched movie not a valid child class of WatchedMovie');
107
        }
108
109 1
        return $newWatchedMovie;
110
    }
111
112
    /**
113
     * @param UserWatchedMovie $userWatchedMovie
114
     * @param Movie            $movie
115
     *
116
     * @throws \Doctrine\ORM\ORMException|\Exception
117
     *
118
     * @return UserWatchedMovie
119
     */
120 1
    private function recreateUserWatchedMovie(UserWatchedMovie $userWatchedMovie, Movie $movie): UserWatchedMovie
121
    {
122
        /** @var $userReference User */
123 1
        $userReference = $this->em->getReference(User::class, $userWatchedMovie->getUser()->getId());
124
125 1
        return new UserWatchedMovie($userReference, $movie, $userWatchedMovie->getVote(), $userWatchedMovie->getWatchedAt());
126
    }
127
128
    /**
129
     * @param GuestWatchedMovie $guestWatchedMovie
130
     * @param Movie             $movie
131
     *
132
     * @throws \Doctrine\ORM\ORMException|\Exception
133
     *
134
     * @return GuestWatchedMovie
135
     */
136
    private function recreateGuestWatchedMovie(GuestWatchedMovie $guestWatchedMovie, Movie $movie): GuestWatchedMovie
137
    {
138
        /** @var $guestSessionReference GuestSession */
139
        $guestSessionReference = $this->em->getReference(GuestSession::class, $guestWatchedMovie->getGuestSession()->getId());
140
141
        return new GuestWatchedMovie($guestSessionReference, $movie, $guestWatchedMovie->getVote(), $guestWatchedMovie->getWatchedAt());
142
    }
143
144
    /**
145
     * @param Movie $movie
146
     *
147
     * @throws \Doctrine\ORM\ORMException
148
     *
149
     * @return Movie
150
     */
151 1
    private function refreshGenresAssociations(Movie $movie): Movie
152
    {
153 1
        $genres = $movie->getGenres();
154 1
        $movie->removeAllGenres(); // Because doctrine doesn't know about these genres due unserialization
155
156 1
        foreach ($genres as $genre) {
157
            /** @var $genreReference Genre */
158 1
            $genreReference = $this->em->getReference(Genre::class, $genre->getId()); // so we need to re-add 'em
159 1
            $movie->addGenre($genreReference);
160
        }
161
162 1
        return $movie;
163
    }
164
165
    public static function getSubscribedTopics()
166
    {
167
        return [self::ADD_WATCHED_MOVIE_TMDB];
168
    }
169
}
170