PlaybookCommand::runPlaybook()   B
last analyzed

Complexity

Conditions 6
Paths 12

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8977
c 0
b 0
f 0
cc 6
nc 12
nop 1
1
<?php
2
3
namespace Scaling\Playbook\Console;
4
5
use Illuminate\Support\Str;
6
use Scaling\Playbook\Playbook;
7
use Illuminate\Console\Command;
8
use Illuminate\Support\Collection;
9
use Illuminate\Console\ConfirmableTrait;
10
use Scaling\Playbook\PlaybookDefenition;
11
12
class PlaybookCommand extends Command
13
{
14
    use ConfirmableTrait;
15
16
    /**
17
     * The name and signature of the console command.
18
     *
19
     * @var string
20
     */
21
    protected $signature = 'playbook:run 
22
                            {playbook? : The name of the playbook you want to run};
23
                            {--force : Force the operation to run when in production}';
24
25
    /**
26
     * The console command description.
27
     *
28
     * @var string
29
     */
30
    protected $description = 'Run a predefined playbook to fill your application.';
31
32
    /**
33
     * List of definitions that has been run.
34
     *
35
     * @var array
36
     */
37
    private $ranDefenitions = [];
38
39
    /**
40
     * Execute the console command.
41
     *
42
     * @return mixed
43
     */
44
    public function handle()
45
    {
46
        if (! $this->confirmToProceed()) {
47
            return;
48
        }
49
50
        if (is_null($name = $this->argument('playbook'))) {
51
            $name = $this->askWhichBook($this->getAvailablePlaybooks());
52
        }
53
54
        $this->call('migrate:refresh');
55
56
        $this->runPlaybook($this->resolvePlaybook($name));
0 ignored issues
show
Bug introduced by
It seems like $name defined by $this->argument('playbook') on line 50 can also be of type array; however, Scaling\Playbook\Console...mand::resolvePlaybook() does only seem to accept object<Scaling\Playbook\...ybookDefinition>|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
57
    }
58
59
    /**
60
     * Run the selected playbook.
61
     *
62
     * @param \Scaling\Playbook\PlaybookDefenition $definition
63
     * @return void
64
     */
65
    private function runPlaybook(PlaybookDefenition $definition): void
66
    {
67
        foreach ($definition->playbook->before() as $book) {
68
            $this->runPlaybook($this->resolvePlaybook($book));
69
        }
70
71
        for ($i = 1; $i <= $definition->times; $i++) {
72
            if ($definition->once && $this->definitionHasRun($definition)) {
73
                continue;
74
            }
75
76
            $name = get_class($definition->playbook);
77
78
            $this->info("Running playbook `{$name}` (#{$i})");
79
80
            $definition->playbook->run($this->input, $this->output);
81
            $definition->playbook->finished();
82
83
            $this->ranDefenitions[$definition->id] = ($this->ranDefenitions[$definition->id] ?? 0) + 1;
84
        }
85
86
        foreach ($definition->playbook->after() as $book) {
87
            $this->runPlaybook($this->resolvePlaybook($book));
88
        }
89
    }
90
91
    /**
92
     * Get a list of available playbooks.
93
     *
94
     * @return array
95
     */
96
    private function getAvailablePlaybooks(): array
97
    {
98
        $files = scandir(config('laravel-playbook.path'));
99
100
        unset($files[0], $files[1]);
101
102
        return Collection::make($files)
103
            ->map(function ($fileName) {
104
                return str_replace('.php', '', $fileName);
105
            })
106
            ->filter(function ($fileName) {
107
                return $fileName !== '.DS_Store';
108
            })
109
            ->values()->toArray();
110
    }
111
112
    /**
113
     * Ask which playbook the developer wants to run.
114
     *
115
     * @param array $available
116
     * @return string
117
     */
118
    private function askWhichBook(array $available): string
119
    {
120
        return $this->choice('Please choose a playbook', $available);
121
    }
122
123
    /**
124
     * Resolve the definition for the given playbook.
125
     *
126
     * @param Scaling\Playbook\Playbook|Scaling\Playbook\PlaybookDefinition|string $class
127
     * @return \Scaling\Playbook\PlaybookDefenition
128
     */
129
    private function resolvePlaybook($class): PlaybookDefenition
130
    {
131
        if ($class instanceof PlaybookDefenition) {
132
            return $class;
133
        }
134
135
        if ($class instanceof Playbook) {
136
            return new PlaybookDefenition(get_class($class));
137
        }
138
139
        $namespace = config('laravel-playbook.namespace');
140
141
        if (! Str::startsWith($class, [$namespace, "\\{$namespace}"])) {
142
            $class = "{$namespace}\\{$class}";
143
        }
144
145
        return new PlaybookDefenition($class);
146
    }
147
148
    /**
149
     * Determine if the given definition has ran before.
150
     *
151
     * @param \Scaling\Playbook\PlaybookDefenition $definition
152
     * @return bool
153
     */
154
    private function definitionHasRun(PlaybookDefenition $definition): bool
155
    {
156
        return isset($this->ranDefenitions[$definition->id]);
157
    }
158
}
159