Passed
Branch master (b01856)
by Alexander
02:16
created

SqlTableGateway::queryAll()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 8.7857
c 0
b 0
f 0
ccs 0
cts 18
cp 0
cc 6
nc 24
nop 5
crap 42
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
    public function queryOne(array $conditions, array $relations = []): ?array
45
    {
46
        $select = [$this->collectionName . '.*'];
47
        foreach ($relations as $relation) {
48
            /** @var Relation $relation */
49
            $columns = $this->getSchema($relation->getRelatedCollection())->getColumnNames();
50
            foreach ($columns as $column) {
51
                $select[] = $relation->getRelatedCollection() . '.' . $column . ' as ' . $relation->getRelatedCollection() . '_relation_' . $column;
52
            }
53
        }
54
        /** @var Query $query */
55
        $query = $this->queryFactory->create();
56
        $query
57
            ->select(\implode(',', $select))
58
            ->from($this->collectionName)
59
            ->where($conditions);
60
61
        foreach ($relations as $relation) {
62
            $joinCondition = $this->collectionName . '.' . $relation->getField() . '=' . $relation->getRelatedCollection() . '.' . $relation->getRelatedField();
63
            $query->join($relation->getRelationType() . ' join', $relation->getRelatedCollection(), $joinCondition);
64
        }
65
66
        $res = $query->one($this->connection);
67
        return $res ? $res : null;
68
    }
69
70
    public function queryAll(array $conditions, array $order = [], int $limit = 0, int $offset = 0, array $relations = []): array
71
    {
72
        $select = [$this->collectionName . '.*'];
73
        foreach ($relations as $relation) {
74
            /** @var Relation $relation */
75
            $columns = $this->getSchema($relation->getRelatedCollection())->getColumnNames();
76
            foreach ($columns as $column) {
77
                $select[] = $relation->getRelatedCollection() . '.' . $column . ' as ' . $relation->getRelatedCollection() . '_relation_' . $column;
78
            }
79
        }
80
        /** @var Query $query */
81
        $query = $this->queryFactory->create();
82
        $query
83
            ->select(\implode(',', $select))
84
            ->from($this->collectionName)
85
            ->where($conditions);
86
87
        if ($limit > 0) {
88
            $query->limit($limit)->offset($offset);
89
        }
90
91
        if (!empty($order)) {
92
            $query->orderBy($order);
93
        }
94
95
        foreach ($relations as $relation) {
96
            $joinCondition = $this->collectionName . '.' . $relation->getField() . '=' . $relation->getRelatedCollection() . '.' . $relation->getRelatedField();
97
            $query->join($relation->getRelationType() . ' join', $relation->getRelatedCollection(), $joinCondition);
98
        }
99
100
        return $query->all($this->connection);
101
    }
102
103
    public function insert(array $data): ?array
104
    {
105
        return $this->connection->schema->insert($this->collectionName, $data);
106
    }
107
108
    public function updateOne(array $data): void
109
    {
110
        $primaryKeys = $this->getPrimaryKeys();
111
        $conditions = [];
112
        foreach ($primaryKeys as $key) {
113
            if (empty($data[$key])) {
114
                throw new UpdateException($data, "Primary key $key not provided");
115
            }
116
            $conditions[$key] = $data[$key];
117
            unset($data[$key]);
118
        }
119
        $this->updateAll($data, $conditions);
120
    }
121
122
    public function updateAll(array $data, array $conditions): int
123
    {
124
        $command = $this->connection->createCommand();
125
        $command->update($this->collectionName, $data, $conditions);
126
        return $command->execute();
127
    }
128
129
    public function deleteOne(array $data): void
130
    {
131
        $primaryKeys = $this->getPrimaryKeys();
132
        $conditions = [];
133
        foreach ($primaryKeys as $key) {
134
            if (empty($data[$key])) {
135
                throw new DeleteException($data, "Primary key $key not provided");
136
            }
137
            $conditions[$key] = $data[$key];
138
        }
139
        $this->deleteAll($conditions);
140
    }
141
142
    public function deleteAll(array $conditions): int
143
    {
144
        $command = $this->connection->createCommand();
145
        $command->delete($this->collectionName, $conditions);
146
        return $command->execute();
147
    }
148
149
    public function aggregate(string $expression, array $conditions): string
150
    {
151
        /** @var Query $query */
152
        $query = $this->queryFactory->create();
153
        return (string)$query
154
            ->select(new Expression($expression))
155
            ->from($this->collectionName)
156
            ->where($conditions)
157
            ->scalar($this->connection);
158
    }
159
160
    public function aggregateCount(string $field = '', array $conditions = []): string
161
    {
162
        if (empty($field)) {
163
            $field = '*';
164
        }
165
        return $this->aggregate("COUNT($field)", $conditions);
166
    }
167
168
    public function aggregateSum(string $field, array $conditions = []): string
169
    {
170
        return $this->aggregate("SUM($field)", $conditions);
171
    }
172
173
    public function aggregateAverage(string $field, array $conditions = []): string
174
    {
175
        return $this->aggregate("AVG($field)", $conditions);
176
    }
177
178
    public function aggregateMin(string $field, array $conditions = []): string
179
    {
180
        return $this->aggregate("MIN($field)", $conditions);
181
    }
182
183
    public function aggregateMax(string $field, array $conditions = []): string
184
    {
185
        return $this->aggregate("MAX($field)", $conditions);
186
    }
187
}
188