GeneratorService   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 418
Duplicated Lines 0 %

Test Coverage

Coverage 78.33%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 185
c 2
b 0
f 0
dl 0
loc 418
ccs 159
cts 203
cp 0.7833
rs 9.28
wmc 39

15 Methods

Rating   Name   Duplication   Size   Complexity  
A generateConfigurationTemplates() 0 6 1
A createModuleBaseFiles() 0 9 1
A createModuleModels() 0 14 1
A generateControllerTemplate() 0 40 4
A createStructureModule() 0 14 2
A generateSchemaTemplate() 0 13 1
A generateIndexTemplate() 0 10 1
B generateApiFiles() 0 16 8
A checkIfIsModel() 0 11 3
A generateConfigTemplate() 0 7 1
A createApi() 0 13 1
A generateBaseApiTemplate() 0 10 2
A generatePropertiesTemplate() 0 10 1
A createApiBaseFile() 0 17 1
B createModuleMigrations() 0 72 11
1
<?php
2
3
namespace PSFS\services;
4
5
use Propel\Common\Config\ConfigurationManager;
6
use Propel\Generator\Config\GeneratorConfig;
7
use Propel\Generator\Manager\MigrationManager;
8
use Propel\Generator\Model\Database;
9
use Propel\Generator\Model\Diff\DatabaseComparator;
10
use Propel\Generator\Model\Schema;
11
use PSFS\base\config\Config;
12
use PSFS\base\exception\ApiException;
13
use PSFS\base\exception\GeneratorException;
14
use PSFS\base\Logger;
15
use PSFS\base\types\helpers\GeneratorHelper;
16
use PSFS\base\types\SimpleService;
17
use PSFS\base\types\traits\Generator\PropelHelperTrait;
18
use PSFS\base\types\traits\Generator\StructureTrait;
19
20
/**
21
 * Class GeneratorService
22
 * @package PSFS\services
23
 */
