Passed
Push — master ( 46374a...c36860 )
by Alexander
02:10 queued 11s
created

SqlTableGateway   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 10
dl 0
loc 186
rs 9.68
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getSchema() 0 7 2
A getPrimaryKeys() 0 4 1
A normalizeFields() 0 11 3
A queryOne() 0 25 5
B queryAll() 0 32 6
A insert() 0 4 1
A updateOne() 0 13 3
A updateAll() 0 6 1
A deleteOne() 0 12 3
A deleteAll() 0 6 1
A aggregate() 0 10 1
A aggregateCount() 0 7 2
A aggregateSum() 0 4 1
A aggregateAverage() 0 4 1
A aggregateMin() 0 4 1
A aggregateMax() 0 4 1
1
<?php declare(strict_types=1);
2
3
namespace Indigerd\Repository\TableGateway;
4
5
use Indigerd\Repository\Query\SqlQueryFactory;
6
use yii\db\Connection;
7
use yii\db\Query;
8
use yii\db\Expression;
9
use Indigerd\Repository\Exception\UpdateException;
10
use Indigerd\Repository\Exception\DeleteException;
11
use Indigerd\Repository\Relation\Relation;
12
use yii\db\TableSchema;
13
14
class SqlTableGateway implements TableGatewayInterface
15
{
16
    protected $connection;
17
18
    protected $queryFactory;
19
20
    protected $collectionName;
21
22
    protected $schemas = [];
23
24
    public function __construct(Connection $connection, SqlQueryFactory $queryFactory, string $collectionName)
25
    {
26
        $this->connection = $connection;
27
        $this->queryFactory = $queryFactory;
28
        $this->collectionName = $collectionName;
29
    }
30
31
    protected function getSchema($collectionName): TableSchema
32
    {
33
        if (!isset($this->schemas[$collectionName])) {
34
            $this->schemas[$collectionName] = $this->connection->getSchema()->getTableSchema($collectionName);
35
        }
36
        return $this->schemas[$collectionName];
37
    }
38
39
    protected function getPrimaryKeys(): array
40
    {
41
        return $this->getSchema($this->collectionName)->primaryKey;
42
    }
43
44
    protected function normalizeFields(array $fields =[]): array
45
    {
46
        $result = [];
47
        foreach ($fields as $name=>$value) {
48
            if (\strpos($name, '.') === false) {
49
                $name = $this->collectionName . '.' . $name;
50
            }
51
            $result[$name] = $value;
52
        }
53
        return $result;
54
    }
55
56
    public function queryOne(array $conditions, array $relations = []): ?array
57
    {
58
        $select = [$this->collectionName . '.*'];
59
        foreach ($relations as $relation) {
60
            /** @var Relation $relation */
61
            $columns = $this->getSchema($relation->getRelatedCollection())->getColumnNames();
62
            foreach ($columns as $column) {
63
                $select[] = $relation->getRelatedCollection() . '.' . $column . ' as ' . $relation->getRelatedCollection() . '_relation_' . $column;
64
            }
65
        }
66
        /** @var Query $query */
67
        $query = $this->queryFactory->create();
68
        $query
69
            ->select(\implode(',', $select))
70
            ->from($this->collectionName)
71
            ->where($this->normalizeFields($conditions));
72
73
        foreach ($relations as $relation) {
74
            $joinCondition = $this->collectionName . '.' . $relation->getField() . '=' . $relation->getRelatedCollection() . '.' . $relation->getRelatedField();
75
            $query->join($relation->getRelationType() . ' join', $relation->getRelatedCollection(), $joinCondition);
76
        }
77
78
        $res = $query->one($this->connection);
79
        return $res ? $res : null;
80
    }
81
82
    public function queryAll(array $conditions, array $order = [], int $limit = 0, int $offset = 0, array $relations = []): array
83
    {
84
        $select = [$this->collectionName . '.*'];
85
        foreach ($relations as $relation) {
86
            /** @var Relation $relation */
87
            $columns = $this->getSchema($relation->getRelatedCollection())->getColumnNames();
88
            foreach ($columns as $column) {
89
                $select[] = $relation->getRelatedCollection() . '.' . $column . ' as ' . $relation->getRelatedCollection() . '_relation_' . $column;
90
            }
91
        }
92
        /** @var Query $query */
93
        $query = $this->queryFactory->create();
94
        $query
95
            ->select(\implode(',', $select))
96
            ->from($this->collectionName)
97
            ->where($this->normalizeFields($conditions));
98
99
        if ($limit > 0) {
100
            $query->limit($limit)->offset($offset);
101
        }
102
103
        if (!empty($order)) {
104
            $query->orderBy($this->normalizeFields($order));
105
        }
106
107
        foreach ($relations as $relation) {
108
            $joinCondition = $this->collectionName . '.' . $relation->getField() . '=' . $relation->getRelatedCollection() . '.' . $relation->getRelatedField();
109
            $query->join($relation->getRelationType() . ' join', $relation->getRelatedCollection(), $joinCondition);
110
        }
111
112
        return $query->all($this->connection);
113
    }
114
115
    public function insert(array $data): ?array
116
    {
117
        return $this->connection->schema->insert($this->collectionName, $data);
118
    }
119
120
    public function updateOne(array $data): void
121
    {
122
        $primaryKeys = $this->getPrimaryKeys();
123
        $conditions = [];
124
        foreach ($primaryKeys as $key) {
125
            if (empty($data[$key])) {
126
                throw new UpdateException($data, "Primary key $key not provided");
127
            }
128
            $conditions[$key] = $data[$key];
129
            unset($data[$key]);
130
        }
131
        $this->updateAll($data, $conditions);
132
    }
133
134
    public function updateAll(array $data, array $conditions): int
135
    {
136
        $command = $this->connection->createCommand();
137
        $command->update($this->collectionName, $data, $conditions);
138
        return $command->execute();
139
    }
140
141
    public function deleteOne(array $data): void
142
    {
143
        $primaryKeys = $this->getPrimaryKeys();
144
        $conditions = [];
145
        foreach ($primaryKeys as $key) {
146
            if (empty($data[$key])) {
147
                throw new DeleteException($data, "Primary key $key not provided");
148
            }
149
            $conditions[$key] = $data[$key];
150
        }
151
        $this->deleteAll($conditions);
152
    }
153
154
    public function deleteAll(array $conditions): int
155
    {
156
        $command = $this->connection->createCommand();
157
        $command->delete($this->collectionName, $conditions);
158
        return $command->execute();
159
    }
160
161
    public function aggregate(string $expression, array $conditions): string
162
    {
163
        /** @var Query $query */
164
        $query = $this->queryFactory->create();
165
        return (string)$query
166
            ->select(new Expression($expression))
167
            ->from($this->collectionName)
168
            ->where($conditions)
169
            ->scalar($this->connection);
170
    }
171
172
    public function aggregateCount(string $field = '', array $conditions = []): string
173
    {
174
        if (empty($field)) {
175
            $field = '*';
176
        }
177
        return $this->aggregate("COUNT($field)", $conditions);
178
    }
179
180
    public function aggregateSum(string $field, array $conditions = []): string
181
    {
182
        return $this->aggregate("SUM($field)", $conditions);
183
    }
184
185
    public function aggregateAverage(string $field, array $conditions = []): string
186
    {
187
        return $this->aggregate("AVG($field)", $conditions);
188
    }
189
190
    public function aggregateMin(string $field, array $conditions = []): string
191
    {
192
        return $this->aggregate("MIN($field)", $conditions);
193
    }
194
195
    public function aggregateMax(string $field, array $conditions = []): string
196
    {
197
        return $this->aggregate("MAX($field)", $conditions);
198
    }
199
}
200