AlbumRepository   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
eloc 112
dl 0
loc 204
ccs 126
cts 126
cp 1
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A delete() 0 6 1
A getListOrderedByArtist() 0 26 3
A search() 0 14 1
A findByGenre() 0 43 3
A findEmptyAlbums() 0 19 1
A prototype() 0 3 1
A getFavorites() 0 49 2
A findByMbId() 0 4 1
A save() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Uxmp\Core\Orm\Repository;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Criteria;
9
use Doctrine\ORM\EntityRepository;
10
use Doctrine\ORM\Query\Expr\Join;
11
use Doctrine\ORM\Query\Parameter;
12
use Generator;
13
use Uxmp\Core\Orm\Model\Album;
14
use Uxmp\Core\Orm\Model\AlbumInterface;
15
use Uxmp\Core\Orm\Model\Artist;
16
use Uxmp\Core\Orm\Model\CatalogInterface;
17
use Uxmp\Core\Orm\Model\Disc;
18
use Uxmp\Core\Orm\Model\Favorite;
19
use Uxmp\Core\Orm\Model\FavoriteItemTypeEnum;
20
use Uxmp\Core\Orm\Model\GenreInterface;
21
use Uxmp\Core\Orm\Model\GenreMap;
22
use Uxmp\Core\Orm\Model\GenreMapEnum;
23
use Uxmp\Core\Orm\Model\UserInterface;
24
25
/**
26
 * @extends EntityRepository<Album>
27
 *
28
 * @method AlbumInterface[] findBy(mixed[] $criteria, null|array $order = null, null|int $limit = null, null|int $offset = null)
29
 * @method null|AlbumInterface find(int $id)
30
 */
