1
|
|
|
<?php |
2
|
|
|
namespace Dennis\Seeder\Command; |
3
|
|
|
|
4
|
|
|
/*************************************************************** |
5
|
|
|
* Copyright notice |
6
|
|
|
* |
7
|
|
|
* (c) 2016 Dennis Römmich <[email protected]> |
8
|
|
|
* |
9
|
|
|
* All rights reserved |
10
|
|
|
* |
11
|
|
|
* This script is part of the TYPO3 project. The TYPO3 project is |
12
|
|
|
* free software; you can redistribute it and/or modify |
13
|
|
|
* it under the terms of the GNU General Public License as published by |
14
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
15
|
|
|
* (at your option) any later version. |
16
|
|
|
* |
17
|
|
|
* The GNU General Public License can be found at |
18
|
|
|
* http://www.gnu.org/copyleft/gpl.html. |
19
|
|
|
* |
20
|
|
|
* This script is distributed in the hope that it will be useful, |
21
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
22
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23
|
|
|
* GNU General Public License for more details. |
24
|
|
|
* |
25
|
|
|
* This copyright notice MUST APPEAR in all copies of the script! |
26
|
|
|
***************************************************************/ |
27
|
|
|
|
28
|
|
|
use Dennis\Seeder\Domain\Model\ColumnInterface; |
29
|
|
|
use Dennis\Seeder\Generator\MethodNameGenerator; |
30
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* SeederCommandController |
34
|
|
|
* |
35
|
|
|
* @author Dennis Römmich<[email protected]> |
36
|
|
|
* @copyright Copyright belongs to the respective authors |
37
|
|
|
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 or later |
38
|
|
|
*/ |
39
|
|
|
class SeederCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandController |
40
|
|
|
{ |
41
|
|
|
/** |
42
|
|
|
* namespace |
43
|
|
|
* |
44
|
|
|
* @var string $namespace |
45
|
|
|
*/ |
46
|
|
|
protected $namespace = 'Dennis\Seeder\Seeder'; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* path |
50
|
|
|
* |
51
|
|
|
* @var string $path |
52
|
|
|
*/ |
53
|
|
|
protected $path = 'seeder/Classes/Seeder/'; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* stub |
57
|
|
|
* |
58
|
|
|
* @var string $stub |
59
|
|
|
*/ |
60
|
|
|
protected $stub = 'seeder/Classes/Seeder/stubs/seeder.stub'; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var MethodNameGenerator |
64
|
|
|
*/ |
65
|
|
|
protected $methodNameGenerator; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @var \Dennis\Seeder\Utility\OutputUtility |
69
|
|
|
* @inject |
70
|
|
|
*/ |
71
|
|
|
protected $outputUtility; |
72
|
|
|
|
73
|
|
|
public function __construct() |
74
|
|
|
{ |
75
|
|
|
$faker = \Dennis\Seeder\Factory\FakerFactory::createFaker(); |
76
|
|
|
$this->methodNameGenerator = GeneralUtility::makeInstance(MethodNameGenerator::class, $faker); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* This command allows you to run predifined Seeds |
81
|
|
|
* |
82
|
|
|
* @param string $seed ClassName or Alias defined in $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['seeder']['alias'] of your seed |
83
|
|
|
* @return boolean |
84
|
|
|
*/ |
85
|
|
|
public function seedCommand($seed) |
|
|
|
|
86
|
|
|
{ |
87
|
|
|
$class = $this->resolveSeederClass($seed); |
88
|
|
|
|
89
|
|
|
/** @var \Dennis\Seeder\Seeder $seeder */ |
90
|
|
|
$seeder = new $class; |
91
|
|
|
$seeder->run(); |
92
|
|
|
$seeder->seed(); |
93
|
|
|
|
94
|
|
|
return true; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @param $tableName |
99
|
|
|
* @return array |
100
|
|
|
* @throws \Exception |
101
|
|
|
*/ |
102
|
|
|
protected function detectSeederInformations($tableName) |
103
|
|
|
{ |
104
|
|
|
$informations = []; |
105
|
|
|
$faker = \Dennis\Seeder\Factory\FakerFactory::createFaker(); |
106
|
|
|
$table = \Dennis\Seeder\Factory\TableFactory::createTable($tableName); |
107
|
|
|
|
108
|
|
|
/** @var ColumnInterface $column */ |
109
|
|
|
foreach ($table->getColumns() as $column) { |
110
|
|
|
if (in_array($column->getName(), \Dennis\Seeder\Provider\Faker::$skippedProvider)) { |
111
|
|
|
continue; |
112
|
|
|
} |
113
|
|
|
$provider = $faker->guessProviderName($column->getName()); |
114
|
|
|
$informationClassName = 'Dennis\\Seeder\\Information\\' . ucfirst(GeneralUtility::underscoredToLowerCamelCase($column->getName()) . 'Information'); |
115
|
|
|
$relationInformationAvailable = false; |
|
|
|
|
116
|
|
|
if ($column->getName() !== 'abstract' && class_exists($informationClassName)) { |
117
|
|
|
$information = GeneralUtility::makeInstance($informationClassName); |
118
|
|
|
} elseif ($this->isRelation($column)) { |
119
|
|
|
$information = GeneralUtility::makeInstance(\Dennis\Seeder\Information\RelationInformation::class); |
120
|
|
|
$relationInformationAvailable = true; |
121
|
|
|
} else { |
122
|
|
|
$information = GeneralUtility::makeInstance(\Dennis\Seeder\Information\NullInformation::class); |
123
|
|
|
$information->setDefaultValue($provider); |
124
|
|
|
} |
125
|
|
|
if (!$information instanceof \Dennis\Seeder\Information) { |
126
|
|
|
throw new \Exception($informationClassName . ' must implement ' . \Dennis\Seeder\Information::class); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
if ($this->isRelation($column) && $relationInformationAvailable) { |
130
|
|
|
$createNewSeeder = $this->askOrSelect($information->getQuestion([$column->getName()]), 'n'); |
131
|
|
|
if (strtolower($createNewSeeder) === 'y' || strtolower($createNewSeeder) === 'yes' || $createNewSeeder == 1) { |
132
|
|
|
$className = ''; |
133
|
|
|
while (!$className) { |
134
|
|
|
$className = $this->outputUtility->ask('<fg=yellow>Please specify the required argument "--class-name" (<fg=green>' . $column->getForeignTable() . '</>):</> '); |
135
|
|
|
} |
136
|
|
|
$this->makeCommand($className, $column->getForeignTable()); |
137
|
|
|
$informations[$column->getName()] = '$this->call(' . $className . '::class)'; |
138
|
|
|
} |
139
|
|
|
} else { |
140
|
|
|
switch ($information->getType()) { |
141
|
|
View Code Duplication |
case \Dennis\Seeder\Information::INFORMATION_TYPE_ASK: |
|
|
|
|
142
|
|
|
if (!is_null($response = $this->askOrSelect($information->getQuestion([$column->getName(), $provider]), $information->getDefaultValue()))) { |
143
|
|
|
if ($this->methodNameGenerator->generate($response)) { |
144
|
|
|
$informations[$column->getName()] = $this->methodNameGenerator->generate($response); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
break; |
148
|
|
|
case \Dennis\Seeder\Information::INFORMATION_TYPE_SELECT: |
149
|
|
View Code Duplication |
case \Dennis\Seeder\Information::INFORMATION_TYPE_SELECTMULTIPLE: |
|
|
|
|
150
|
|
|
if (!is_null($response = $this->askOrSelect($information->getQuestion([$column->getName(), $provider]), $information->getDefaultValue(), $information->getChoices()))) { |
151
|
|
|
if ($this->methodNameGenerator->generate($response)) { |
152
|
|
|
$informations[$column->getName()] = $this->methodNameGenerator->generate($response); |
153
|
|
|
} |
154
|
|
|
} |
155
|
|
|
break; |
156
|
|
|
default: |
157
|
|
|
if ($this->methodNameGenerator->generate($column->getName())) { |
158
|
|
|
$informations[$column->getName()] = $this->methodNameGenerator->generate($column->getName()); |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
if (!isset($informations['pid'])) { |
165
|
|
|
/** @var \Dennis\Seeder\Information $information */ |
166
|
|
|
$information = GeneralUtility::makeInstance(\Dennis\Seeder\Information\PidInformation::class); |
167
|
|
|
$informations['pid'] = $this->outputUtility->ask($information->getQuestion(), $information->getDefaultValue()); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
return $informations; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @param ColumnInterface $column |
175
|
|
|
* @return bool |
176
|
|
|
*/ |
177
|
|
|
protected function isRelation(ColumnInterface $column) |
178
|
|
|
{ |
179
|
|
|
return ( |
180
|
|
|
( |
181
|
|
|
$column instanceof \Dennis\Seeder\Domain\Model\Column\Select || |
182
|
|
|
$column instanceof \Dennis\Seeder\Domain\Model\Column\Inline || |
183
|
|
|
$column instanceof \Dennis\Seeder\Domain\Model\Column\Group |
184
|
|
|
) && |
185
|
|
|
$column->getForeignTable() |
186
|
|
|
); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @param $question |
191
|
|
|
* @param $defaultValue |
192
|
|
|
* @param null $choices |
193
|
|
|
* @return array|int|string |
194
|
|
|
*/ |
195
|
|
|
protected function askOrSelect($question, $defaultValue, $choices = null) |
196
|
|
|
{ |
197
|
|
|
if (is_null($choices)) { |
198
|
|
|
return $this->outputUtility->ask($question, $defaultValue); |
199
|
|
|
} |
200
|
|
|
return $this->outputUtility->select($question, $choices, $defaultValue); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* This command allows you to create new Seeds. |
205
|
|
|
* |
206
|
|
|
* @param string $className |
207
|
|
|
* @param string $tableName |
208
|
|
|
* @return boolean |
209
|
|
|
*/ |
210
|
|
|
public function makeCommand($className, $tableName) |
|
|
|
|
211
|
|
|
{ |
212
|
|
|
$class = $this->namespace . '\\' . $className; |
213
|
|
|
|
214
|
|
|
if (class_exists($class)) { |
215
|
|
|
$this->outputUtility->error('Class ' . $class . ' already exists.'); |
216
|
|
|
return false; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
if (!isset($GLOBALS['TCA'][$tableName])) { |
220
|
|
|
$this->outputAndExit('Configuration for ' . $tableName . ' not Found!'); |
221
|
|
|
} |
222
|
|
|
$informations = $this->detectSeederInformations($tableName); |
223
|
|
|
|
224
|
|
|
$seederClass = $this->getSeederClass($this->namespace, $className, $tableName, $informations); |
225
|
|
|
$file = fopen(__DIR__ . '/../../../' . $this->path . $className . '.php', 'w'); |
226
|
|
|
fwrite($file, $seederClass); |
227
|
|
|
fclose($file); |
228
|
|
|
|
229
|
|
|
$this->outputUtility->success( |
230
|
|
|
__DIR__ . '/../../../' . $this->path . $className . '.php' . ' successfully created</>' |
231
|
|
|
); |
232
|
|
|
|
233
|
|
|
return true; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param $string |
238
|
|
|
*/ |
239
|
|
|
protected function outputAndExit($string) |
240
|
|
|
{ |
241
|
|
|
$this->outputUtility->error($string); |
242
|
|
|
exit; |
|
|
|
|
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* getSeederClass |
247
|
|
|
* |
248
|
|
|
* @param string $namespace |
249
|
|
|
* @param string $className |
250
|
|
|
* @param array $informations |
251
|
|
|
* @return string |
252
|
|
|
*/ |
253
|
|
|
protected function getSeederClass($namespace, $className, $tableName, $informations) |
254
|
|
|
{ |
255
|
|
|
$stub = file_get_contents(__DIR__ . '/../../../' . $this->stub); |
256
|
|
|
|
257
|
|
|
$stub = str_replace('{namespace}', $namespace, $stub); |
258
|
|
|
$stub = str_replace('{ClassName}', $className, $stub); |
259
|
|
|
$stub = str_replace('{TableName}', $tableName, $stub); |
260
|
|
|
$informations = var_export($informations, true); |
|
|
|
|
261
|
|
|
$pattern = '/(\'.*\'\s=>\s)\'(\$.+->\w+\(.*\))\'/'; |
262
|
|
|
$replacement = '${1}${2}'; |
263
|
|
|
$informations = preg_replace($pattern, $replacement, $informations); |
|
|
|
|
264
|
|
|
$stub = str_replace('{informations}', $informations, $stub); |
265
|
|
|
|
266
|
|
|
return $stub; |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* @param string $className |
271
|
|
|
* @return bool|string |
|
|
|
|
272
|
|
|
*/ |
273
|
|
|
protected function resolveSeederClass($className) |
|
|
|
|
274
|
|
|
{ |
275
|
|
|
if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['seeder']['alias'][$className])) { |
276
|
|
|
$className = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['seeder']['alias'][$className]; |
|
|
|
|
277
|
|
|
if (!is_string($className)) { |
278
|
|
|
$this->outputUtility->error('$className must be type of string. Type of ' . gettype($className) . ' given.'); |
279
|
|
|
$this->sendAndExit(1); |
280
|
|
|
return false; |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
if (!class_exists($className)) { |
284
|
|
|
$this->outputUtility->error('Class ' . $className . ' does not exist.'); |
285
|
|
|
$this->sendAndExit(1); |
286
|
|
|
return false; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
return $className; |
290
|
|
|
} |
291
|
|
|
} |
292
|
|
|
|
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.