Completed
Push — master ( 146147...1776d4 )
by Neomerx
01:58
created

BaseSeedRunner::getIO()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php namespace Limoncello\Application\Data;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use DateTimeImmutable;
20
use Doctrine\DBAL\Connection;
21
use Doctrine\DBAL\Schema\AbstractSchemaManager;
22
use Doctrine\DBAL\Schema\Table;
23
use Doctrine\DBAL\Types\Type;
24
use Generator;
25
use Limoncello\Contracts\Commands\IoInterface;
26
use Limoncello\Contracts\Data\SeedInterface;
27
use Psr\Container\ContainerInterface;
28
29
/**
30
 * @package Limoncello\Application
31
 */
32
abstract class BaseSeedRunner
33
{
34
    /** Seed column name */
35
    const SEEDS_COLUMN_ID = 'id';
36
37
    /** Seed column name */
38
    const SEEDS_COLUMN_CLASS = 'class';
39
40
    /** Seed column name */
41
    const SEEDS_COLUMN_SEEDED_AT = 'seeded_at';
42
43
    /**
44
     * @var string
45
     */
46
    private $seedsTable;
47
48
    /**
49
     * @var null|callable
50
     */
51
    private $seedInit = null;
52
53
    /**
54
     * @var IoInterface
55
     */
56
    private $inOut;
57
58
    /**
59
     * @return string[]
60
     */
61
    abstract protected function getSeedClasses(): array;
62
63
    /**
64
     * @param IoInterface $inOut
65
     * @param callable    $seedInit
0 ignored issues
show
Documentation introduced by
Should the type for parameter $seedInit not be null|callable? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
66
     * @param string      $seedsTable
67
     */
68 2
    public function __construct(
69
        IoInterface $inOut,
70
        callable $seedInit = null,
71
        string $seedsTable = BaseMigrationRunner::SEEDS_TABLE
72
    ) {
73 2
        assert(empty($seedsTable) === false);
74
75 2
        $this->seedInit    = $seedInit;
76 2
        $this->seedsTable  = $seedsTable;
77
78 2
        $this->setIO($inOut);
79
    }
80
81
    /**
82
     * @param ContainerInterface $container
83
     *
84
     * @return void
85
     */
86 1
    public function run(ContainerInterface $container): void
87
    {
88 1
        foreach ($this->getSeeds($container) as $seederClass) {
89 1
            $this->getIO()->writeInfo("Starting seed for `$seederClass`..." . PHP_EOL, IoInterface::VERBOSITY_VERBOSE);
0 ignored issues
show
Unused Code introduced by
The call to IoInterface::writeInfo() has too many arguments starting with \Limoncello\Contracts\Co...face::VERBOSITY_VERBOSE.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
90 1
            $this->executeSeedInit($container, $seederClass);
91
            /** @var SeedInterface $seeder */
92 1
            $seeder = new $seederClass();
93 1
            $seeder->init($container)->run();
94 1
            $this->getIO()->writeInfo("Seed finished for `$seederClass`." . PHP_EOL, IoInterface::VERBOSITY_NORMAL);
0 ignored issues
show
Unused Code introduced by
The call to IoInterface::writeInfo() has too many arguments starting with \Limoncello\Contracts\Co...rface::VERBOSITY_NORMAL.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
95
        }
96
    }
97
98
    /**
99
     * @param ContainerInterface $container
100
     *
101
     * @return Generator
102
     *
103
     * @SuppressWarnings(PHPMD.ElseExpression)
104
     */
105 1 View Code Duplication
    protected function getSeeds(ContainerInterface $container): Generator
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
    {
107 1
        $connection = $this->getConnection($container);
108 1
        $manager    = $connection->getSchemaManager();
109
110 1
        if ($manager->tablesExist([$this->getSeedsTable()]) === true) {
111 1
            $seeded = $this->readSeeded($connection);
112
        } else {
113 1
            $this->createSeedsTable($manager);
114 1
            $seeded = [];
115
        }
116
117 1
        $notYetSeeded = array_diff($this->getSeedClasses(), $seeded);
118
119 1
        foreach ($notYetSeeded as $class) {
120 1
            yield $class;
121 1
            $this->saveSeed($connection, $class);
122
        }
123
    }
124
125
    /**
126
     * @param ContainerInterface $container
127
     *
128
     * @return Connection
129
     */
130 1
    protected function getConnection(ContainerInterface $container): Connection
131
    {
132 1
        return $container->get(Connection::class);
133
    }
134
135
    /**
136
     * @param ContainerInterface $container
137
     * @param string             $seedClass
138
     *
139
     * @return void
140
     */
141 1
    protected function executeSeedInit(ContainerInterface $container, string $seedClass): void
142
    {
143 1
        if ($this->seedInit !== null) {
144 1
            call_user_func($this->seedInit, $container, $seedClass);
145
        }
146
    }
147
148
    /**
149
     * @return IoInterface
150
     */
151 1
    protected function getIO(): IoInterface
152
    {
153 1
        return $this->inOut;
154
    }
155
156
    /**
157
     * @param IoInterface $inOut
158
     *
159
     * @return self
160
     */
161 2
    private function setIO(IoInterface $inOut): self
162
    {
163 2
        $this->inOut = $inOut;
164
165 2
        return $this;
166
    }
167
168
    /**
169
     * @param AbstractSchemaManager $manager
170
     *
171
     * @return void
172
     */
173 1 View Code Duplication
    private function createSeedsTable(AbstractSchemaManager $manager): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
174
    {
175 1
        $table = new Table($this->getSeedsTable());
176
177
        $table
178 1
            ->addColumn(static::SEEDS_COLUMN_ID, Type::INTEGER)
179 1
            ->setUnsigned(true)
180 1
            ->setAutoincrement(true);
181
        $table
182 1
            ->addColumn(static::SEEDS_COLUMN_CLASS, Type::STRING)
183 1
            ->setLength(255);
184
        $table
185 1
            ->addColumn(static::SEEDS_COLUMN_SEEDED_AT, Type::DATETIME);
186
187 1
        $table->setPrimaryKey([static::SEEDS_COLUMN_ID]);
188 1
        $table->addUniqueIndex([static::SEEDS_COLUMN_CLASS]);
189
190 1
        $manager->createTable($table);
191
    }
192
193
    /**
194
     * @param Connection $connection
195
     *
196
     * @return array
197
     */
198 1
    private function readSeeded(Connection $connection): array
199
    {
200 1
        $builder = $connection->createQueryBuilder();
201 1
        $seeded  = [];
202
203 1
        if ($connection->getSchemaManager()->tablesExist([$this->getSeedsTable()]) === true) {
204
            $seeds = $builder
205 1
                ->select(static::SEEDS_COLUMN_ID, static::SEEDS_COLUMN_CLASS)
206 1
                ->from($this->getSeedsTable())
207 1
                ->orderBy(static::SEEDS_COLUMN_ID)
208 1
                ->execute()
209 1
                ->fetchAll();
210 1
            foreach ($seeds as $seed) {
211 1
                $index          = $seed[static::SEEDS_COLUMN_ID];
212 1
                $class          = $seed[static::SEEDS_COLUMN_CLASS];
213 1
                $seeded[$index] = $class;
214
            }
215
        }
216
217 1
        return $seeded;
218
    }
219
220
    /**
221
     * @param Connection $connection
222
     * @param string     $class
223
     *
224
     * @return void
225
     */
226 1 View Code Duplication
    private function saveSeed(Connection $connection, string $class): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227
    {
228 1
        $format = $connection->getSchemaManager()->getDatabasePlatform()->getDateTimeFormatString();
229 1
        $now    = (new DateTimeImmutable())->format($format);
230 1
        $connection->insert($this->getSeedsTable(), [
231 1
            static::SEEDS_COLUMN_CLASS     => $class,
232 1
            static::SEEDS_COLUMN_SEEDED_AT => $now,
233
        ]);
234
    }
235
236
    /**
237
     * @return string
238
     */
239 1
    private function getSeedsTable(): string
240
    {
241 1
        return $this->seedsTable;
242
    }
243
}
244