TweetRepository   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 7
dl 0
loc 214
ccs 96
cts 96
cp 1
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getWithUsers() 0 22 1
A getWithUsersAndMediasQuery() 0 19 1
A getWithUsersAndMedias() 0 14 2
A getTweetId() 0 19 2
A getPreviousTweetId() 0 4 1
A getNextTweetId() 0 4 1
A countPendingTweets() 0 21 2
A getLastTweet() 0 9 1
A getTweetsLessThanId() 0 21 1
A removeOrphanMedias() 0 6 2
A removeTweet() 0 18 3
A deleteAndHideTweetsLessThanId() 0 21 3
1
<?php
2
3
namespace AlexisLefebvre\Bundle\AsyncTweetsBundle\Entity;
4
5
use Doctrine\ORM\EntityRepository;
6
use Doctrine\ORM\QueryBuilder;
7
8
/**
9
 * TweetRepository.
10
 *
11
 * This class was generated by the Doctrine ORM. Add your own custom
12
 * repository methods below.
13
 *
14
 * @extends \Doctrine\ORM\EntityRepository<Tweet>
15
 */
16
class TweetRepository extends EntityRepository
17
{
18
    const TWEETS_PER_PAGE = 5;
19
20
    /**
21
     * @return int|mixed|string
22
     */
23 3
    public function getWithUsers(int $page = 1)
24
    {
25 3
        $firstResult = (($page - 1) * self::TWEETS_PER_PAGE);
26
27 3
        $qb = $this->createQueryBuilder('t');
28
29
        $query = $qb
30 3
            ->select('t, user, rt, rt_user')
31 3
            ->innerJoin('t.user', 'user')
32 3
            ->leftJoin('t.retweeted_status', 'rt')
33 3
            ->leftJoin('rt.user', 'rt_user')
34
35
            // Ignore tweets that were only retweeted
36 3
            ->where($qb->expr()->eq('t.in_timeline', 'true'))
37
38 3
            ->orderBy('t.id', 'DESC')
39
40 3
            ->setFirstResult($firstResult)
41 3
            ->setMaxResults(self::TWEETS_PER_PAGE);
42
43 3
        return $query->getQuery()->getResult();
44
    }
45
46 8
    private function getWithUsersAndMediasQuery(QueryBuilder $qb): QueryBuilder
47
    {
48
        $query = $qb
49 8
            ->select('t, user, medias, rt, rt_user')
50 8
            ->innerJoin('t.user', 'user')
51 8
            ->leftJoin('t.medias', 'medias')
52 8
            ->leftJoin('t.retweeted_status', 'rt')
53 8
            ->leftJoin('rt.user', 'rt_user')
54
55
            // Ignore tweets that were only retweeted
56 8
            ->where($qb->expr()->eq('t.in_timeline', 'true'))
57
58 8
            ->orderBy('t.id', 'ASC')
59
60 8
            ->setFirstResult(0)
61 8
            ->setMaxResults(self::TWEETS_PER_PAGE);
62
63 8
        return $query;
64
    }
65
66
    /**
67
     * @return array<Tweet>
68
     */
69 8
    public function getWithUsersAndMedias(?int $firstTweetId = null): array
70
    {
71 8
        $qb = $this->createQueryBuilder('t');
72
73 8
        $query = $this->getWithUsersAndMediasQuery($qb);
74
75 8
        if (!is_null($firstTweetId)) {
76 5
            $query = $query->andWhere(
77 5
                $qb->expr()->gte('t.id', $firstTweetId)
78
            );
79
        }
80
81 8
        return $query->getQuery()->getResult();
82
    }
83
84 6
    private function getTweetId(string $condition, string $order, int $tweetId): ?int
85
    {
86 6
        $qb = $this->createQueryBuilder('t')
87 6
            ->select('t.id')
88
89 6
            ->where('t.id '.$condition.' :tweetId')
90 6
            ->setParameter(':tweetId', $tweetId)
91
92 6
            ->andWhere('t.in_timeline = true')
93
94 6
            ->orderBy('t.id', $order)
95
96 6
            ->setFirstResult(self::TWEETS_PER_PAGE - 1)
97 6
            ->setMaxResults(1);
98
99 6
        $result = $qb->getQuery()->getOneOrNullResult();
100
101 6
        return is_array($result) ? $result['id'] : null;
102
    }
103
104 6
    public function getPreviousTweetId(int $tweetId): ?int
105
    {
106 6
        return $this->getTweetId('<', 'DESC', $tweetId);
107
    }
108
109 6
    public function getNextTweetId(int $tweetId): ?int
110
    {
111 6
        return $this->getTweetId('>', 'ASC', $tweetId);
112
    }
113
114 7
    public function countPendingTweets(?int $lastTweetId = null): int
115
    {
116
        /** @var \Doctrine\ORM\QueryBuilder $qb */
117 7
        $qb = $this->createQueryBuilder('t');
118
119
        $query = $qb
120 7
            ->add('select', $qb->expr()->count('t.id'))
121
            // Ignore tweets that were only retweeted
122 7
            ->where(
123 7
                $qb->expr()->eq('t.in_timeline', 'true')
124
            );
125
126 7
        if (!is_null($lastTweetId)) {
127 7
            $query = $query->andWhere(
128 7
                $qb->expr()->gte('t.id', $lastTweetId)
129
            );
130
        }
131
132
        // return result of "COUNT()" query
133 7
        return $query->getQuery()->getSingleScalarResult();
134
    }
135
136 7
    public function getLastTweet(): ?Tweet
137
    {
138 7
        $qb = $this->createQueryBuilder('t')
139 7
            ->addOrderBy('t.id', 'DESC')
140 7
            ->setFirstResult(0)
141 7
            ->setMaxResults(1);
142
143 7
        return $qb->getQuery()->getOneOrNullResult();
144
    }
145
146
    /**
147
     * @return array<Tweet>
148
     */
149 2
    private function getTweetsLessThanId(int $tweetId): array
150
    {
151 2
        $qb = $this->createQueryBuilder('t')
152 2
            ->select('t, m')
153 2
            ->leftJoin('t.medias', 'm')
154 2
            ->where('t.id < :tweetId')
155 2
            ->setParameter(':tweetId', $tweetId)
156
157
            // Get retweeted tweets (it would break foreign keys)
158
            //  http://stackoverflow.com/questions/15087933/how-to-do-left-join-in-doctrine/15088250#15088250
159 2
            ->leftJoin(
160 2
                'AsyncTweetsBundle:Tweet',
161 2
                't2',
162 2
                'WITH',
163 2
                't.id = t2.retweeted_status'
164
            )
165
166 2
            ->orderBy('t.id', 'DESC');
167
168 2
        return $qb->getQuery()->getResult();
169
    }
170
171
    /**
172
     * Remove Media not associated to any Tweet.
173
     */
174 1
    private function removeOrphanMedias(Media $media): void
175
    {
176 1
        if (count($media->getTweets()) == 0) {
177 1
            $this->_em->remove($media);
178
        }
179 1
    }
180
181
    /**
182
     * Remove the tweet and return 1 is the deleted tweet is not a
183
     *  retweet.
184
     */
185 2
    protected function removeTweet(Tweet $tweet): int
186
    {
187 2
        $count = 0;
188
189 2
        foreach ($tweet->getMedias() as $media) {
190 1
            $tweet->removeMedia($media);
191 1
            $this->removeOrphanMedias($media);
192
        }
193
194
        // Don't count tweets that were only retweeted
195 2
        if ($tweet->isInTimeline()) {
196 2
            $count = 1;
197
        }
198
199 2
        $this->_em->remove($tweet);
200
201 2
        return $count;
202
    }
203
204
    /**
205
     * Delete tweets and return the number of deleted tweets (excluding
206
     *  retweeted-only tweets).
207
     */
208 2
    public function deleteAndHideTweetsLessThanId(int $tweetId): int
209
    {
210 2
        $count = 0;
211
212 2
        $tweets = $this->getTweetsLessThanId($tweetId);
213
214 2
        foreach ($tweets as $tweet) {
215 2
            if ($tweet->mustBeKept($tweetId)) {
216
                // The Tweet is still in the timeline, it can only be hidden
217 1
                $tweet->setInTimeline(false);
218 1
                $this->_em->persist($tweet);
219
            } else {
220
                // The Tweet has not been retweeted, it can be removed
221 2
                $count += $this->removeTweet($tweet);
222
            }
223
        }
224
225 2
        $this->_em->flush();
226
227 2
        return $count;
228
    }
229
}
230