Completed
Push — master ( fd95a3...5639cc )
by Jitendra
02:08
created

TwigGenerator::mayOverride()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 2
dl 0
loc 16
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the PHINT package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\Phint\Generator;
13
14
use Ahc\Phint\Util\Inflector;
15
use Ahc\Phint\Util\Path;
16
use Symfony\Component\Finder\Finder;
17
18
class TwigGenerator implements GeneratorInterface
19
{
20
    /** @var \Twig_Environment */
21
    protected $twig;
22
23
    /** @var Path */
24
    protected $pathUtil;
25
26
    /** @var Inflector */
27
    protected $inflector;
28
29
    /** @var string|array */
30
    protected $templatePath;
31
32
    /** @var string */
33
    protected $cachePath;
34
35
    /** @var array Templates required for type 'project' only */
36
    protected $projectTemplates = [
37
        '.env.example' => true,
38
        'package.json' => true,
39
    ];
40
41
    /** @var array Templates only loaded by some specific commands */
42
    protected $commandTemplates = [
43
        'test' => true,
44
    ];
45
46
    public function __construct(string $templatePath, string $cachePath)
47
    {
48
        $this->templatePath = $templatePath;
49
        $this->cachePath    = $cachePath;
50
        $this->pathUtil     = new Path;
51
        $this->inflector    = new Inflector;
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function generate(string $targetPath, array $parameters, CollisionHandlerInterface $handler = null)
58
    {
59
        if (!$this->twig) {
60
            $this->initTwig();
61
        }
62
63
        $templates = $this->findTemplates($this->templatePath);
0 ignored issues
show
Bug introduced by
It seems like $this->templatePath can also be of type array; however, parameter $templatePath of Ahc\Phint\Generator\TwigGenerator::findTemplates() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

63
        $templates = $this->findTemplates(/** @scrutinizer ignore-type */ $this->templatePath);
Loading history...
64
        foreach ($templates as $template) {
65
            if ($this->shouldGenerate($template, $parameters)) {
66
                $this->doGenerate($template, $targetPath, $parameters, $handler);
67
            }
68
        }
69
70
        $this->pathUtil->createBinaries($parameters['bin'] ?? [], $parameters['path'] ?? '');
71
    }
72
73
    public function generateTests(array $testMetadata, array $parameters): int
74
    {
75
        if (!$this->twig) {
76
            $this->initTwig();
77
        }
78
79
        $generated = 0;
80
81
        foreach ($testMetadata as $metadata) {
82
            // Skip existing
83
            if (\is_file($targetFile = $metadata['testPath'])) {
84
                continue;
85
            }
86
87
            $generated++;
88
89
            $content = $this->twig->render('tests/test.twig', $metadata + $parameters);
90
91
            $this->pathUtil->writeFile($targetFile, $content);
92
        }
93
94
        return $generated;
95
    }
96
97
    protected function initTwig()
98
    {
99
        $options = [
100
            'auto_reload' => true,
101
            'cache'       => false,
102
        ];
103
104
        if ($this->cachePath) {
105
            $this->pathUtil->ensureDir($this->cachePath);
106
            $options['cache'] = $this->cachePath;
107
        }
108
109
        $this->twig = new \Twig_Environment(
110
            new \Twig_Loader_Filesystem($this->templatePath),
111
            $options
112
        );
113
114
        $this->twig->addFilter(new \Twig_SimpleFilter('snake', function ($x) {
115
            return $this->inflector->snakeCase($x);
116
        }));
117
118
        $this->twig->addFilter(new \Twig_SimpleFilter('lcfirst', function ($x) {
119
            return \lcfirst($x);
120
        }));
121
122
        $this->twig->addFunction(new \Twig_Function('gmdate', function ($f = null) {
123
            return \gmdate($f ?? 'Y-m-d H:i:s');
124
        }));
125
    }
126
127
    protected function findTemplates(string $templatePath)
128
    {
129
        $templates = [];
130
        $finder    = new Finder;
131
132
        $finder->files()->ignoreDotFiles(false)->filter(function ($file) {
133
            return \substr($file, -5) === '.twig';
134
        });
135
136
        foreach ($finder->in($templatePath) as $file) {
137
            $templates[] = (string) $file;
138
        }
139
140
        return $templates;
141
    }
142
143
    protected function doGenerate(string $template, string $targetPath, array $parameters, CollisionHandlerInterface $handler = null)
144
    {
145
        $relativePath = $this->pathUtil->getRelativePath($template, $this->templatePath);
146
        $targetFile   = $this->pathUtil->join($targetPath, $this->getRelativeTarget($parameters, $relativePath));
147
        $fileExists   = \is_file($targetFile);
148
        $targetDir    = \dirname($targetFile);
0 ignored issues
show
Unused Code introduced by
The assignment to $targetDir is dead and can be removed.
Loading history...
149
        $content      = $this->twig->render($relativePath, $parameters);
150
151
        if ($handler && $fileExists) {
152
            $handler->handle($targetFile, $content, $parameters);
153
154
            return;
155
        }
156
157
        if ($this->mayOverride($fileExists, $parameters)) {
158
            $this->pathUtil->writeFile($targetFile, $content);
159
        }
160
    }
161
162
    protected function getRelativeTarget(array $parameters, string $relativePath): string
163
    {
164
        $fileName   = \basename($relativePath, '.twig');
165
        $targetFile = \str_replace('.twig', '', $relativePath);
166
167
        if (!empty($parameters['ghTemplate']) && \in_array($fileName, ['ISSUE_TEMPLATE.md', 'PULL_REQUEST_TEMPLATE.md'])) {
168
            $targetFile = '.github/' . $fileName;
169
        }
170
171
        return $targetFile;
172
    }
173
174
    protected function shouldGenerate(string $template, array $parameters)
175
    {
176
        $name = \basename($template, '.twig');
177
178
        if (isset($this->projectTemplates[$name])) {
179
            return $parameters['type'] === 'project';
180
        }
181
182
        if (isset($this->commandTemplates[$name])) {
183
            return false;
184
        }
185
186
        return true;
187
    }
188
189
    protected function mayOverride(bool $fileExists, array $parameters)
190
    {
191
        if (!$fileExists) {
192
            return true;
193
        }
194
195
        // If using reference package then we dont overwrite!
196
        if (!empty($parameters['using'])) {
197
            return false;
198
        }
199
200
        if (!empty($parameters['sync'])) {
201
            return false;
202
        }
203
204
        return true;
205
    }
206
}
207