Passed
Pull Request — master (#70)
by Dmitriy
03:35 queued 01:04
created

AbstractGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 0
c 0
b 0
f 0
dl 0
loc 5
ccs 1
cts 1
cp 1
rs 10
cc 1
nc 1
nop 3
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Gii\Generator;
6
7
use ReflectionClass;
8
use ReflectionException;
9
use Throwable;
10
use Yiisoft\Aliases\Aliases;
11
use Yiisoft\Validator\ValidatorInterface;
12
use Yiisoft\Yii\Gii\Component\CodeFile\CodeFile;
13
use Yiisoft\Yii\Gii\Exception\InvalidConfigException;
14
use Yiisoft\Yii\Gii\Exception\InvalidGeneratorCommandException;
15
use Yiisoft\Yii\Gii\GeneratorCommandInterface;
16
use Yiisoft\Yii\Gii\GeneratorInterface;
17
use Yiisoft\Yii\Gii\ParametersProvider;
18
19
/**
20
 * This is the base class for all generator classes.
21
 *
22
 * A generator instance is responsible for taking user inputs, validating them,
23
 * and using them to generate the corresponding code based on a set of code template files.
24
 *
25
 * A generator class typically needs to implement the following methods:
26
 *
27
 * - {@see GeneratorInterface::getName()}: returns the name of the generator
28
 * - {@see GeneratorInterface::getDescription()}: returns the detailed description of the generator
29
 * - {@see GeneratorInterface::generate()}: generates the code based on the current user input and the specified code
30
 * template files. This is the place where main code generation code resides.
31
 */
32
abstract class AbstractGenerator implements GeneratorInterface
33
{
34 4
    public function __construct(
35
        protected Aliases $aliases,
36
        protected ValidatorInterface $validator,
37
        protected ParametersProvider $parametersProvider,
38
    ) {
39 4
    }
40
41
    public function getRequiredTemplates(): array
42
    {
43
        return [];
44
    }
45
46
    /**
47
     * Returns the root path to the default code template files.
48
     * The default implementation will return the "templates" subdirectory of the
49
     * directory containing the generator class file.
50
     *
51
     * @throws ReflectionException
52
     *
53
     * @return string the root path to the default code template files.
54
     */
55 1
    private function defaultTemplate(): string
56
    {
57 1
        $class = new ReflectionClass($this);
58
59 1
        return dirname($class->getFileName()) . '/default';
60
    }
61
62 1
    public function getTemplatePath(GeneratorCommandInterface $command): string
63
    {
64 1
        $template = $command->getTemplate();
65
66 1
        if ($template === 'default') {
67 1
            return $this->defaultTemplate();
68
        }
69
70
        $templates = $this->parametersProvider->getTemplates(static::getId());
71
72
        return $templates[$template] ?? throw new InvalidConfigException("Unknown template: \"{$template}\"");
0 ignored issues
show
Bug Best Practice introduced by
The expression return $templates[$template] ?? ThrowNode also could return the type array|true which is incompatible with the return type mandated by Yiisoft\Yii\Gii\Generato...face::getTemplatePath() of string.
Loading history...
73
    }
74
75
    /**
76
     * @param GeneratorCommandInterface $command
77
     *
78
     * @throws InvalidGeneratorCommandException
79
     *
80
     * @return CodeFile[]
81
     */
82 3
    final public function generate(GeneratorCommandInterface $command): array
83
    {
84 3
        $result = $this->validator->validate($command);
85
86 3
        if (!$result->isValid()) {
87 2
            throw new InvalidGeneratorCommandException($result);
88
        }
89
90 1
        return $this->doGenerate($command);
91
    }
92
93
    abstract protected function doGenerate(GeneratorCommandInterface $command): array;
94
95
    /**
96
     * Generates code using the specified code template and parameters.
97
     * Note that the code template will be used as a PHP file.
98
     *
99
     * @param string $templateFile the code template file. This must be specified as a file path
100
     * relative to {@see getTemplatePath()}.
101
     * @param array $params list of parameters to be passed to the template file.
102
     *
103
     * @throws Throwable
104
     *
105
     * @return string the generated code
106
     */
107 1
    protected function render(GeneratorCommandInterface $command, string $templateFile, array $params = []): string
108
    {
109 1
        $file = sprintf(
110 1
            '%s/%s',
111 1
            $this->aliases->get($this->getTemplatePath($command)),
112 1
            $templateFile
113 1
        );
114
115 1
        $renderer = function (): void {
116 1
            extract(func_get_arg(1));
117
            /** @psalm-suppress UnresolvableInclude */
118 1
            require func_get_arg(0);
119 1
        };
120
121 1
        $obInitialLevel = ob_get_level();
122 1
        ob_start();
123 1
        ob_implicit_flush(false);
124
        try {
125
            /**
126
             * @noRector \Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector
127
             * @psalm-suppress PossiblyInvalidFunctionCall
128
             */
129 1
            $renderer->bindTo($this)($file, array_merge($params, ['command' => $command]));
130 1
            return ob_get_clean();
131
        } catch (Throwable $e) {
132
            while (ob_get_level() > $obInitialLevel) {
133
                if (!@ob_end_clean()) {
134
                    ob_clean();
135
                }
136
            }
137
            throw $e;
138
        }
139
    }
140
}
141