24
class GeneratorService extends SimpleService
25
{
26
    use PropelHelperTrait;
27
    use StructureTrait;
28
29
    /**
30
     * @Injectable
31
     * @var \PSFS\base\config\Config Servicio de configuración
32
     */
33
    protected $config;
34
    /**
35
     * @Injectable
36
     * @var \PSFS\base\Security Servicio de autenticación
37
     */
38
    protected $security;
39
40
    /**
41
     * Servicio que genera la estructura de un módulo o lo actualiza en caso de ser necesario
42
     * @param string $module
43
     * @param boolean $force
44
     * @param string $type
45
     * @param string $apiClass
46
     * @param bool $skipMigration
47
     * @throws GeneratorException
48
     * @throws \ReflectionException
49
     */
50 1
    public function createStructureModule(string $module, bool $force = false, string $type = "", string $apiClass = "", bool $skipMigration = false): void
51
    {
52 1
        $modPath = CORE_DIR . DIRECTORY_SEPARATOR;
53 1
        $module = ucfirst($module);
54 1
        $this->createModulePath($module, $modPath);
55 1
        $this->createModulePathTree($module, $modPath);
0 ignored issues
show
Bug introduced by
$modPath of type string is incompatible with the type boolean expected by parameter $modPath of PSFS\services\GeneratorS...:createModulePathTree(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

55
        $this->createModulePathTree($module, /** @scrutinizer ignore-type */ $modPath);
Loading history...
56 1
        $this->createModuleBaseFiles($module, $modPath, $force, $type);
57 1
        $this->createModuleModels($module, $modPath);
58 1
        $this->generateBaseApiTemplate($module, $modPath, $force, $apiClass);
59 1
        if (!$skipMigration) {
60
            $this->createModuleMigrations($module, $modPath);
61
        }
62
        //Redireccionamos al home definido
63 1
        Logger::log("Módulo generado correctamente");
64
    }
65
66
    /**
67
     * Servicio que genera las plantillas básicas de ficheros del módulo
68
     * @param string $module
69
     * @param string $modPath
70
     * @param boolean $force
71
     * @param string $controllerType
72
     * @throws GeneratorException
73
     */
74 1
    private function createModuleBaseFiles($module, $modPath, $force = false, $controllerType = '')
75
    {
76 1
        $modulePath = $modPath . $module;
77 1
        $this->generateControllerTemplate($module, $modulePath, $force, $controllerType);
78 1
        $this->generateServiceTemplate($module, $modulePath, $force);
79 1
        $this->generateSchemaTemplate($module, $modulePath, $force);
80 1
        $this->generateConfigurationTemplates($module, $modulePath, $force);
81 1
        $this->generateIndexTemplate($module, $modulePath, $force);
82 1
        $this->generatePublicTemplates($modulePath, $force);
83
    }
84
85
    /**
86
     * @param string $module
87
     * @param string $modulePath
88
     * @param bool $force
89
     * @return void
90
     * @throws GeneratorException
91
     */
92 1
    public function generateConfigurationTemplates(string $module, string $modulePath, bool $force = false): void
93
    {
94 1
        $this->genereateAutoloaderTemplate($module, $modulePath, $force);
95 1
        $this->generatePropertiesTemplate($module, $modulePath, $force);
96 1
        $this->generateConfigTemplate($modulePath, $force);
97 1
        $this->createModuleModels($module, CORE_DIR . DIRECTORY_SEPARATOR);
98
    }
99
100
    /**
101
     * @param string $module
102
     * @param string $modPath
103
     * @param boolean $force
104
     * @param string $controllerType
105
     * @return boolean
106
     */
107 1
    private function generateControllerTemplate($module, $modPath, $force = false, $controllerType = "")
108
    {
109
        //Generamos el controlador base
110 1
        Logger::log("Generamos el controlador BASE");
111 1
        $class = preg_replace('/(\\\|\/)/', '', $module);
112 1
        $controllerBody = $this->tpl->dump("generator/controller.template.twig", array(
113 1
            "module" => $module,
114 1
            "namespace" => preg_replace('/(\\\|\/)/', '\\', $module),
115 1
            "url" => preg_replace('/(\\\|\/)/', '/', $module),
116 1
            "class" => $class,
117 1
            "controllerType" => $class . "Base",
118 1
            "is_base" => false
119 1
        ));
120 1
        $controller = $this->writeTemplateToFile($controllerBody, $modPath . DIRECTORY_SEPARATOR . "Controller" .
121 1
            DIRECTORY_SEPARATOR . "{$class}Controller.php", $force);
122
123 1
        $controllerBody = $this->tpl->dump("generator/controller.template.twig", array(
124 1
            "module" => $module,
125 1
            "namespace" => preg_replace('/(\\\|\/)/', '\\', $module),
126 1
            "url" => preg_replace('/(\\\|\/)/', '/', $module),
127 1
            "class" => $class . "Base",
128 1
            "service" => $class,
129 1
            "controllerType" => $controllerType,
130 1
            "is_base" => true,
131 1
            "domain" => $class,
132 1
        ));
133 1
        $controllerBase = $this->writeTemplateToFile($controllerBody, $modPath . DIRECTORY_SEPARATOR . "Controller" .
134 1
            DIRECTORY_SEPARATOR . "base" . DIRECTORY_SEPARATOR . "{$class}BaseController.php", true);
135
136 1
        $filename = $modPath . DIRECTORY_SEPARATOR . "Test" . DIRECTORY_SEPARATOR . "{$class}Test.php";
137 1
        $test = true;
138 1
        if (!file_exists($filename)) {
139 1
            $testTemplate = $this->tpl->dump("generator/testCase.template.twig", array(
140 1
                "module" => $module,
141 1
                "namespace" => preg_replace('/(\\\|\/)/', '\\', $module),
142 1
                "class" => $class,
143 1
            ));
144 1
            $test = $this->writeTemplateToFile($testTemplate, $filename, true);
145
        }
146 1
        return ($controller && $controllerBase && $test);
147
    }
148
149
    /**
150
     * Servicio que ejecuta Propel y genera el modelo de datos
151
     * @param string $module
152
     * @param string $path
153
     * @throws \PSFS\base\exception\GeneratorException
154
     */
155 1
    private function createModuleModels($module, $path)
156
    {
157 1
        $modulePath = str_replace(CORE_DIR . DIRECTORY_SEPARATOR, '', $path . $module);
158 1
        $configGenerator = $this->getConfigGenerator($modulePath);
159
160 1
        $this->buildModels($configGenerator);
161 1
        $this->buildSql($configGenerator);
162
163 1
        $configTemplate = $this->tpl->dump("generator/config.propel.template.twig", array(
164 1
            "module" => $module,
165 1
        ));
166 1
        $this->writeTemplateToFile($configTemplate, CORE_DIR . DIRECTORY_SEPARATOR . $modulePath . DIRECTORY_SEPARATOR . "Config" .
167 1
            DIRECTORY_SEPARATOR . "config.php", true);
168 1
        Logger::log("Generado config genérico para propel");
169
    }
170
171
    /**
172
     * @throws GeneratorException
173
     */
174
    private function createModuleMigrations($module, $path)
175
    {
176
        $migrationService = MigrationService::getInstance();
177
        /** @var $manager MigrationManager */
178
        /** @var $generatorConfig GeneratorConfig */
179
        list($manager, $generatorConfig) = $migrationService->getConnectionManager($module, $path);
180
181
        if ($manager->hasPendingMigrations()) {
182
            throw new ApiException(t(sprintf('Módulo %s generado correctamente. Hay una migración pendiente de aplicar, ejecute comando `psfs:migrate` o elimine el fichero generado en el módulo', $module)), 400);
183
        }
184
185
        // Checking the schema xml as source of tables and modifications
186
        $totalNbTables = 0;
187
        $reversedSchema = new Schema();
188
        $debugLogger = Config::getParam('log.level') === 'DEBUG';
189
        $connections = $generatorConfig->getBuildConnections();
190
        /** @var Database $appDatabase */
191
        foreach ($manager->getDatabases() as $appDatabase) {
192
            list($database, $nbTables) = $migrationService->checkSourceDatabase($manager, $generatorConfig, $appDatabase, $connections, $debugLogger);
193
194
            if ($database) {
195
                $reversedSchema->addDatabase($database);
196
            }
197
            $totalNbTables += $nbTables;
198
        }
199
200
        if ($totalNbTables) {
201
            Logger::log(sprintf('%d tables found in all databases.', $totalNbTables));
202
        } else {
203
            Logger::log('No table found in all databases');
204
        }
205
206
        // Comparing models with the connected database for this module
207
        Logger::log('Comparing models...');
208
        $migrationsUp = [];
209
        $migrationsDown = [];
210
        $configManager = new ConfigurationManager($generatorConfig->getSection('paths')['phpConfDir']);
211
        $excludedTables = (array)$configManager->getSection('exclude_tables');
212
213
        foreach ($reversedSchema->getDatabases() as $database) {
214
            $name = $database->getName();
215
216
            if ($debugLogger) {
217
                Logger::log(sprintf('Comparing database "%s"', $name));
218
            }
219
220
            $appDataDatabase = $manager->getDatabase($name);
221
            if (!$appDataDatabase) {
222
                Logger::log(sprintf('<error>Database "%s" does not exist in schema.xml. Skipped.</error>', $name));
223
                continue;
224
            }
225
226
            $databaseDiff = DatabaseComparator::computeDiff($database, $appDataDatabase, true, false, false, $excludedTables);
227
228
            if (!$databaseDiff) {
229
                if ($debugLogger) {
230
                    Logger::log(sprintf('Same XML and database structures for datasource "%s" - no diff to generate', $name));
231
                }
232
                continue;
233
            }
234
235
            list(, $platform) = $migrationService->getPlatformAndConnection($manager, $name, $generatorConfig);
236
            $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff);
237
            $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff());
238
        }
239
        if (count($migrationsUp) === 0) {
240
            Logger::log('Same XML and database structures for all datasource - no diff to generate');
241
            return true;
242
        }
243
244
        $migrationService->generateMigrationFile($manager, $migrationsUp, $migrationsDown, $generatorConfig);
245
        return true;
246
    }
