Completed
Push — master ( b0a68c...0157fa )
by Martijn van
02:24
created

AbstractMakeCommand::classExists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
4
use Symfony\Component\Console\Input\InputArgument;
5
use Symfony\Component\Console\Input\InputOption;
6
7
abstract class AbstractMakeCommand extends SilverstripeCommand
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
8
{
9
    /**
10
     * @config
11
     *
12
     * @var array
13
     */
14
    private static $default_dirs = [
15
        'Command'             => 'mysite/code/commands',
16
        'Controller'          => 'mysite/code/controllers',
17
        'ControllerExtension' => 'mysite/code/extensions',
18
        'DataObject'          => 'mysite/code/dataobjects',
19
        'DataExtension'       => 'mysite/code/extensions',
20
        'Extension'           => 'mysite/code/extensions',
21
        'Form'                => 'mysite/code/forms',
22
        'Page'                => 'mysite/code/pages',
23
        'Test'                => 'mysite/tests',
24
        'Theme'               => 'themes',
25
    ];
26
27
    public function fire()
28
    {
29
        $class = $this->getNameInput();
30
31
        if (!(bool) $class) {
32
            $this->error('Empty name given. Are you running a test?');
33
34
            return false;
35
        }
36
37
        $target = $this->getTargetFile($class);
38
39
        if ($this->classOrFileExists($target, $class)) {
40
            return false;
41
        }
42
43
        $this->writeFile($target, $class);
44
45
        $this->clearCache();
46
    }
47
48
    /**
49
     * @param string $target
50
     * @param string $class
51
     *
52
     * @return bool
53
     */
54
    protected function classOrFileExists($target, $class)
55
    {
56
        if ($this->classExists($class)) {
57
            $this->error('class '.$class.' already exists!');
58
59
            return true;
60
        } elseif ($this->fileExists($class)) {
61
            $this->error('file '.str_replace(BASE_PATH, '', $target).' already exists!');
62
63
            return true;
64
        }
65
66
        return false;
67
    }
68
69
    /**
70
     * @param string $target
71
     * @param string $class
72
     */
73
    protected function writeFile($target, $class)
74
    {
75
        $this->makeDirectory();
76
77
        file_put_contents($target, $this->buildClass($class));
78
79
        $this->info($class.' created successfully in '.str_replace(BASE_PATH, '', $target));
80
    }
81
82
    protected function clearCache()
83
    {
84
        if ($this->option('clearcache')) {
85
            $this->call('cache:clear');
86
        } else {
87
            $this->warn('to use the class, please run cache:clear or add the --clearcache next time');
88
        }
89
    }
90
91
    /**
92
     * @return string
93
     */
94
    public function getPhpStub()
95
    {
96
        return $this->getStubFilePath($this->getCommandClass());
97
    }
98
99
    /**
100
     * @return string
101
     */
102
    public function getTemplateStub()
103
    {
104
        return Str::replaceLast('.php.stub', '.ss.stub', $this->getPhpStub());
105
    }
106
107
    /**
108
     * @return string
109
     */
110
    public function getTargetDirectory()
111
    {
112
        $class = $this->getCommandClass();
113
        $dirs = (array) self::$default_dirs;
114
        $custom = $this->getTargetDirectoryByOptionOrConfig();
115
116
        // --dir=mymodule || MakeCommand.default_dirs = mymodule || MakeCommand.default_dirs = mymodule/somedir
117
        if (is_string($custom)) {
118
            $dirs = $this->setTargetDirectoriesByString($custom, $dirs);
119
            if (is_string($dirs)) {
120
                return $dirs;
121
            }
122
        // MakeCommand.default_dirs = array()
123
        } elseif (is_array($custom)) {
124
            $dirs = $this->mergeCustomDirectoriesWithDefault($custom, $dirs);
125
        }
126
127
        return isset($dirs[$class]) ? BASE_PATH.'/'.$dirs[$class] : '';
128
    }
129
130
    /**
131
     * @param string $customDir
132
     * @param array  $defaultDirs
133
     *
134
     * @return string|array
135
     */
136
    protected function setTargetDirectoriesByString($customDir, $defaultDirs)
137
    {
138
        // MakeCommand.default_dirs = mymodule/somedir
139
        if (Str::contains($customDir, '/')) {
140
            return BASE_PATH.'/'.$customDir;
141
        }
142
143
        // MakeCommand.default_dirs = mymodule
144
        foreach ($defaultDirs as $key => $dir) {
145
            $defaultDirs[$key] = Str::replaceFirst('mysite', $customDir, $dir);
146
        }
147
148
        return $defaultDirs;
149
    }
150
151
    /**
152
     * @param array $customDirs
153
     * @param array $defaultDirs
154
     *
155
     * @return array
156
     */
157
    protected function mergeCustomDirectoriesWithDefault($customDirs, $defaultDirs)
158
    {
159
        foreach ($customDirs as $key => $dir) {
160
            if (is_string($key)) {
161
                $defaultDirs[$key] = $dir;
162
            }
163
        }
164
165
        return $defaultDirs;
166
    }
167
168
    /**
169
     * The absolute file path.
170
     *
171
     * @return string
172
     */
173
    public function getTargetFile($class)
174
    {
175
        return $this->getTargetDirectory().'/'.$class.'.php';
176
    }
177
178
    /**
179
     * Gets the Classname to generate from the called class like
180
     * MakeDataObjectCommand => DataObject class
181
     * MakeFormCommand       => Form class.
182
     *
183
     * @return string
184
     */
185
    public function getCommandClass()
186
    {
187
        $class = get_class($this);
188
        $class = Str::replaceFirst('Make', '', $class);
189
        $class = Str::replaceLast('Command', '', $class);
190
191
        return $class;
192
    }
193
194
    /**
195
     * @return string|array|int|float|bool
196
     */
197
    protected function getTargetDirectoryByOptionOrConfig()
198
    {
199
        if ($this->option('dir')) {
200
            return $this->option('dir');
201
        }
202
203
        return Config::inst()->get('MakeCommand', 'default_dirs');
204
    }
205
206
    /**
207
     * @return string
208
     */
209
    protected function getStubFilePath($stubName)
210
    {
211
        $customStubFilePath = $this->getCustomStubPath($stubName);
212
        if (is_file($customStubFilePath)) {
213
            return $customStubFilePath;
214
        }
215
216
        $mysiteStubFilePath = $this->getCustomStubPath($stubName);
217
218
        if (is_file($mysiteStubFilePath)) {
219
            return $mysiteStubFilePath;
220
        }
221
222
        return $this->getConsoleStubPath($stubName);
223
    }
224
225
    /**
226
     * @return string
227
     */
228
    protected function getConsoleStubPath($stubName)
229
    {
230
        return BASE_PATH.'/console/stubs/'.$stubName.'.php.stub';
231
    }
232
233
    /**
234
     * @return string
235
     */
236
    protected function getMySiteStubPath($stubName)
237
    {
238
        return BASE_PATH.'/mysite/stubs/'.$stubName.'.php.stub';
239
    }
240
241
    /**
242
     * @return string
243
     */
244
    protected function getCustomStubPath($stubName)
245
    {
246
        $stubDir = Config::inst()->get('MakeCommand', 'stub_dir');
247
248
        if ($stubDir) {
249
            return BASE_PATH.'/'.$stubDir.'/'.$stubName.'.php.stub';
250
        }
251
252
        return '';
253
    }
254
255
    /**
256
     * @param $class
257
     *
258
     * @return bool
259
     */
260
    protected function fileExists($class)
261
    {
262
        return is_file($this->getTargetFile($class));
263
    }
264
265
    /**
266
     * @param $class
267
     *
268
     * @return bool
269
     */
270
    protected function classExists($class)
271
    {
272
        $loader = SS_ClassLoader::instance();
273
        $exists = $loader->classExists($class);
274
        $path = $loader->getItemPath($class);
275
276
        return $exists && is_file($path);
277
    }
278
279
    /**
280
     * Build the directory for the class if necessary.
281
     */
282
    protected function makeDirectory()
283
    {
284
        $path = $this->getTargetDirectory();
285
286
        if (!is_dir($path)) {
287
            mkdir($path, 0777, true);
288
289
            $this->info('directory '.str_replace(BASE_PATH, '', $path).' created');
290
        }
291
    }
292
293
    /**
294
     * Replace the class name for the given stub.
295
     *
296
     * @param string $class
297
     *
298
     * @return string
299
     */
300
    protected function buildClass($class)
301
    {
302
        return str_replace('DummyClass', $class, file_get_contents($this->getPhpStub()));
303
    }
304
305
    /**
306
     * Get the desired class name from the input.
307
     *
308
     * @return string
309
     */
310
    protected function getNameInput()
311
    {
312
        return (string) $this->argument('name');
313
    }
314
315
    protected function getOptions()
316
    {
317
        return [
318
            ['clearcache', 'c', InputOption::VALUE_NONE, 'Clear the cache after adding the class'],
319
            ['dir', 'd', InputOption::VALUE_OPTIONAL, 'Set the directory to write the file to'],
320
        ];
321
    }
322
323
    /**
324
     * Get the console command arguments.
325
     *
326
     * @return array
327
     */
328
    protected function getArguments()
329
    {
330
        return [
331
            ['name', InputArgument::REQUIRED, 'The name of the class'],
332
        ];
333
    }
334
}
335