ArchiveRepository   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 96
Duplicated Lines 0 %

Test Coverage

Coverage 61.7%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 42
c 2
b 1
f 0
dl 0
loc 96
ccs 29
cts 47
cp 0.617
rs 10
wmc 9

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getMonthlyArchive() 0 9 1
A getFullArchive() 0 15 1
A select() 0 3 1
A getDriver() 0 8 1
A __construct() 0 5 1
A extractFromDateColumn() 0 9 2
A prepareDataReader() 0 3 1
A getYearlyArchive() 0 11 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Blog\Archive;
6
7
use App\Blog\Entity\Post;
8
use App\Blog\Post\PostRepository;
9
use Cycle\ORM\ORMInterface;
10
use Cycle\ORM\Select;
11
use Spiral\Database\DatabaseInterface;
12
use Spiral\Database\Driver\DriverInterface;
13
use Spiral\Database\Driver\SQLite\SQLiteDriver;
14
use Spiral\Database\Injection\Fragment;
15
use Spiral\Database\Injection\FragmentInterface;
16
use Spiral\Database\Query\SelectQuery;
17
use Yiisoft\Data\Reader\DataReaderInterface;
18
use Yiisoft\Data\Reader\Sort;
19
use Yiisoft\Yii\Cycle\Data\Reader\EntityReader;
20
21
/**
22
 * This repository is not associated with Post entity
23
 */
24
final class ArchiveRepository
25
{
26
    private PostRepository $postRepo;
27
28 1
    public function __construct(ORMInterface $orm)
29
    {
30
        /** @var PostRepository $postRepo */
31 1
        $postRepo = $orm->getRepository(Post::class);
32 1
        $this->postRepo = $postRepo;
33 1
    }
34
35 1
    public function select(): Select
36
    {
37 1
        return $this->postRepo->select();
38
    }
39
40
    public function getMonthlyArchive(int $year, int $month): DataReaderInterface
41
    {
42
        $begin = (new \DateTimeImmutable())->setDate($year, $month, 1)->setTime(0, 0, 0);
43
        $end = $begin->setDate($year, $month + 1, 1)->setTime(0, 0, -1);
44
45
        $query = $this->select()
46
                    ->andWhere('published_at', 'between', $begin, $end)
47
                    ->load(['user', 'tags']);
48
        return $this->prepareDataReader($query);
49
    }
50
51
    public function getYearlyArchive(int $year): DataReaderInterface
52
    {
53
        $begin = (new \DateTimeImmutable())->setDate($year, 1, 1)->setTime(0, 0, 0);
54
        $end = $begin->setDate($year + 1, 1, 1)->setTime(0, 0, -1);
55
56
        $query = $this
57
            ->select()
58
            ->andWhere('published_at', 'between', $begin, $end)
59
            ->load('user', ['method' => Select::SINGLE_QUERY])
60
            ->orderBy(['published_at' => 'asc']);
61
        return $this->prepareDataReader($query);
62
    }
63
64
    /**
65
     * @return DataReaderInterface Collection of Array('Count' => '123', 'Month' => '8', 'Year' => '2019') on read
66
     */
67 1
    public function getFullArchive(): DataReaderInterface
68
    {
69 1
        $sort = Sort::only(['year', 'month', 'count'])->withOrder(['year' => 'desc', 'month' => 'desc']);
70
71
        $query = $this
72 1
            ->select()
73 1
            ->buildQuery()
74 1
            ->columns([
75 1
                'count(post.id) count',
76 1
                $this->extractFromDateColumn('month'),
77 1
                $this->extractFromDateColumn('year'),
78
            ])
79 1
            ->groupBy('year, month');
80
81 1
        return (new EntityReader($query))->withSort($sort);
82
    }
83
84
    /**
85
     * @param string $attr Can be 'day', 'month' or 'year'
86
     *
87
     * @return FragmentInterface
88
     */
89 1
    private function extractFromDateColumn(string $attr): FragmentInterface
90
    {
91 1
        $driver = $this->getDriver();
92 1
        $wrappedField = $driver->getQueryCompiler()->quoteIdentifier($attr);
93 1
        if ($driver instanceof SQLiteDriver) {
94 1
            $str = ['year' => '%Y', 'month' => '%m', 'day' => '%d'][$attr];
95 1
            return new Fragment("strftime('{$str}', post.published_at) {$wrappedField}");
96
        }
97
        return new Fragment("extract({$attr} from post.published_at) {$wrappedField}");
98
    }
99
100 1
    private function getDriver(): DriverInterface
101
    {
102 1
        return $this->select()
103 1
                    ->getBuilder()
104 1
                    ->getLoader()
105 1
                    ->getSource()
106 1
                    ->getDatabase()
107 1
                    ->getDriver(DatabaseInterface::READ);
108
    }
109
110
    /**
111
     * @psalm-suppress UndefinedDocblockClass
112
     *
113
     * @param Select|SelectQuery $query
114
     *
115
     * @return EntityReader
116
     */
117
    private function prepareDataReader($query): EntityReader
118
    {
119
        return (new EntityReader($query))->withSort(Sort::only(['published_at'])->withOrder(['published_at' => 'desc']));
120
    }
121
}
122