Passed
Push — master ( 7ba57e...634515 )
by Paweł
03:13
created

MultipleTagsDiff::prepareData()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 16
nc 3
nop 0
dl 0
loc 29
rs 9.7333
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created for IG Monitoring.
4
 * User: jakim <[email protected]>
5
 * Date: 2019-01-29
6
 */
7
8
namespace app\components\stats\diffs;
9
10
11
use app\components\stats\base\BaseDiff;
12
use app\components\stats\traits\FromToDateTrait;
13
use app\components\stats\traits\StatsAttributesTrait;
14
use app\components\traits\SetTagTrait;
15
use app\models\TagStats;
16
use yii\base\InvalidConfigException;
17
use yii\db\Expression;
18
use yii\helpers\ArrayHelper;
19
20
class MultipleTagsDiff extends BaseDiff
21
{
22
    use FromToDateTrait, SetTagTrait, StatsAttributesTrait;
23
24
    /**
25
     * @var \app\models\Tag[]|array
26
     */
27
    public $tags;
28
29
    protected $tagIds = [];
30
31
    public function setTags(array $tags)
32
    {
33
        $this->tags = $tags;
34
35
        return $this;
36
    }
37
38
    public function init()
39
    {
40
        parent::init();
41
        if ($this->tags === null) {
42
            throw new InvalidConfigException('Property \'tags\' can not be empty.');
43
        }
44
        $this->tagIds = ArrayHelper::getColumn($this->tags, 'id');
45
        $this->throwExceptionIfFromToAreNotSet();
46
        $this->throwExceptionIfStatsAttributesIsNotSet();
47
    }
48
49
    protected function prepareData(): array
50
    {
51
        $models = [];
52
53
        $dbTo = $this->to->copy()->endOfDay()->toDateTimeString();
54
        $dbFrom = $this->from->copy()->endOfDay()->toDateTimeString();
55
56
        $toStatsIds = $this->findStatsIds($dbTo);
57
        $toModels = $this->findDataModels($toStatsIds);
58
59
        // jesli znaleziona ostatnia data 'do' jest wczesniejsza niz od, to nie pomijaj modelu
60
        $ignoredModels = array_filter($toModels, function ($toModel) use ($dbFrom) {
61
            if (strtotime($toModel['created_at']) > strtotime($dbFrom)) {
62
                return true;
63
            }
64
        });
65
66
        $fromStatsIds = $this->findStatsIds($dbFrom, ArrayHelper::getColumn($ignoredModels, 'id'));
67
        $fromModels = $this->findDataModels($fromStatsIds);
68
69
        foreach ($toModels as $accountId => $toModel) {
70
            $fromModel = ArrayHelper::getValue($fromModels, $accountId);
71
            foreach ($this->statsAttributes as $statsAttribute) {
72
                $value = ArrayHelper::getValue($toModel, $statsAttribute, 0) - ArrayHelper::getValue($fromModel, $statsAttribute, 0);
73
                $models[$accountId][$statsAttribute] = $value;
74
            }
75
        }
76
77
        return $models;
78
    }
79
80
    protected function findStatsIds(?string $date, array $ignoredStatsIds = [])
81
    {
82
        return TagStats::find()
83
            ->cache()
84
            ->select(new Expression('MAX(id) as id'))
85
            ->indexBy('tag_id')
86
            ->andWhere(['tag_id' => $this->tagIds])
87
            ->andWhere(['<=', 'created_at', $date])
88
            ->andFilterWhere(['not', ['id' => $ignoredStatsIds]])
89
            ->groupBy('tag_id')
90
            ->column();
91
    }
92
93
    protected function findDataModels(array $statsIds)
94
    {
95
        $columns = array_map(function ($attr) {
96
            return "tag_stats.{$attr}";
97
        }, $this->statsAttributes);
98
        $columns[] = 'id';
99
        $columns[] = 'tag_id';
100
        $columns[] = new Expression('DATE(created_at) as created_at');
101
102
        return TagStats::find()
103
            ->cache()
104
            ->select($columns)
105
            ->indexBy('tag_id')
106
            ->andWhere(['id' => $statsIds])
107
            ->asArray()
108
            ->all();
109
    }
110
}