Passed
Pull Request — master (#49)
by
unknown
11:21
created

ArchiveRepository::getYearlyArchive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 11
rs 10
cc 1
nc 1
nop 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 Yiisoft\Data\Reader\DataReaderInterface;
16
use Yiisoft\Data\Reader\Sort;
17
use Yiisoft\Yii\Cycle\DataReader\SelectDataReader;
18
19
/**
20
 * This repository is not associated with Post entity
21
 */
22
final class ArchiveRepository
23
{
24
    private ORMInterface $orm;
25
    private PostRepository $postRepo;
26
27
    public function __construct(ORMInterface $orm) {
28
        $this->orm = $orm;
29
        /** @var PostRepository $postRepo */
30
        $postRepo = $this->orm->getRepository(Post::class);
31
        $this->postRepo = $postRepo;
32
    }
33
34
    public function select(): Select
35
    {
36
        return $this->postRepo->select();
37
    }
38
39
    /**
40
     * @param int $year
41
     * @param int $month
42
     * @return SelectDataReader
43
     * @throws \Exception
44
     */
45
    public function getMonthlyArchive(int $year, int $month): DataReaderInterface
46
    {
47
        $begin = (new \DateTimeImmutable())->setDate($year, $month, 1)->setTime(0, 0, 0);
48
        $end = $begin->setDate($year, $month + 1, 1)->setTime(0, 0, -1);
49
50
        $query = $this->select()
51
                    ->andWhere('published_at', 'between', $begin, $end)
52
                    ->load(['user', 'tags']);
53
        return $this->prepareDataReader($query);
54
    }
55
56
57
    public function getYearlyArchive(int $year): DataReaderInterface
58
    {
59
        $begin = (new \DateTimeImmutable())->setDate($year, 1, 1)->setTime(0, 0, 0);
60
        $end = $begin->setDate($year + 1, 1, 1)->setTime(0, 0, -1);
61
62
        $query = $this
63
            ->select()
64
            ->andWhere('published_at', 'between', $begin, $end)
65
            ->load('user', ['method' => Select::SINGLE_QUERY])
66
            ->orderBy(['published_at' => 'asc']);
67
        return $this->prepareDataReader($query);
68
    }
69
70
     /**
71
     * @return SelectDataReader Collection of Array('Count' => '123', 'Month' => '8', 'Year' => '2019')
72
     */
73
    public function getFullArchive(): DataReaderInterface
74
    {
75
        $sort = (new Sort([]))->withOrder(['year' => 'desc', 'month' => 'desc']);
76
77
        $query = $this
78
            ->select()
79
            ->buildQuery()
80
            ->columns([
81
                'count(post.id) count',
82
                $this->extractFromDateColumn('month'),
83
                $this->extractFromDateColumn('year'),
84
            ])
85
            ->groupBy('year, month');
86
87
        return (new SelectDataReader($query))->withSort($sort);
88
    }
89
90
    private function extractFromDateColumn($attr = 'year'): Fragment
91
    {
92
        if ($this->getDriver() instanceof SQLiteDriver) {
93
            $str = ['year' => '%Y', 'month' => '%m', 'day' => '%d'][$attr];
94
            return new Fragment("strftime('{$str}', post.published_at) {$str}");
95
        }
96
        return new Fragment("extract({$attr} from post.published_at) {$attr}");
97
    }
98
99
    private function getDriver(): DriverInterface
100
    {
101
        return $this->select()
102
                    ->getBuilder()
103
                    ->getLoader()
104
                    ->getSource()
105
                    ->getDatabase()
106
                    ->getDriver(DatabaseInterface::READ);
107
    }
108
109
    private function prepareDataReader($query): SelectDataReader
110
    {
111
        return (new SelectDataReader($query))->withSort((new Sort([]))->withOrder(['published_at' => 'desc']));
112
    }
113
}
114