Completed
Push — master ( 21df9f...59a5b3 )
by Korvin
02:20
created

Console::runCallable()   B

Complexity

Conditions 6
Paths 31

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 22.0981

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 4
cts 17
cp 0.2353
rs 8.439
c 0
b 0
f 0
cc 6
eloc 17
nc 31
nop 3
crap 22.0981
1
<?php
2
3
namespace Buttress\Concrete\Console;
4
5
use Buttress\Concrete\Console\Command\CacheCommand;
6
use Buttress\Concrete\CommandBus\Command\HandlerLocator;
7
use Buttress\Concrete\CommandBus\Provider\LegacyProvider;
8
use Buttress\Concrete\CommandBus\Provider\ModernProvider;
9
use Buttress\Concrete\Console\Command\Collection\Collection;
10
use Buttress\Concrete\Console\Command\HelpCommand;
11
use Buttress\Concrete\Console\Command\PackageCommand;
12
use Buttress\Concrete\Exception\BaseException;
13
use Buttress\Concrete\Exception\RuntimeException;
14
use Buttress\Concrete\Exception\VersionMismatchException;
15
use Buttress\Concrete\Locator\Site;
16
use Buttress\Concrete\Route\Dispatcher;
17
use Buttress\Concrete\Route\RouteCollector;
18
use League\CLImate\CLImate;
19
use League\Tactician\Exception\MissingHandlerException;
20
use Psr\Container\ContainerInterface;
21
22
/**
23
 * The main entry point to the c5console project
24
 */
25
class Console
26
{
27
28
    /** @var \Psr\Container\ContainerInterface */
29
    public $container;
30
31
    /** @var \Buttress\Concrete\Console\Command\Collection */
32
    public $collection;
33
34
    /** @var string The last invoked filename */
35
    public $filename;
36
37
    /** @var string The last invoked command string */
38
    public $commandName;
39
40
    /** @var \Buttress\Concrete\Locator\Site */
41
    protected $site;
42
43
    /**
44
     * A list of the available console commands
45
     * @var string[]
46
     */
47
    protected $commands = [
48
        CacheCommand::class,
49
        HelpCommand::class,
50
        PackageCommand::class
51
    ];
52
53
    /**
54
     * A list of CommandBus Handler Providers
55
     * @var string[]
56
     */
57
    protected $providers = [
58
        ModernProvider::class,
59
        LegacyProvider::class
60
    ];
61
62 9
    public function __construct(
63
        ContainerInterface $container,
64
        Collection $collection,
65
        Site $site
66
    ) {
67 9
        $this->container = $container;
68 9
        $this->collection = $collection;
0 ignored issues
show
Documentation Bug introduced by
It seems like $collection of type object<Buttress\Concrete...\Collection\Collection> is incompatible with the declared type object<Buttress\Concrete...ole\Command\Collection> of property $collection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
69 9
        $this->site = $site;
70 9
    }
71
72 3
    public function run(array $arguments)
73
    {
74 3
        $this->filename = array_shift($arguments);
75 3
        $this->commandName = array_shift($arguments);
76
77 3
        $site = $this->site;
78 3
        $cli = $this->container->get(CLImate::class);
79
80 3
        $dispatcher = Dispatcher::simpleDispatcher(function (RouteCollector $routes) use ($site) {
81 3
            foreach ($this->collection->all() as $command) {
82 3
                $command->registerRoutes($routes, $site);
83 3
            }
84 3
        });
85
86 3
        return $this->dispatch($dispatcher, $cli);
87
    }
88
89
    /**
90
     * Prepare to run, this method is used for loading service providers and things like that.
91
     */
92 6
    public function prepare()
93
    {
94 6
        $this->registerCommands();
95 6
        $this->registerHandlers();
96 6
        return $this;
97
    }
98
99
    /**
100
     * @param $dispatcher
101
     * @return int
102
     */
103 3
    protected function dispatch(Dispatcher $dispatcher, CLImate $cli)
104
    {
105 3
        $command = $this->commandName ?: 'help';
106
107 3
        $result = $dispatcher->dispatch($command);
108 3
        switch ($result[0]) {
109 3
            case 0:
110 3
                $cli->error(sprintf('Command "%s" not found.', $command));
111 3
                return 1;
112 3
            case 1:
113 3
                list(, $callable, $data) = $result;
114
115 3
                return $this->runCallable($cli, $callable, $data);
116
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
117
            case 2:
118
                $cli->error(sprintf('Unexpected routing error.'));
119
                return 1;
120
        }
121
    }
122
123 6
    protected function registerCommands()
124
    {
125 6
        foreach ($this->commands as $command) {
126 3
            $this->collection->add($this->container->get($command));
127 6
        }
128 6
    }
129
130 6
    protected function registerHandlers()
131
    {
132 6
        $handler = $this->container->get(HandlerLocator::class);
133 6
        foreach ($this->providers as $provider) {
134 3
            $this->container->get($provider)->register($handler, $this->site);
135 6
        }
136 6
    }
137
138
    /**
139
     * Run a callable
140
     * @param \League\CLImate\CLImate $cli
141
     * @param callable $callable
142
     * @param array $data
143
     * @return int
144
     */
145 3
    private function runCallable(CLImate $cli, $callable, array $data)
146
    {
147
        try {
148 3
            if (is_string($callable)) {
149
                if (strpos($callable, '::')) {
150
                    list($class, $method) = explode('::', $callable, 2);
151
                    $callable = [$this->container->get($class), $method];
152
                } else {
153
                    $callable = $this->container->get($callable);
154
                }
155
            }
156
157 3
            if (!is_callable($callable)) {
158
                throw new RuntimeException('Invalid route callable');
159
            }
160
161 3
            return $callable($this->site, ...$data);
162
        } catch (VersionMismatchException $e) {
163
            $cli->error('Invalid Version: ' . $e->getMessage())
164
                ->dim(sprintf('Detected version "%s"', $e->getVersion()));
165
        } catch (BaseException $e) {
166
            $cli->error('Runtime Error: ' . $e->getMessage());
167
        }
168
169
        return 1;
170
    }
171
}
172