AlbumRepository::findEmptyAlbums()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 9.7666
cc 1
nc 1
nop 1
crap 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