Passed
Pull Request — master (#14)
by
unknown
12:13
created

YamlCommands   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 67
c 5
b 0
f 0
dl 0
loc 163
ccs 0
cts 83
cp 0
rs 10
wmc 25

5 Methods

Rating   Name   Duplication   Size   Complexity  
B bindInputOptionsToConfig() 0 47 10
A getConfigurationFile() 0 3 1
A getDefaultConfigurationFile() 0 3 1
B runTasks() 0 44 7
A runPreconditions() 0 32 6
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace PhpTaskman\Core\Robo\Plugin\Commands;
6
7
use Consolidation\AnnotatedCommand\AnnotatedCommand;
8
use PhpTaskman\CoreTasks\Plugin\Task\CollectionFactoryTask;
9
use Robo\Collection\CollectionBuilder;
10
use Robo\Contract\VerbosityThresholdInterface;
11
use Robo\Exception\TaskException;
12
use Symfony\Component\Console\Event\ConsoleCommandEvent;
13
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
14
use Symfony\Component\ExpressionLanguage\SyntaxError;
15
16
/**
17
 * Class DynamicCommands.
18
 */
19
final class YamlCommands extends AbstractCommands
20
{
21
    /**
22
     * Bind input values of custom command options to config entries.
23
     *
24
     * @param \Symfony\Component\Console\Event\ConsoleCommandEvent $event
25
     *
26
     * @hook pre-command-event *
27
     */
28
    public function bindInputOptionsToConfig(ConsoleCommandEvent $event): void
29
    {
30
        $command = $event->getCommand();
31
32
        if (null === $command) {
33
            return;
34
        }
35
36
        if (AnnotatedCommand::class !== \get_class($command)) {
37
            return;
38
        }
39
40
        if (!($command instanceof AnnotatedCommand)) {
41
            return;
42
        }
43
44
        /** @var \Consolidation\AnnotatedCommand\AnnotatedCommand $command */
45
        /** @var \Consolidation\AnnotatedCommand\AnnotationData $annotatedData */
46
        $annotatedData = $command->getAnnotationData();
47
48
        if (!$annotatedData->get('dynamic-command')) {
49
            return;
50
        }
51
52
        // Dynamic commands may define their own options bound to specific configuration. Dynamically set the
53
        // configuration from command options.
54
        $config = $this->getConfig();
55
        $commands = $config->get('commands');
56
57
        if (empty($commands[$command->getName()]['options'])) {
58
            return;
59
        }
60
61
        foreach ($commands[$command->getName()]['options'] as $optionName => $option) {
62
            if (empty($option['config']) && $event->getInput()->hasOption($optionName)) {
63
                continue;
64
            }
65
66
            $inputValue = $event->getInput()->getOption($optionName);
67
68
            if (null === $inputValue) {
69
                continue;
70
            }
71
72
            $config->set(
73
                $option['config'],
74
                $event->getInput()->getOption($optionName)
75
            );
76
        }
77
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82
    public function getConfigurationFile(): string
83
    {
84
        return __DIR__ . '/../../../../config/commands/default.yml';
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function getDefaultConfigurationFile(): string
91
    {
92
        return __DIR__ . '/../../../../config/default.yml';
93
    }
94
95
    /**
96
     * Run a task.
97
     *
98
     * @dynamic-command true
99
     *
100
     * @throws \Robo\Exception\TaskException
101
     *
102
     * @return \Robo\Collection\CollectionBuilder
103
     */
104
    public function runTasks(): CollectionBuilder
105
    {
106
        $command = $this->input()->getArgument('command');
107
108
        if (!\is_string($command)) {
109
            throw new TaskException($this, 'The command must be a string.');
110
        }
111
112
        $inputOptions = [];
113
114
        foreach ($this->input()->getOptions() as $name => $value) {
115
            if ($this->input()->hasParameterOption('--' . $name)) {
116
                $inputOptions[$name] = $value;
117
            }
118
        }
119
120
        $command = $this->getConfig()->get('commands.' . $command);
121
122
        // Handle different types of command definitions.
123
        if (isset($command['tasks'])) {
124
            $arguments = [
125
                'tasks' => $command['tasks'],
126
                'options' => $inputOptions,
127
                'preconditions' => $command['preconditions'] ?? [],
128
            ];
129
130
            if (\is_string($arguments['preconditions'])) {
131
                $arguments['preconditions'] = [$arguments['preconditions']];
132
            }
133
134
            if (false === $this->runPreconditions($arguments['preconditions'])) {
135
                $arguments['tasks'] = [];
136
            }
137
        } else {
138
            $arguments = [
139
                'tasks' => $command,
140
                'options' => [],
141
            ];
142
        }
143
144
        /** @var CollectionFactoryTask $collectionFactory */
145
        $collectionFactory = $this->task(CollectionFactoryTask::class);
146
147
        return $collectionFactory->setTaskArguments($arguments);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $collectionFactor...skArguments($arguments) returns the type PhpTaskman\CoreTasks\Plu...k\CollectionFactoryTask which is incompatible with the type-hinted return Robo\Collection\CollectionBuilder.
Loading history...
148
    }
149
150
    private function runPreconditions(array $preconditions): bool
151
    {
152
        if (!\count($preconditions)) {
153
            return true;
154
        }
155
156
        foreach ($preconditions as $key => $precondition) {
157
            if (preg_match('/^\((.*)\)$/', $precondition, $matches)) {
158
                $expressionLanguage = new ExpressionLanguage();
159
160
                try {
161
                    $result = $expressionLanguage->evaluate($matches[1], $this->input()->getOptions());
162
                } catch (SyntaxError $ex) {
163
                    $result = false;
164
                }
165
166
                if (false === $result) {
167
                    return false;
168
                }
169
                unset($preconditions[$key]);
170
            }
171
        }
172
173
        /** @var CollectionFactoryTask $preconditionsTask */
174
        $preconditionsTask = $this->task(CollectionFactoryTask::class);
175
        $preconditionsTask->setVerbosityThreshold(VerbosityThresholdInterface::VERBOSITY_DEBUG);
176
        $preconditionsTask->setTaskArguments([
177
            'tasks' => $preconditions,
178
            'options' => [],
179
        ]);
180
181
        return $preconditionsTask->run()->wasSuccessful();
182
    }
183
}
184