• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fnagel / t3extblog / 24024426271

04 Apr 2026 03:45PM UTC coverage: 50.089%. First build
24024426271

push

github

fnagel
[TASK] Improve tags repository method

0 of 2 new or added lines in 1 file covered. (0.0%)

1681 of 3356 relevant lines covered (50.09%)

4.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.29
/Classes/Domain/Repository/PostRepository.php
1
<?php
2

3
namespace FelixNagel\T3extblog\Domain\Repository;
4

5
/**
6
 * This file is part of the "t3extblog" Extension for TYPO3 CMS.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11

12
use Doctrine\DBAL\ParameterType;
13
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
14
use TYPO3\CMS\Core\Utility\GeneralUtility;
15
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
16
use FelixNagel\T3extblog\Domain\Model\BackendUser;
17
use FelixNagel\T3extblog\Domain\Model\Category;
18
use FelixNagel\T3extblog\Domain\Model\Post;
19
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
20

21
/**
22
 * @SuppressWarnings("PHPMD.TooManyPublicMethods")
23
 */
24
class PostRepository extends AbstractRepository
25
{
26
    protected $defaultOrderings = [
27
        'publishDate' => QueryInterface::ORDER_DESCENDING,
28
    ];
29

30
    /**
31
     * Override default findByUid function to enable also the option to turn of
32
     * the enableField setting.
33
     */
34
    public function findByUid($uid, bool $respectEnableFields = true): ?Post
8✔
35
    {
36
        $query = $this->createQuery();
8✔
37

38
        $query->getQuerySettings()->setRespectStoragePage(false);
8✔
39
        $query->getQuerySettings()->setRespectSysLanguage(false);
8✔
40
        $query->getQuerySettings()->setIgnoreEnableFields(!$respectEnableFields);
8✔
41

42
        $query->matching(
8✔
43
            $query->logicalAnd(
8✔
44
                $query->equals('uid', $uid),
8✔
45
                $query->equals('deleted', 0)
8✔
46
            )
8✔
47
        );
8✔
48

49
        return $query->execute()->getFirst();
8✔
50
    }
51

52
    /**
53
     * Gets localized post by uid. No overlay.
54
     */
55
    public function findByLocalizedUid(int $uid, bool $respectEnableFields = true): ?Post
19✔
56
    {
57
        $table = $this->getTableName();
19✔
58
        $queryBuilder = $this->getQueryBuilder($table);
19✔
59

60
        if (!$respectEnableFields) {
19✔
61
            $queryBuilder
×
62
                ->getRestrictions()
×
63
                ->removeAll()
×
64
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
×
65
        }
66

67
        $queryBuilder
19✔
68
            ->select('post.*')
19✔
69
            ->from($table, 'post')
19✔
70
            ->where(
19✔
71
                $queryBuilder->expr()->eq(
19✔
72
                    'uid',
19✔
73
                    $queryBuilder->createNamedParameter($uid, ParameterType::INTEGER)
19✔
74
                ),
19✔
75
            )
19✔
76
            ->setMaxResults(1)
19✔
77
        ;
19✔
78

79
        return $this->createQuery()->statement($queryBuilder->getSQL(), $queryBuilder->getParameters())
19✔
80
            ->execute()
19✔
81
            ->getFirst();
19✔
82
    }
83

84
    /**
85
     * Get next post.
86
     */
87
    public function nextPost(Post $post): ?Post
11✔
88
    {
89
        $query = $this->createQuery();
11✔
90

91
        $query->setOrderings(
11✔
92
            ['publishDate' => QueryInterface::ORDER_ASCENDING]
11✔
93
        );
11✔
94

95
        $query->matching($query->greaterThan('publishDate', $post->getPublishDate()));
11✔
96

97
        return $query->execute()->getFirst();
11✔
98
    }
99

100
    /**
101
     * Get previous post.
102
     */
103
    public function previousPost(Post $post): ?Post
11✔
104
    {
105
        $query = $this->createQuery();
11✔
106

107
        $query->matching($query->lessThan('publishDate', $post->getPublishDate()));
11✔
108

109
        return $query->execute()->getFirst();
11✔
110
    }
111

112
    /**
113
     * Get related posts.
114
     */
115
    public function relatedPosts(Post $post): ?QueryResultInterface
13✔
116
    {
117
        $query = $this->createQuery();
13✔
118

119
        $constraints = [];
13✔
120
        foreach ($post->getTagCloud() as $tag) {
13✔
121
            $constraints[] = $query->like('tagCloud', '%'.$this->escapeStrForLike($tag).'%');
13✔
122
        }
123

124
        $query->matching($query->logicalAnd(
13✔
125
            $query->logicalNot($query->equals('uid', $post->getUid())),
13✔
126
            $query->logicalOr(...$constraints)
13✔
127
        ));
13✔
128

129
        return $query->execute();
13✔
130
    }
131

132
    /**
133
     * Find all or filtered by tag, category or author.
134
     */
135
    public function findByFilter($filter = null): ?QueryResultInterface
22✔
136
    {
137
        if ($filter === null) {
22✔
138
            return $this->findAll();
17✔
139
        }
140

141
        if ($filter instanceof BackendUser) {
5✔
142
            return $this->findBy(['author' => $filter]);
1✔
143
        }
144

145
        if ($filter instanceof Category) {
4✔
146
            return $this->findByCategory($filter);
2✔
147
        }
148

149
        if (is_int($filter)) {
2✔
150
            return $this->findByYear($filter);
1✔
151
        }
152

153
        if (is_string($filter)) {
1✔
154
            return $this->findByTag($filter);
1✔
155
        }
156

157
        return null;
×
158
    }
159

160
    /**
161
     * Finds posts by the specified tag.
162
     */
163
    public function findByTag(string $tag): QueryResultInterface
4✔
164
    {
165
        $query = $this->createQuery();
4✔
166

167
        $query->matching(
4✔
168
            $query->like('tagCloud', '%'.$this->escapeStrForLike($tag).'%')
4✔
169
        );
4✔
170

171
        return $query->execute();
4✔
172
    }
173

174
    /**
175
     * Returns all objects of this repository with a matching category.
176
     */
177
    public function findByCategory(Category $category): QueryResultInterface
3✔
178
    {
179
        $query = $this->createQuery();
3✔
180

181
        $constraints = [];
3✔
182
        $constraints[] = $query->contains('categories', $category);
3✔
183

184
        $categories = $category->getChildCategories();
3✔
185

186
        if (!is_null($categories) && count($categories) > 0) {
3✔
187
            foreach ($categories as $childCategory) {
3✔
188
                $constraints[] = $query->contains('categories', $childCategory);
3✔
189
            }
190
        }
191

192
        $query->matching($query->logicalOr(...$constraints));
3✔
193

194
        return $query->execute();
3✔
195
    }
196

197
    /**
198
     * Returns all hidden posts of a time frame from now.
199
     */
200
    public function findDrafts(int $pid = 0, ?int $limit = null, string $until = '-12 months'): QueryResultInterface
1✔
201
    {
202
        $query = $this->createQuery($pid);
1✔
203
        $query->getQuerySettings()->setIgnoreEnableFields(true);
1✔
204

205
        if (is_int($limit) && $limit >= 1) {
1✔
206
            $query->setLimit($limit);
×
207
        }
208

209
        $date = new \DateTime();
1✔
210
        $date->modify($until);
1✔
211

212
        $query->matching(
1✔
213
            $query->logicalAnd(
1✔
214
                $query->equals('hidden', 1),
1✔
215
                $query->equals('deleted', 0),
1✔
216
                $query->greaterThanOrEqual('crdate', $date->getTimestamp())
1✔
217
            )
1✔
218
        );
1✔
219

220
        return $query->execute();
1✔
221
    }
222

223
    /**
224
     * Get tag cloud.
225
     *
226
     * @return array{tag: string, posts: int}[]
227
     */
NEW
228
    public function tagCloud(int $limit = 10, int $minimum = 2): array
×
229
    {
230
        $table = $this->getTableName();
×
231
        $connection = $this->getConnection($table);
×
232
        $query = 'WITH RECURSIVE all_tags AS (
×
233
            SELECT uid, TRIM(SUBSTRING_INDEX(tagClouds, ",", 1)) AS tag,
234
            SUBSTRING(tagClouds, LENGTH(SUBSTRING_INDEX(tagClouds, ",", 1)) + 2) AS rest
235
            FROM '.$table.'
×
236
            WHERE tagClouds IS NOT NULL AND tagClouds <> "" AND '.$this->getFeEnableFields($table).'
×
237

238
            UNION ALL
239

240
            SELECT uid, TRIM(SUBSTRING_INDEX(rest, ",", 1)) AS tag,
241
            CASE
242
                WHEN rest LIKE "%,%" THEN SUBSTRING(rest, LENGTH(SUBSTRING_INDEX(rest, ",", 1)) + 2)
243
            ELSE ""
244
            END AS rest
245
            FROM all_tags
246
            WHERE rest <> ""
247
        )
248
        SELECT tag as title, COUNT(*) AS posts
249
        FROM all_tags
250
        GROUP BY tag
251
        HAVING posts >= :minimum
252
        ORDER BY posts DESC
253
        LIMIT :limit';
×
254

255
        $params = [
×
256
            'limit' => $limit,
×
257
            'minimum' => $minimum,
×
258
        ];
×
259

260
        $query = $connection->executeQuery($query, $params);
×
NEW
261
        $result = $query->fetchAllAssociative() ?: [];
×
262
        $query->free();
×
263

264
        return $result;
×
265
    }
