TaskCommand::configure()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of Bldr.io
5
 *
6
 * (c) Aaron Scherer <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE
10
 */
11
12
namespace Bldr\Block\Core\Command;
13
14
use Bldr\Block\Core\Task\AbstractTask;
15
use Bldr\Command\AbstractCommand;
16
use Bldr\Task\TaskInterface;
17
use Symfony\Component\Console\Input\InputArgument;
18
19
/**
20
 * @author Aaron Scherer <[email protected]>
21
 */
22
class TaskCommand extends AbstractCommand
23
{
24
    protected function configure()
25
    {
26
        $this->setName('task')
27
            ->setDescription('Runs a single task')
28
            ->addArgument('name', InputArgument::REQUIRED, 'Task to use')
29
            ->setHelp(
30
                <<<EOF
31
32
The <info>%command.name%</info> runs the given task.
33
34
To use:
35
36
    <info>$ bldr %command.name% <task name></info>
37
38
To pass arguments:
39
40
    <info>$ bldr %command.name% <task name> --executable=echo --arguments=["Hello", "World"]</info>
41
42
EOF
43
            )
44
            ->ignoreValidationErrors()
45
        ;
46
    }
47
48
    /**
49
     * {@inheritDoc}
50
     */
51
    protected function doExecute()
52
    {
53
        $service = $this->findCall($this->input->getArgument('name'), $this->getOptions());
54
55
        $service->run($this->output);
56
    }
57
58
    /**
59
     * @param string $name
60
     *
61
     * @param array $options
62
     *
63
     * @throws \Exception
64
     * @return TaskInterface|AbstractTask
65
     */
66
    private function findCall($name, array $options = [])
67
    {
68
        $tasks    = array_keys($this->container->findTaggedServiceIds('bldr'));
0 ignored issues
show
Bug introduced by
The method findTaggedServiceIds does only exist in Symfony\Component\Depend...ection\ContainerBuilder, but not in Symfony\Component\Depend...tion\ContainerInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
69
        $services = [];
70
        foreach ($tasks as $serviceName) {
71
            /** @var TaskInterface|AbstractTask $service */
72
73
            $service = $this->container->get($serviceName);
74
            if ($service instanceof AbstractTask) {
75
                $service->configure();
76
            }
77
78
            if (method_exists($service, 'setEventDispatcher')) {
79
                $service->setEventDispatcher($this->container->get('bldr.dispatcher'));
80
            }
81
82
            foreach ($options as $name => $value) {
83
                $service->setParameter($name, $value);
84
            }
85
86
            if (method_exists($service, 'validate')) {
87
                $service->validate();
88
            }
89
90
            if ($service->getName() === $name) {
91
                $services[] = $service;
92
            }
93
        }
94
95
        if (sizeof($services) > 1) {
96
            throw new \Exception("Multiple calls exist with the '{$name}' tag.");
97
        }
98
        if (sizeof($services) === 0) {
99
            throw new \Exception("No task type found for {$name}.");
100
        }
101
102
        return $services[0];
103
    }
104
105
    /**
106
     * This method takes the Argv, and parses out all the options passed.
107
     *
108
     * @return array
109
     * @throws \Exception
110
     */
111
    private function getOptions()
112
    {
113
        $inputString = (string) $this->input;
114
        $options     = [];
115
116
        // Remove the first two arguments from the array (c/call and the name)
117
        $content = explode(' ', $inputString, 3);
118
        if (sizeof($content) > 2 && strpos($inputString, '=') === false) {
119
            throw new \Exception("Option syntax should contain an equal sign. Ex: --executable=php");
120
        }
121
        if (sizeof($content) > 2 && strpos($inputString, '--') === false) {
122
            throw new \Exception("Option syntax should contain double dashes. Ex: --executable=php");
123
        }
124
125
        // Parse out all of the options
126
        $pieces = explode('--', $content[2]);
127
        array_shift($pieces);
128
129
        foreach ($pieces as $piece) {
130
            $piece = trim($piece);
131
            list($name, $value) = explode('=', $piece, 2);
132
133
            if (strpos($value, "'[") === 0 && strpos($value, "]'") === (strlen($value) - 2)) {
134
                $csv   = trim(str_replace(['[', ']'], '', $value), "'");
135
                $value = str_getcsv($csv, ',');
136
            }
137
138
            $options[$name] = $value;
139
        }
140
141
        return $options;
142
    }
143
}
144