247
248
    /**
249
     * @param string $module
250
     * @param string $modPath
251
     * @param boolean $force
252
     * @param string $apiClass
253
     * @return boolean
254
     * @throws \ReflectionException
255
     */
256 1
    private function generateBaseApiTemplate($module, $modPath, $force = false, $apiClass = "")
257
    {
258 1
        $created = true;
259 1
        $modelPath = $modPath . $module . DIRECTORY_SEPARATOR . 'Models';
260 1
        $apiPath = $modPath . $module . DIRECTORY_SEPARATOR . 'Api';
261 1
        if (file_exists($modelPath)) {
262 1
            $dir = dir($modelPath);
263 1
            $this->generateApiFiles($module, $force, $apiClass, $dir, $apiPath);
264
        }
265 1
        return $created;
266
    }
267
268
    /**
269
     * @param string $modPath
270
     * @param boolean $force
271
     * @return boolean
272
     */
273 1
    private function generateConfigTemplate($modPath, $force = false)
274
    {
275
        //Generamos el fichero de configuración
276 1
        Logger::log("Generamos fichero vacío de configuración");
277 1
        return $this->writeTemplateToFile("<?php\n\t",
278 1
            $modPath . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . "config.php",
279 1
            $force);
280
    }
281
282
    /**
283
     * @param string $module
284
     * @param string $modPath
285
     * @param boolean $force
286
     * @return boolean
287
     */
