Passed
Pull Request — master (#49)
by
unknown
17:14 queued 02:12
created

ArchiveRepository   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 91
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 9
eloc 42
c 2
b 1
f 0
dl 0
loc 91
rs 10

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 6 1
A extractFromDateColumn() 0 7 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 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
    {
29
        $this->orm = $orm;
30
        /** @var PostRepository $postRepo */
31
        $postRepo = $this->orm->getRepository(Post::class);
32
        $this->postRepo = $postRepo;
33
    }
34
35
    public function select(): Select
36
    {
37
        return $this->postRepo->select();
38
    }
39
40
    /**
41
     * @param int $year
42
     * @param int $month
43
     * @return SelectDataReader
44
     * @throws \Exception
45
     */
46
    public function getMonthlyArchive(int $year, int $month): DataReaderInterface
47
    {
48
        $begin = (new \DateTimeImmutable())->setDate($year, $month, 1)->setTime(0, 0, 0);
49
        $end = $begin->setDate($year, $month + 1, 1)->setTime(0, 0, -1);
50
51
        $query = $this->select()
52
                    ->andWhere('published_at', 'between', $begin, $end)
53
                    ->load(['user', 'tags']);
54
        return $this->prepareDataReader($query);
55
    }
56
57
58
    public function getYearlyArchive(int $year): DataReaderInterface
59
    {
60
        $begin = (new \DateTimeImmutable())->setDate($year, 1, 1)->setTime(0, 0, 0);
61
        $end = $begin->setDate($year + 1, 1, 1)->setTime(0, 0, -1);
62
63
        $query = $this
64
            ->select()
65
            ->andWhere('published_at', 'between', $begin, $end)
66
            ->load('user', ['method' => Select::SINGLE_QUERY])
67
            ->orderBy(['published_at' => 'asc']);
68
        return $this->prepareDataReader($query);
69
    }
70
71
    /**
72
     * @return SelectDataReader Collection of Array('Count' => '123', 'Month' => '8', 'Year' => '2019')
73
     */
74
    public function getFullArchive(): DataReaderInterface
75
    {
76
        $sort = (new Sort([]))->withOrder(['year' => 'desc', 'month' => 'desc']);
77
78
        $query = $this
79
            ->select()
80
            ->buildQuery()
81
            ->columns([
82
                'count(post.id) count',
83
                $this->extractFromDateColumn('month'),
84
                $this->extractFromDateColumn('year'),
85
            ])
86
            ->groupBy('year, month');
87
88
        return (new SelectDataReader($query))->withSort($sort);
89
    }
90
91
    private function extractFromDateColumn($attr = 'year'): Fragment
92
    {
93
        if ($this->getDriver() instanceof SQLiteDriver) {
94
            $str = ['year' => '%Y', 'month' => '%m', 'day' => '%d'][$attr];
95
            return new Fragment("strftime('{$str}', post.published_at) {$attr}");
96
        }
97
        return new Fragment("extract({$attr} from post.published_at) {$attr}");
98
    }
99
100
    private function getDriver(): DriverInterface
101
    {
102
        return $this->select()
103
                    ->getBuilder()
104
                    ->getLoader()
105
                    ->getSource()
106
                    ->getDatabase()
107
                    ->getDriver(DatabaseInterface::READ);
108
    }
109
110
    private function prepareDataReader($query): SelectDataReader
111
    {
112
        return (new SelectDataReader($query))->withSort((new Sort([]))->withOrder(['published_at' => 'desc']));
113
    }
114
}
115