SeedTrait::readModelsData()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
1
<?php declare (strict_types = 1);
2
3
namespace Limoncello\Data\Seeds;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Closure;
22
use DateTimeImmutable;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\DBALException;
25
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
26
use Doctrine\DBAL\Schema\AbstractSchemaManager;
27
use Doctrine\DBAL\Types\Type;
28
use Exception;
29
use Limoncello\Contracts\Data\ModelSchemaInfoInterface;
30
use Limoncello\Contracts\Data\SeedInterface;
31
use PDO;
32
use Psr\Container\ContainerInterface;
33
use function array_key_exists;
34
use function assert;
35
36
/**
37
 * @package Limoncello\Data
38
 */
39
trait SeedTrait
40
{
41
    /**
42
     * @var ContainerInterface
43
     */
44
    private $container;
45
46
    /**
47
     * @inheritdoc
48
     */
49 1
    public function init(ContainerInterface $container): SeedInterface
50
    {
51 1
        $this->container = $container;
52
53
        /** @var SeedInterface $self */
54 1
        $self = $this;
55
56 1
        return $self;
57
    }
58
59
    /**
60
     * @return ContainerInterface
61
     */
62 1
    protected function getContainer(): ContainerInterface
63
    {
64 1
        return $this->container;
65
    }
66
67
    /**
68
     * @return Connection
69
     */
70 1
    protected function getConnection(): Connection
71
    {
72 1
        assert($this->getContainer()->has(Connection::class) === true);
73
74 1
        return $this->getContainer()->get(Connection::class);
75
    }
76
77
    /**
78
     * @return ModelSchemaInfoInterface
79
     */
80 1
    protected function getModelSchemas(): ModelSchemaInfoInterface
81
    {
82 1
        assert($this->getContainer()->has(ModelSchemaInfoInterface::class) === true);
83
84 1
        return $this->getContainer()->get(ModelSchemaInfoInterface::class);
85
    }
86
87
    /**
88
     * @return AbstractSchemaManager
89
     */
90 1
    protected function getSchemaManager(): AbstractSchemaManager
91
    {
92 1
        return $this->getConnection()->getSchemaManager();
93
    }
94
95
    /**
96
     * @return string
97
     *
98
     * @throws Exception
99
     */
100 1
    protected function now(): string
101
    {
102 1
        $format = $this->getSchemaManager()->getDatabasePlatform()->getDateTimeFormatString();
103 1
        $now    = (new DateTimeImmutable())->format($format);
104
105 1
        return $now;
106
    }
107
108
    /**
109
     * @param string   $tableName
110
     * @param null|int $limit
111
     *
112
     * @return array
113
     */
114 1
    protected function readTableData(string $tableName, int $limit = null): array
115
    {
116 1
        assert($limit === null || $limit > 0);
117
118 1
        $builder = $this->getConnection()->createQueryBuilder();
119
        $builder
120 1
            ->select('*')
121 1
            ->from($tableName);
122
123 1
        $limit === null ?: $builder->setMaxResults($limit);
124
125 1
        $result = $builder->execute()->fetchAll(PDO::FETCH_ASSOC);
126
127 1
        return $result;
128
    }
129
130
    /**
131
     * @param string   $modelClass
132
     * @param null|int $limit
133
     *
134
     * @return array
135
     */
136 1
    protected function readModelsData(string $modelClass, int $limit = null): array
137
    {
138 1
        return $this->readTableData($this->getModelSchemas()->getTable($modelClass), $limit);
139
    }
140
141
    /**
142
     * @param int     $records
143
     * @param string  $tableName
144
     * @param Closure $dataClosure
145
     * @param array   $columnTypes
146
     *
147
     * @return void
148
     *
149
     * @throws DBALException
150
     */
151 1
    protected function seedTableData(int $records, $tableName, Closure $dataClosure, array $columnTypes = []): void
152
    {
153 1
        $attributeTypeGetter = $this->createAttributeTypeGetter($columnTypes);
154
155 1
        $connection = $this->getConnection();
156 1
        for ($i = 0; $i !== $records; $i++) {
157 1
            $this->insertRow($tableName, $connection, $dataClosure($this->getContainer()), $attributeTypeGetter);
158
        }
159
    }
160
161
    /**
162
     * @param int     $records
163
     * @param string  $modelClass
164
     * @param Closure $dataClosure
165
     *
166
     * @return void
167
     *
168
     * @throws DBALException
169
     */
170 1
    protected function seedModelsData(int $records, string $modelClass, Closure $dataClosure): void
171
    {
172 1
        $attributeTypes = $this->getModelSchemas()->getAttributeTypes($modelClass);
173
174 1
        $this->seedTableData($records, $this->getModelSchemas()->getTable($modelClass), $dataClosure, $attributeTypes);
175
    }
176
177
    /**
178
     * @param string $tableName
179
     * @param array  $data
180
     * @param array  $columnTypes
181
     *
182
     * @return void
183
     *
184
     * @throws DBALException
185
     */
186 1
    protected function seedRowData(string $tableName, array $data, array $columnTypes = []): void
187
    {
188 1
        $attributeTypeGetter = $this->createAttributeTypeGetter($columnTypes);
189
190 1
        $this->insertRow($tableName, $this->getConnection(), $data, $attributeTypeGetter);
191
    }
192
193
    /**
194
     * @param string $modelClass
195
     * @param array  $data
196
     *
197
     * @return void
198
     *
199
     * @throws DBALException
200
     */
201 1
    protected function seedModelData(string $modelClass, array $data): void
202
    {
203 1
        $attributeTypes = $this->getModelSchemas()->getAttributeTypes($modelClass);
204
205 1
        $this->seedRowData($this->getModelSchemas()->getTable($modelClass), $data, $attributeTypes);
206
    }
207
208
    /**
209
     * @return string
210
     */
211 1
    protected function getLastInsertId(): string
212
    {
213 1
        return $this->getConnection()->lastInsertId();
214
    }
215
216
    /**
217
     * @param string     $tableName
218
     * @param Connection $connection
219
     * @param array      $data
220
     * @param Closure    $getColumnType
221
     *
222
     * @return void
223
     *
224
     * @throws DBALException
225
     */
226 1
    private function insertRow($tableName, Connection $connection, array $data, Closure $getColumnType): void
227
    {
228 1
        $types        = [];
229 1
        $quotedFields = [];
230 1
        foreach ($data as $column => $value) {
231 1
            $name                = $connection->quoteIdentifier($column);
232 1
            $quotedFields[$name] = $value;
233 1
            $types[$name]        = $getColumnType($column);
234
        }
235
236
        try {
237 1
            $result = $connection->insert($tableName, $quotedFields, $types);
238 1
            assert($result !== false, 'Insert failed');
239 1
        } /** @noinspection PhpRedundantCatchClauseInspection */ catch (UniqueConstraintViolationException $e) {
240
            // ignore non-unique records
241
        }
242
    }
243
244
    /**
245
     * @param array $attributeTypes
246
     *
247
     * @return Closure
248
     */
249 1
    private function createAttributeTypeGetter(array $attributeTypes): Closure
250
    {
251
        return function (string $attributeType) use ($attributeTypes) : string {
252 1
            return array_key_exists($attributeType, $attributeTypes) === true ?
253 1
                $attributeTypes[$attributeType] : Type::STRING;
254 1
        };
255
    }
256
}
257