QueryRelationDataProvider::prepareKeys()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 17
rs 9.9332
1
<?php
2
3
namespace Smoren\QueryRelationManager\Yii2;
4
5
use Smoren\QueryRelationManager\Base\QueryRelationManagerException;
6
use yii\data\BaseDataProvider;
7
use yii\db\Connection;
8
use yii\db\Query;
9
10
/**
11
 * DataProvider class for building pager navigation for QueryRelationManager queries
12
 * @author Smoren <[email protected]>
13
 */
14
class QueryRelationDataProvider extends BaseDataProvider
15
{
16
    /**
17
     * @var QueryRelationManager QueryRelationManager instance
18
     */
19
    public QueryRelationManager $queryRelationManager;
20
21
    /**
22
     * @var Connection|null the DB connection object or the application component ID of the DB connection.
23
     * If not set, the default DB connection will be used.
24
     */
25
    public ?Connection $db;
26
27
    /**
28
     * @var string|callable table column name of key or callback-function which returns it
29
     */
30
    public $key;
31
32
    /**
33
     * @var bool Flag to prevent total count query
34
     */
35
    public bool $withoutTotalCount = false;
36
37
    /**
38
     * @inheritDoc
39
     */
40
    public function init(): void
41
    {
42
        parent::init();
43
        $this->queryRelationManager = clone $this->queryRelationManager;
44
    }
45
46
    /**
47
     * @inheritDoc
48
     * @return array<mixed> the available data models
49
     * @throws QueryRelationManagerException
50
     */
51
    protected function prepareModels(): array
52
    {
53
        $pagination = $this->getPagination();
54
55
        if($pagination === false) {
56
            $models = $this->queryRelationManager->all($this->db);
57
        } else {
58
            $limit = $pagination->getLimit();
59
            $offset = $pagination->getOffset();
60
61
            $pagination->totalCount = $this->getTotalCount();
62
63
            $mainTable = $this->queryRelationManager->getTableCollection()->getMainTable();
64
            $pkFields = $mainTable->getPrimaryKeyForSelect();
65
66
            if(count($pkFields) === 1) {
67
                $ids = $this->queryRelationManager
68
                    ->prepare()
69
                    ->getQuery()
70
                    ->select($pkFields)
71
                    ->distinct()
72
                    ->limit($limit)
73
                    ->offset($offset)
74
                    ->column();
75
76
                $models = $this->queryRelationManager->filter(function(Query $q) use ($pkFields, $ids) {
77
                    $q->andWhere([$pkFields[0] => $ids]);
78
                })->all();
79
            } else {
80
                $pkValues = $this->queryRelationManager
81
                    ->prepare()
82
                    ->getQuery()
83
                    ->select($pkFields)
84
                    ->distinct()
85
                    ->limit($limit)
86
                    ->offset($offset)
87
                    ->all();
88
89
                $pkValuesPrefixed = [];
90
                foreach($pkValues as $row) {
91
                    $rowPrefixed = [];
92
                    foreach($row as $field => $value) {
93
                        $rowPrefixed["{$mainTable->alias}.{$field}"] = $value;
94
                    }
95
                    $pkValuesPrefixed[] = $rowPrefixed;
96
                }
97
98
                $models = $this->queryRelationManager->filter(
99
                    function(Query $q) use ($pkFields, $pkValuesPrefixed) {
100
                        $q->andWhere(['in', $pkFields, $pkValuesPrefixed]);
101
                    }
102
                )->all();
103
            }
104
        }
105
106
        return $models;
107
    }
108
109
    /**
110
     * @inheritDoc
111
     * @param array<array<string, mixed>> $models the available data models
112
     * @return array<scalar> the keys
113
     */
114
    protected function prepareKeys($models): array
115
    {
116
        if($this->key !== null) {
117
            /** @var array<scalar> $keys */
118
            $keys = [];
119
120
            foreach($models as $model) {
121
                if(is_string($this->key)) {
122
                    $keys[] = $model[$this->key];
123
                } else {
124
                    $keys[] = call_user_func($this->key, $model);
125
                }
126
            }
127
128
            return $keys;
129
        } else {
130
            return array_keys($models);
131
        }
132
    }
133
134
    /**
135
     * @inheritDoc
136
     * @throws QueryRelationManagerException
137
     */
138
    protected function prepareTotalCount(): int
139
    {
140
        if($this->withoutTotalCount) {
141
            return 0;
142
        }
143
144
        return (int)$this->queryRelationManager
145
            ->prepare()
146
            ->getQuery()
147
            ->select($this->queryRelationManager->getTableCollection()->getMainTable()->getPrimaryKeyForSelect())
148
            ->distinct()
149
            ->count();
150
    }
151
}
152