Creating Artisan tasks that generate files

Published by at 1st January 2018 4:06 pm

While the documentation for creating Artisan tasks is generally pretty good, it doesn't really touch on creating tasks that generate new files. The only way to figure it out was to go digging through the source code. In this case, I was building an Artisan command to create Fractal transformers as part of a package I'm working on.

There's a specialised class for generating files at Illuminate\Console\GeneratorCommand, which your command class should extend instead of Illuminate\Console\Command. In addition to the usual properties such as the signature and description, you also need to specify $type to give the type of class being generated. Also, note that the constructor is different, so if you use php artisan make:console to create the boilerplate for this command, you'll need to delete the constructor.

1<?php
2
3namespace Matthewbdaly\MyPackage\Console\Commands;
4
5use Illuminate\Console\GeneratorCommand;
6use Symfony\Component\Console\Input\InputArgument;
7
8class TransformerMakeCommand extends GeneratorCommand
9{
10 /**
11 * The name and signature of the console command.
12 *
13 * @var string
14 */
15 protected $signature = 'make:transformer {name : The required name of the transformer class}';
16
17 /**
18 * The console command description.
19 *
20 * @var string
21 */
22 protected $description = 'Create a Fractal transformer';
23
24 /**
25 * The type of class being generated.
26 *
27 * @var string
28 */
29 protected $type = 'Fractal transformer';
30
31 /**
32 * Get the stub file for the generator.
33 *
34 * @return string
35 */
36 protected function getStub()
37 {
38 return __DIR__.'/stubs/transformer.stub';
39 }
40
41 /**
42 * Get the console command arguments.
43 *
44 * @return array
45 */
46 protected function getArguments()
47 {
48 return [
49 ['name', InputArgument::REQUIRED, 'The name of the command.'],
50 ];
51 }
52
53 /**
54 * Get the default namespace for the class.
55 *
56 * @param string $rootNamespace
57 * @return string
58 */
59 protected function getDefaultNamespace($rootNamespace)
60 {
61 return $rootNamespace.'\Transformers';
62 }
63}

Note the getDefaultNamespace() method. If your class will live directly under the app folder this is not necessary. Otherwise, it needs to return the root namespace, with the folder structure you want after it. Here my class will live under app\Transformers, so I've set it to reflect that.

Also, note the getStub() method. This tells Artisan that it should use the specified stub file as the basis for our class. Below you'll find the stub file I used for my transformer:

1<?php
2
3namespace DummyNamespace;
4
5use Matthewbdaly\MyPackage\Transformers\BaseTransformer;
6use Illuminate\Database\Eloquent\Model;
7
8class DummyClass extends BaseTransformer
9{
10 public function transform(Model $model)
11 {
12 return [
13 'id' => (int) $model->id,
14 ];
15 }
16}

Note that the DummyNamespace and DummyClass fields will be overwritten with the correct values.

Once this Artisan command is registered in the usual way, you can then run it as follows:

$ php artisan make:transformer Example

And it will generate a boilerplate class something like this:

1<?php
2
3namespace App\Transformers;
4
5use Matthewbdaly\MyPackage\Transformers\BaseTransformer;
6use Illuminate\Database\Eloquent\Model;
7
8class Example extends BaseTransformer
9{
10 public function transform(Model $model)
11 {
12 return [
13 'id' => (int) $model->id,
14 ];
15 }
16}

You can then replace the model with your own one as necessary, and add any further content to this class.