Test Failed
Pull Request — master (#494)
by
unknown
03:32
created

ArchiveRepository   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 108
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 54
dl 0
loc 108
rs 10
c 0
b 0
f 0
wmc 9

8 Methods

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