288 1
    private function generateSchemaTemplate($module, $modPath, $force = false)
289
    {
290
        //Generamos el autoloader del módulo
291 1
        Logger::log("Generamos el schema");
292 1
        $schema = $this->tpl->dump("generator/schema.propel.twig", array(
293 1
            "module" => $module,
294 1
            "namespace" => preg_replace('/(\\\|\/)/', '', $module),
295 1
            "prefix" => preg_replace('/(\\\|\/)/', '', $module),
296 1
            "db" => $this->config->get("db_name"),
297 1
        ));
298 1
        return $this->writeTemplateToFile($schema,
299 1
            $modPath . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . "schema.xml",
300 1
            $force);
301
    }
302
303
    /**
304
     * @param string $module
305
     * @param string $modPath
306
     * @param boolean $force
307
     * @return boolean
308
     */
309 1
    private function generatePropertiesTemplate($module, $modPath, $force = false)
310
    {
311 1
        Logger::log("Generamos la configuración de Propel");
312 1
        $buildProperties = $this->tpl->dump("generator/build.properties.twig", array(
313 1
            "module" => $module,
314 1
            "namespace" => preg_replace('/(\\\|\/)/', '', $module),
315 1
        ));
316 1
        return $this->writeTemplateToFile($buildProperties,
317 1
            $modPath . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . "propel.php",
318 1
            $force);
319
    }
320
321
    /**
322
     * @param string $module
323
     * @param string $modPath
324
     * @param boolean $force
325
     * @return boolean
326
     */
327 1
    private function generateIndexTemplate($module, $modPath, $force = false)
328
    {
329
        //Generamos la plantilla de index
330 1
        Logger::log("Generamos una plantilla base por defecto");
331 1
        $index = $this->tpl->dump("generator/index.template.twig", array(
332 1
            "module" => $module,
333 1
        ));
334 1
        return $this->writeTemplateToFile($index,
335 1
            $modPath . DIRECTORY_SEPARATOR . "Templates" . DIRECTORY_SEPARATOR . "index.html.twig",
336 1
            $force);
337
    }
338
339
    /**
340
     * Create ApiBase
341
     * @param string $module
342
     * @param string $modPath
343
     * @param string $api
344
     * @param string $apiClass
345
     * @param string $package
346
     *
347
     * @return bool
348
     */
349 1
    private function createApiBaseFile($module, $modPath, $api, $apiClass = '', $package = null)
350
    {
351 1
        $class = preg_replace('/(\\\|\/)/', '', $module);
352 1
        $customClass = GeneratorHelper::extractClassFromNamespace($apiClass);
353 1
        $controller = $this->tpl->dump("generator/api.base.template.twig", array(
354 1
            "module" => $module,
355 1
            "api" => $api,
356 1
            "namespace" => preg_replace('/(\\\|\/)/', '\\', $module),
357 1
            "url" => preg_replace('/(\\\|\/)/', '/', $module),
358 1
            "class" => $class,
359 1
            'customClass' => $customClass,
360 1
            'customNamespace' => $apiClass,
361 1
            'package' => $package,
362 1
        ));
363
364 1
        return $this->writeTemplateToFile($controller,
365 1
            $modPath . DIRECTORY_SEPARATOR . 'base' . DIRECTORY_SEPARATOR . "{$api}BaseApi.php", true);
366
    }
367
368
    /**
369
     * Create Api
370
     * @param string $module
371
     * @param string $modPath
372
     * @param bool $force
373
     * @param string $api
374
     * @param string $package
375
     *
376
     * @return bool
377
     */
378 1
    private function createApi($module, $modPath, $force, $api, $package = null)
379
    {
380 1
        $class = preg_replace('/(\\\|\/)/', '', $module);
381 1
        $controller = $this->tpl->dump("generator/api.template.twig", array(
382 1
            "module" => $module,
383 1
            "api" => $api,
384 1
            "namespace" => preg_replace('/(\\\|\/)/', '\\', $module),
385 1
            "url" => preg_replace('/(\\\|\/)/', '/', $module),
386 1
            "class" => $class,
387 1
            "package" => $package,
388 1
        ));
389
390 1
        return $this->writeTemplateToFile($controller, $modPath . DIRECTORY_SEPARATOR . "{$api}.php", $force);
391
    }
392
393
    /**
394
     * @param $module
395
     * @param $force
396
     * @param $apiClass
397
     * @param \Directory|null $dir
398
     * @param string $apiPath
399
     * @param string $package
400
     * @throws \ReflectionException
401
     */
402 1
    private function generateApiFiles($module, $force, $apiClass, \Directory $dir, string $apiPath, $package = null)
403
    {
404 1
        $base = $dir->path;
405 1
        while ($file = $dir->read()) {
406 1
            if (!in_array(strtolower($file), ['.', '..', 'base', 'map'])) {
407 1
                if (is_dir($base . DIRECTORY_SEPARATOR . $file)) {
408 1
                    $this->generateApiFiles($module, $force, $apiClass, dir($base . DIRECTORY_SEPARATOR . $file), $apiPath . DIRECTORY_SEPARATOR . $file, $file);
409 1
                } else if (!preg_match('/Query\.php$/i', $file)
410 1
                    && !preg_match('/I18n\.php$/i', $file)
411 1
                    && preg_match('/\.php$/i', $file)
412
                ) {
413 1
                    $filename = str_replace(".php", "", $file);
414 1
                    $this->log->addLog("Generamos Api BASES para {$filename}");
415 1
                    if ($this->checkIfIsModel($module, $filename, $package)) {
416 1
                        $this->createApiBaseFile($module, $apiPath, $filename, $apiClass, $package);
417 1
                        $this->createApi($module, $apiPath, $force, $filename, $package);
418
                    }
419
                }
420
            }
421
        }
422
    }
423
424
    /**
425
     * @param string $module
426
     * @param string $package
427
     * @param string $filename
428
     * @return bool
429
     * @throws \ReflectionException
430
     */
431 1
    private function checkIfIsModel($module, $filename, $package = null)
432
    {
433 1
        $parts = [$module, 'Models'];
434 1
        if (strlen($package ?: '')) {
435 1
            $parts[] = $package;
436
        }
437 1
        $parts[] = $filename;
438 1
        $namespace = '\\' . implode('\\', $parts);
439 1
        $reflectorClass = new \ReflectionClass($namespace);
440 1
        $isModel = $reflectorClass->isInstantiable();
441 1
        return $isModel;
442
    }
443
}
444