Passed
Push — ft/package ( 5ee474...180175 )
by Philippe
05:16 queued 12s
created

GeneratePage::publishController()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
ccs 0
cts 5
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Thinktomorrow\Chief\Pages\Console;
4
5
use Illuminate\Filesystem\Filesystem;
6
use Illuminate\Support\Str;
7
use Thinktomorrow\Chief\App\Console\BaseCommand;
8
use Thinktomorrow\Chief\Common\Traits\Publishable;
9
use Thinktomorrow\Chief\Common\Traits\Sortable;
10
11
class GeneratePage extends BaseCommand
12
{
13
    protected $signature = 'chief:page 
14
                            {name : the name for the page model in singular.}
15
                            {--force : Overwrite any existing files.}';
16
17
    protected $description = 'Generate a new page model and associated controller, routes and views.';
18
19
    private $filesystem;
20
    private $settings;
21
22
    private $dirs;
23
    private $files;
24
25
    private $chosenTraits = [];
26
27
    private $singular;
28
    private $plural;
29
30 82
    public function __construct(Filesystem $filesystem, array $settings = [])
31
    {
32 82
        parent::__construct();
33
34 82
        $this->filesystem = $filesystem;
35 82
        $this->settings = $settings;
36
37
        // Set required paths
38 82
        $this->dirs = ['base' => $this->settings['base_path'] ?? base_path()];
39 82
        $this->dirs['model'] = $this->settings['model_path'] ?? $this->dirs['base'].'/src';
40 82
        $this->dirs['views'] = $this->settings['views_path'] ?? $this->dirs['base'].'/resources/views';
41 82
        $this->dirs['controller'] = $this->settings['controller_path'] ?? $this->dirs['base'].'/app/Http/Controllers';
42
43 82
        $this->files['routes'] = $this->settings['routes_file'] ?? $this->dirs['base'].'/routes/web.php';
44 82
    }
45
46
    public function handle()
47
    {
48
        $this->singular = $this->argument('name');
49
        $this->plural = Str::plural($this->singular);
0 ignored issues
show
Bug introduced by
It seems like $this->singular can also be of type array; however, parameter $value of Illuminate\Support\Str::plural() 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

49
        $this->plural = Str::plural(/** @scrutinizer ignore-type */ $this->singular);
Loading history...
50
51
        $this->promptForModelTraits();
52
        // anticipate model name and check if file already exists
53
        // Yes: ask to override or keep exisint (default)
54
        // -> Generate model
55
56
        $this->publishModel();
57
//        $this->publishController();
58
    }
59
60
    private function publishModel()
61
    {
62
        $this->publishFile(
63
            __DIR__ . '/stubs/model.php.stub',
64
            $to = $this->dirs['model'] . '/' . ucfirst($this->plural) . '/' . ucfirst($this->singular) . '.php',
65
            'model'
66
        );
67
    }
68
69
    private function publishController()
0 ignored issues
show
Unused Code introduced by
The method publishController() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
70
    {
71
        $this->publishFile(
72
            __DIR__ . '/stubs/controller.php.stub',
73
            $to = $this->dirs['controller'] . '/' . ucfirst($this->plural) . '/' . ucfirst($this->singular) . '.php',
74
            'controller'
75
        );
76
    }
77
78
    /**
79
     * Prompt for which provider or tag to publish.
80
     *
81
     * @return void
82
     */
83
    protected function promptForModelTraits()
84
    {
85
        $choice = null;
86
87
        while (!in_array($choice, ['q'])) {
88
            $choice = $this->choice(
89
                "Which model options would you like to set up?",
90
                $choices = $this->modelTraits(),
91
                'q' // Default is to just continue without traits
92
            );
93
94
            if (!in_array($choice, ['q'])) {
95
                $this->chooseTrait($choices[$choice]);
96
            }
97
        }
98
    }
99
100
    protected function chooseTrait(string $trait)
101
    {
102
        if (in_array($trait, $this->chosenTraits)) {
103
            return;
104
        }
105
106
        $this->chosenTraits[] = $trait;
107
    }
108
109
    private function modelTraits()
110
    {
111
        return [
112
            Publishable::class,
113
            Sortable::class,
114
            'q' => 'Proceed.',
115
        ];
116
    }
117
118
    /**
119
     * Publish the file to the given path.
120
     *
121
     * @param  string $from
122
     * @param  string $to
123
     * @return void
124
     */
125
    protected function publishFile($from, $to, $type)
126
    {
127
        if ($this->filesystem->exists($to) && !$this->option('force')) {
128
            if (!$this->confirm('File [' . $to . '] already exists? Overwrite this file?')) {
129
                return;
130
            }
131
        }
132
133
        $this->createParentDirectory(dirname($to));
134
135
        $this->filesystem->put($to, $this->replacePlaceholders(file_get_contents($from)));
136
137
        $this->status($from, $to, $type);
138
    }
139
140
    /**
141
     * Create the directory to house the published files if needed.
142
     *
143
     * @param  string $directory
144
     * @return void
145
     */
146
    protected function createParentDirectory($directory)
147
    {
148
        if (!$this->filesystem->isDirectory($directory)) {
149
            $this->filesystem->makeDirectory($directory, 0755, true);
150
        }
151
    }
152
153
    /**
154
     * Write a status message to the console.
155
     *
156
     * @param  string $from
157
     * @param  string $to
158
     * @param  string $type
159
     * @return void
160
     */
161
    protected function status($from, $to, $type)
162
    {
163
        $from = str_replace($this->dirs['base'], '', realpath($from));
164
165
        $to = str_replace($this->dirs['base'], '', realpath($to));
166
167
        $this->line('<info>Copied ' . $type . '</info> <comment>[' . $from . ']</comment> <info>To</info> <comment>[' . $to . ']</comment>');
168
    }
169
170
    protected function replacePlaceholders($content)
171
    {
172
        $replacements = [
173
            '##NAMESPACE##' => $this->guessNamespace(), // TODO: how to determine proper namespace?
174
            '##CLASSNAME##' => ucfirst($this->singular),
175
            '##TABLENAME##' => strtolower($this->plural),
176
            '##IMPORTS##'   => $this->generateImportStatements(),
177
            '##TRAITS##'    => $this->generateTraitStatements(),
178
        ];
179
180
        return str_replace(array_keys($replacements), array_values($replacements), $content);
181
    }
182
183
    private function generateImportStatements(): string
184
    {
185
        return collect(['Illuminate\Database\Eloquent\Model'])
186
            ->map(function ($statement) {
187
                return 'use ' . $statement . ";\n    ";
188
            })->implode('');
189
    }
190
191
    private function generateTraitStatements(): string
192
    {
193
        return collect($this->chosenTraits)
194
            ->map(function ($statement) {
195
                return 'use ' . $statement . ";\n    ";
196
            })->implode('');
197
    }
198
199
    private function guessNamespace()
200
    {
201
        if (isset($this->settings['namespace'])) {
202
            return $this->settings['namespace'];
203
        }
204
205
        // We make an estimated guess based on the project name. At Think Tomorrow, we
206
        // have a src folder which is PSR-4 namespaced by the project name itself.
207
        return ucfirst(config('thinktomorrow.chief.name', 'App')).'\\'. ucfirst($this->plural);
208
    }
209
}
210