31
final class AlbumRepository extends EntityRepository implements AlbumRepositoryInterface
32
{
33 1
    public function prototype(): AlbumInterface
34
    {
35 1
        return new Album();
36
    }
37
38 1
    public function save(AlbumInterface $album): void
39
    {
40 1
        $em = $this->getEntityManager();
41
42 1
        $em->persist($album);
43 1
        $em->flush();
44
    }
45
46 1
    public function findByMbId(string $mbid): ?AlbumInterface
47
    {
48 1
        return $this->findOneBy([
49 1
            'mbid' => $mbid,
50 1
        ]);
51
    }
52
53
    /**
54
     * Returns albums having a certain genre
55
     *
56
     * @return Generator<AlbumInterface>
57
     */
58 1
    public function findByGenre(
59
        GenreInterface $genre,
60
        ?int $limit = null,
61
        ?int $offset = null,
62
        ?int $catalogId = null,
63
    ): Generator {
64 1
        $queryBuilder = $this->createQueryBuilder('a');
65 1
        $subQueryBuilder = $this
66 1
            ->getEntityManager()
67 1
            ->createQueryBuilder();
68 1
        $expressionBuilder = $this
69 1
            ->getEntityManager()
70 1
            ->getExpressionBuilder();
71
72 1
        $andExpression = $expressionBuilder->andX();
73 1
        $andExpression->add($expressionBuilder->eq('genre_map.genre', ':genre'));
74 1
        $andExpression->add($expressionBuilder->eq('genre_map.mapped_item_type', ':genreType'));
75
76 1
        $queryBuilder
77 1
            ->where(
78 1
                $expressionBuilder->in(
79 1
                    'a.id',
80 1
                    $subQueryBuilder
81 1
                        ->select('genre_map.mapped_item_id')
82 1
                        ->from(GenreMap::class, 'genre_map')
83 1
                        ->where($andExpression)
84 1
                        ->getDQL()
85 1
                )
86 1
            )
87 1
            ->setFirstResult($offset)
88 1
            ->setMaxResults($limit)
89 1
            ->orderBy('a.title', 'ASC')
90 1
            ->setParameter('genre', $genre)
91 1
            ->setParameter('genreType', GenreMapEnum::ALBUM)
92 1
        ;
93
94 1
        if ($catalogId !== null) {
95 1
            $queryBuilder->andWhere('catalog_id = :catalogId');
96 1
            $queryBuilder->setParameter('catalogId', $catalogId);
97
        }
98
99 1
        foreach ($queryBuilder->getQuery()->toIterable() as $item) {
100 1
            yield $item;
101
        }
102
    }
103
104 1
    public function delete(AlbumInterface $album): void
105
    {
106 1
        $em = $this->getEntityManager();
107
108 1
        $em->remove($album);
109 1
        $em->flush();
110
    }
111
112
    /**
113
     * @return iterable<AlbumInterface>
114
     */
115 1
    public function getFavorites(
116
        UserInterface $user,
117
        ?CatalogInterface $catalog = null,
118
        ?int $limit = null,
119
        ?int $offset = null
120
    ): iterable {
121 1
        $parameter = [
122 1
            new Parameter('user', $user),
123 1
            new Parameter('type', FavoriteItemTypeEnum::ALBUM),
124 1
        ];
125
126 1
        $qb = $this
127 1
            ->getEntityManager()
128 1
            ->createQueryBuilder();
129 1
        $qbSub = $this
130 1
            ->getEntityManager()
131 1
            ->createQueryBuilder();
132 1
        $expressionBuilder = $this
133 1
            ->getEntityManager()
134 1
            ->getExpressionBuilder();
135
136 1
        $andExpression = $expressionBuilder->andX();
137 1
        $andExpression->add($expressionBuilder->eq('fav.user', ':user'));
138 1
        $andExpression->add($expressionBuilder->eq('fav.type', ':type'));
139 1
        if ($catalog !== null) {
140 1
            $andExpression->add($expressionBuilder->eq('a.catalog', ':catalog'));
141
142 1
            $parameter[] = new Parameter('catalog', $catalog);
143
        }
144
145 1
        $qb
146 1
            ->select('a')
147 1
            ->from(Album::class, 'a')
148 1
            ->where(
149 1
                $expressionBuilder->in(
150 1
                    'a.id',
151 1
                    $qbSub
152 1
                        ->select('fav.item_id')
153 1
                        ->from(Favorite::class, 'fav')
154 1
                        ->where($andExpression)
155 1
                        ->getDQL()
156 1
                )
157 1
            )
158 1
            ->setParameters(new ArrayCollection($parameter))
159 1
            ->orderBy('a.title', 'ASC')
160 1
            ->setMaxResults($limit)
161 1
            ->setFirstResult($offset);
162
163 1
        return $qb->getQuery()->getResult();
164
    }
165
166 1
    public function findEmptyAlbums(CatalogInterface $catalog): iterable
167
    {
168 1
        $query = <<<SQL
169
            SELECT album
170
            FROM %s album
171
            LEFT JOIN %s disc 
172
            WITH disc.album_id = album.id
173
            WHERE album.catalog_id = %d
174
            GROUP BY album HAVING COUNT(disc.id) = 0
175 1
            SQL;
176
177 1
        return $this->getEntityManager()
178 1
            ->createQuery(sprintf(
179 1
                $query,
180 1
                Album::class,
181 1
                Disc::class,
182 1
                $catalog->getId(),
183 1
            ))
184 1
            ->getResult();
185
    }
186
187
    /**
188
     * Returns an ordered list by the albums artist
189
     *
190
     * @return Generator<AlbumInterface>
191
     */
192 1
    public function getListOrderedByArtist(
193
        null|int $limit = null,
194
        null|int $offset = null,
195
        ?int $catalogId = null,
196
    ): Generator {
197 1
        $query_builder = $this
198 1
            ->createQueryBuilder('ab')
199 1
            ->leftJoin(
200 1
                Artist::class,
201 1
                'ac',
202 1
                Join::WITH,
203 1
                'ac.id = ab.artist_id'
204 1
            )
205 1
            ->setFirstResult($offset)
206 1
            ->setMaxResults($limit)
207 1
            ->addOrderBy('ac.title', Criteria::ASC)
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\Common\Collections\Criteria::ASC has been deprecated: use Order::Ascending instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

207
            ->addOrderBy('ac.title', /** @scrutinizer ignore-deprecated */ Criteria::ASC)

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
208 1
            ->addOrderBy('ab.title', Criteria::ASC)
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\Common\Collections\Criteria::ASC has been deprecated: use Order::Ascending instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

208
            ->addOrderBy('ab.title', /** @scrutinizer ignore-deprecated */ Criteria::ASC)

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
209 1
        ;
210
211 1
        if ($catalogId !== null) {
212 1
            $query_builder->where('ab.catalog_id = :catalogId');
213 1
            $query_builder->setParameter('catalogId', $catalogId);
214
        }
215
216 1
        foreach ($query_builder->getQuery()->toIterable() as $album) {
217 1
            yield $album;
218
        }
219
    }
220
221 1
    public function search(string $searchTerm): array
222
    {
223 1
        $qb = $this->getEntityManager()->createQueryBuilder();
224
225 1
        $qb
226 1
            ->select('a')
227 1
            ->from(Album::class, 'a')
228 1
            ->where(
229 1
                $qb->expr()->like('a.searchTitle', ':searchTerm')
230 1
            )
231 1
            ->setParameter('searchTerm', sprintf('%%%s%%', mb_strtolower($searchTerm)))
232 1
        ;
233
234 1
        return $qb->getQuery()->getResult();
235
    }
236
}
237