266

267
    /**
268
     * @return null|array{year: int, count: int}[]
269
     */
270
    public function findYears(): ?array
2✔
271
    {
272
        $table = $this->getTableName();
2✔
273
        $connection = $this->getConnection($table);
2✔
274

275
        $yearExpr = $this->isSQLite($table)
2✔
276
            ? "CAST(strftime('%Y', date, 'unixepoch') AS INTEGER)"
2✔
277
            : 'YEAR(FROM_UNIXTIME(date))';
×
278
        $query = 'SELECT ' . $yearExpr . ' AS year, COUNT(uid) AS count FROM ' . $table .
2✔
279
            ' WHERE ' . $this->getFeEnableFields($table) . ' GROUP BY year ORDER BY year DESC';
2✔
280

281
        $query = $connection->executeQuery($query);
2✔
282
        $result = $query->fetchAllAssociative() ?: null;
2✔
283
        $query->free();
2✔
284

285
        return $result;
2✔
286
    }
287

288
    public function findByYear(int $year): QueryResultInterface
1✔
289
    {
290
        $until = new \DateTime();
1✔
291
        $until->modify('midnight first day of January '.$year);
1✔
292

293
        $from = clone $until;
1✔
294
        $from->modify('+1 year - 1 second');
1✔
295

296
        return $this->getDateQueryBuilder($until, $from)->execute();
1✔
297
    }
298

299
    protected function getDateQueryBuilder(\DateTime $until, ?\DateTime $from = null): QueryInterface
1✔
300
    {
301
        $query = $this->createQuery();
1✔
302
        $constraints = [
1✔
303
            $query->greaterThanOrEqual('publishDate', $until->getTimestamp()),
1✔
304
        ];
1✔
305

306
        if ($from !== null) {
1✔
307
            $constraints[] = $query->lessThanOrEqual('publishDate', $from->getTimestamp());
1✔
308
        }
309

310
        $query->matching($query->logicalAnd(...$constraints));
1✔
311

312
        return $query;
1✔
313
    }
314
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc