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

MultiAccountsDiff::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-24
6
 */
7
8
namespace app\components\stats\diffs;
9
10
11
use app\components\stats\base\BaseDiff;
12
use app\models\AccountStats;
13
use yii\base\InvalidConfigException;
14
use yii\db\Expression;
15
use yii\helpers\ArrayHelper;
16
17
/**
18
 * Class MultiAccountsDiffDataProvider
19
 *
20
 * @package app\components\stats\providers
21
 *
22
 * @property \Carbon\Carbon $from
23
 * @property \Carbon\Carbon $to
24
 */
25
class MultiAccountsDiff extends BaseDiff
26
{
27
    /**
28
     * @var \app\models\Account[]|array
29
     */
30
    public $accounts;
31
32
    public $accountIds = [];
33
34
    public function setAccounts(array $accounts)
35
    {
36
        $this->accounts = $accounts;
37
38
        return $this;
39
    }
40
41
    public function init()
42
    {
43
        parent::init();
44
        if ($this->accounts === null) {
45
            throw new InvalidConfigException('Property \'accounts\' can not be empty.');
46
        }
47
        $this->accountIds = $this->accountIds ?: ArrayHelper::getColumn($this->accounts, 'id');
48
        $this->throwExceptionIfFromToAreNotSet();
49
        $this->throwExceptionIfStatsAttributesIsNotSet();
50
    }
51
52
    protected function prepareData(): array
53
    {
54
        $models = [];
55
56
        $dbTo = $this->to->copy()->endOfDay()->toDateTimeString();
57
        $dbFrom = $this->from->copy()->endOfDay()->toDateTimeString();
58
59
        $toStatsIds = $this->findStatsIds($dbTo);
60
        $toModels = $this->findDataModels($toStatsIds);
61
62
        // jesli znaleziona ostatnia data 'do' jest wczesniejsza niz od, to nie pomijaj modelu
63
        $ignoredModels = array_filter($toModels, function ($toModel) use ($dbFrom) {
64
            if (strtotime($toModel['created_at']) > strtotime($dbFrom)) {
65
                return true;
66
            }
67
        });
68
69
        $fromStatsIds = $this->findStatsIds($dbFrom, ArrayHelper::getColumn($ignoredModels, 'id'));
70
        $fromModels = $this->findDataModels($fromStatsIds);
71
72
        foreach ($toModels as $accountId => $toModel) {
73
            $fromModel = ArrayHelper::getValue($fromModels, $accountId);
74
            foreach ($this->statsAttributes as $statsAttribute) {
75
                $value = ArrayHelper::getValue($toModel, $statsAttribute, 0) - ArrayHelper::getValue($fromModel, $statsAttribute, 0);
76
                $models[$accountId][$statsAttribute] = $value;
77
            }
78
        }
79
80
        return $models;
81
    }
82
83
    protected function findStatsIds(?string $date, array $ignoredStatsIds = [])
84
    {
85
        return AccountStats::find()
86
            ->cache()
87
            ->select(new Expression('MAX(id) as id'))
88
            ->indexBy('account_id')
89
            ->andWhere(['account_id' => $this->accountIds])
90
            ->andWhere(['<=', 'created_at', $date])
91
            ->andFilterWhere(['not', ['id' => $ignoredStatsIds]])
92
            ->groupBy('account_id')
93
            ->column();
94
    }
95
96
    protected function findDataModels(array $statsIds)
97
    {
98
        $columns = array_map(function ($attr) {
99
            return "account_stats.{$attr}";
100
        }, $this->statsAttributes);
101
        $columns[] = 'id';
102
        $columns[] = 'account_id';
103
        $columns[] = new Expression('DATE(created_at) as created_at');
104
105
        return AccountStats::find()
106
            ->cache()
107
            ->select($columns)
108
            ->indexBy('account_id')
109
            ->andWhere(['id' => $statsIds])
110
            ->asArray()
111
            ->all();
112
    }
113
}