Completed
Push — master ( efd4b5...cdc15c )
by Greg
11s
created

Robo::process()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
namespace Robo;
3
4
use League\Container\Container;
5
use League\Container\ContainerInterface;
6
use Robo\Common\ProcessExecutor;
7
use Symfony\Component\Console\Input\StringInput;
8
use Symfony\Component\Console\Application as SymfonyApplication;
9
use Symfony\Component\Process\Process;
10
11
/**
12
 * Manages the container reference and other static data.  Favor
13
 * using dependency injection wherever possible.  Avoid using
14
 * this class directly, unless setting up a custom DI container.
15
 */
16
class Robo
17
{
18
    const APPLICATION_NAME = 'Robo';
19
    const VERSION = '1.0.6-dev';
20
21
    /**
22
     * The currently active container object, or NULL if not initialized yet.
23
     *
24
     * @var ContainerInterface|null
25
     */
26
    protected static $container;
27
28
    /**
29
     * Entrypoint for standalone Robo-based tools.  See docs/framework.md.
30
     *
31
     * @param string[] $argv
32
     * @param string $commandClasses
33
     * @param null|string $appName
34
     * @param null|string $appVersion
35
     * @param null|\Symfony\Component\Console\Output\OutputInterface $output
36
     *
37
     * @return int
38
     */
39
    public static function run($argv, $commandClasses, $appName = null, $appVersion = null, $output = null)
40
    {
41
        $runner = new \Robo\Runner($commandClasses);
42
        $statusCode = $runner->execute($argv, $appName, $appVersion, $output);
43
        return $statusCode;
44
    }
45
46
    /**
47
     * Sets a new global container.
48
     *
49
     * @param ContainerInterface $container
50
     *   A new container instance to replace the current.
51
     */
52
    public static function setContainer(ContainerInterface $container)
53
    {
54
        static::$container = $container;
55
    }
56
57
    /**
58
     * Unsets the global container.
59
     */
60
    public static function unsetContainer()
61
    {
62
        static::$container = null;
63
    }
64
65
    /**
66
     * Returns the currently active global container.
67
     *
68
     * @return \League\Container\ContainerInterface
69
     *
70
     * @throws \RuntimeException
71
     */
72
    public static function getContainer()
73
    {
74
        if (static::$container === null) {
75
            throw new \RuntimeException('container is not initialized yet. \Robo\Robo::setContainer() must be called with a real container.');
76
        }
77
        return static::$container;
78
    }
79
80
    /**
81
     * Returns TRUE if the container has been initialized, FALSE otherwise.
82
     *
83
     * @return bool
84
     */
85
    public static function hasContainer()
86
    {
87
        return static::$container !== null;
88
    }
89
90
    /**
91
     * Create a container and initiailze it.  If you wish to *change*
92
     * anything defined in the container, then you should call
93
     * \Robo::configureContainer() instead of this function.
94
     *
95
     * @param null|\Symfony\Component\Console\Input\InputInterface $input
96
     * @param null|\Symfony\Component\Console\Output\OutputInterface $output
97
     * @param null|\Robo\Application $app
98
     * @param null|\Robo\Config $config
99
     *
100
     * @return \League\Container\Container|\League\Container\ContainerInterface
101
     */
102
    public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null)
103
    {
104
        // Do not allow this function to be called more than once.
105
        if (static::hasContainer()) {
106
            return static::getContainer();
107
        }
108
109
        if (!$app) {
110
            $app = static::createDefaultApplication();
111
        }
112
113
        if (!$config) {
114
            $config = new Config();
115
        }
116
117
        // Set up our dependency injection container.
118
        $container = new Container();
119
        static::configureContainer($container, $app, $config, $input, $output);
120
121
        // Set the application dispatcher
122
        $app->setDispatcher($container->get('eventDispatcher'));
123
124
        return $container;
125
    }
126
127
    /**
128
     * Initialize a container with all of the default Robo services.
129
     * IMPORTANT:  after calling this method, clients MUST call:
130
     *
131
     * $dispatcher = $container->get('eventDispatcher');
132
     * $app->setDispatcher($dispatcher);
133
     *
134
     * Any modification to the container should be done prior to fetching
135
     * objects from it.
136
     *
137
     * It is recommended to use \Robo::createDefaultContainer()
138
     * instead, which does all required setup for the caller, but has
139
     * the limitation that the container it creates can only be
140
     * extended, not modified.
141
     *
142
     * @param \League\Container\ContainerInterface $container
143
     * @param \Symfony\Component\Console\Application $app
144
     * @param \Robo\Config $config
145
     * @param null|\Symfony\Component\Console\Input\InputInterface $input
146
     * @param null|\Symfony\Component\Console\Output\OutputInterface $output
147
     */
148
    public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, Config $config, $input = null, $output = null)
149
    {
150
        // Self-referential container refernce for the inflector
151
        $container->add('container', $container);
152
        static::setContainer($container);
153
154
        // Create default input and output objects if they were not provided
155
        if (!$input) {
156
            $input = new StringInput('');
157
        }
158
        if (!$output) {
159
            $output = new \Symfony\Component\Console\Output\ConsoleOutput();
160
        }
161
        $config->setDecorated($output->isDecorated());
162
163
        $container->share('application', $app);
164
        $container->share('config', $config);
165
        $container->share('input', $input);
166
        $container->share('output', $output);
167
        $container->share('outputAdapter', \Robo\Common\OutputAdapter::class);
168
169
        // Register logging and related services.
170
        $container->share('logStyler', \Robo\Log\RoboLogStyle::class);
171
        $container->share('logger', \Robo\Log\RoboLogger::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
172
            ->withArgument('output')
173
            ->withMethodCall('setLogOutputStyler', ['logStyler']);
174
        $container->add('progressBar', \Symfony\Component\Console\Helper\ProgressBar::class)
175
            ->withArgument('output');
176
        $container->share('progressIndicator', \Robo\Common\ProgressIndicator::class)
177
            ->withArgument('progressBar')
178
            ->withArgument('output');
179
        $container->share('resultPrinter', \Robo\Log\ResultPrinter::class);
180
        $container->add('simulator', \Robo\Task\Simulator::class);
181
        $container->share('globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class);
182
        $container->share('collectionProcessHook', \Robo\Collection\CollectionProcessHook::class);
183
        $container->share('hookManager', \Consolidation\AnnotatedCommand\Hooks\HookManager::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
184
            ->withMethodCall('addResultProcessor', ['collectionProcessHook', '*']);
185
        $container->share('alterOptionsCommandEvent', \Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent::class)
186
            ->withArgument('application');
187
        $container->share('eventDispatcher', \Symfony\Component\EventDispatcher\EventDispatcher::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
188
            ->withMethodCall('addSubscriber', ['globalOptionsEventListener'])
189
            ->withMethodCall('addSubscriber', ['alterOptionsCommandEvent'])
190
            ->withMethodCall('addSubscriber', ['hookManager']);
191
        $container->share('formatterManager', \Consolidation\OutputFormatters\FormatterManager::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
192
            ->withMethodCall('addDefaultFormatters', [])
193
            ->withMethodCall('addDefaultSimplifiers', []);
194
        $container->share('prepareTerminalWidthOption', \Consolidation\AnnotatedCommand\Options\PrepareTerminalWidthOption::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
195
            ->withMethodCall('setApplication', ['application']);
196
        $container->share('commandProcessor', \Consolidation\AnnotatedCommand\CommandProcessor::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
197
            ->withArgument('hookManager')
198
            ->withMethodCall('setFormatterManager', ['formatterManager'])
199
            ->withMethodCall('addPrepareFormatter', ['prepareTerminalWidthOption'])
200
            ->withMethodCall(
201
                'setDisplayErrorFunction',
202
                [
203
                    function ($output, $message) use ($container) {
204
                        $logger = $container->get('logger');
205
                        $logger->error($message);
206
                    }
207
                ]
208
            );
209
        $container->share('commandFactory', \Consolidation\AnnotatedCommand\AnnotatedCommandFactory::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\Container\Definition\DefinitionInterface as the method withMethodCall() does only exist in the following implementations of said interface: League\Container\Definition\ClassDefinition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
210
            ->withMethodCall('setCommandProcessor', ['commandProcessor']);
211
        $container->add('collection', \Robo\Collection\Collection::class);
212
        $container->add('collectionBuilder', \Robo\Collection\CollectionBuilder::class);
213
        $container->add('processExecutor', ProcessExecutor::class);
214
215
        static::addInflectors($container);
216
217
        // Make sure the application is appropriately initialized.
218
        $app->setAutoExit(false);
219
    }
220
221
    /**
222
     * @param null|string $appName
223
     * @param null|string $appVersion
224
     *
225
     * @return \Robo\Application
226
     */
227
    public static function createDefaultApplication($appName = null, $appVersion = null)
228
    {
229
        $appName = $appName ?: self::APPLICATION_NAME;
230
        $appVersion = $appVersion ?: self::VERSION;
231
232
        $app = new \Robo\Application($appName, $appVersion);
233
        $app->setAutoExit(false);
234
        return $app;
235
    }
236
237
    /**
238
     * Add the Robo League\Container inflectors to the container
239
     *
240
     * @param \League\Container\ContainerInterface $container
241
     */
242
    public static function addInflectors($container)
243
    {
244
        // Register our various inflectors.
245
        $container->inflector(\Robo\Contract\ConfigAwareInterface::class)
246
            ->invokeMethod('setConfig', ['config']);
247
        $container->inflector(\Psr\Log\LoggerAwareInterface::class)
248
            ->invokeMethod('setLogger', ['logger']);
249
        $container->inflector(\League\Container\ContainerAwareInterface::class)
250
            ->invokeMethod('setContainer', ['container']);
251
        $container->inflector(\Symfony\Component\Console\Input\InputAwareInterface::class)
252
            ->invokeMethod('setInput', ['input']);
253
        $container->inflector(\Robo\Contract\OutputAwareInterface::class)
254
            ->invokeMethod('setOutput', ['output']);
255
        $container->inflector(\Robo\Contract\ProgressIndicatorAwareInterface::class)
256
            ->invokeMethod('setProgressIndicator', ['progressIndicator']);
257
        $container->inflector(\Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface::class)
258
            ->invokeMethod('setHookManager', ['hookManager']);
259
        $container->inflector(\Robo\Contract\VerbosityThresholdInterface::class)
260
            ->invokeMethod('setOutputAdapter', ['outputAdapter']);
261
    }
262
263
    /**
264
     * Retrieves a service from the container.
265
     *
266
     * Use this method if the desired service is not one of those with a dedicated
267
     * accessor method below. If it is listed below, those methods are preferred
268
     * as they can return useful type hints.
269
     *
270
     * @param string $id
271
     *   The ID of the service to retrieve.
272
     *
273
     * @return mixed
274
     *   The specified service.
275
     */
276
    public static function service($id)
277
    {
278
        return static::getContainer()->get($id);
279
    }
280
281
    /**
282
     * Indicates if a service is defined in the container.
283
     *
284
     * @param string $id
285
     *   The ID of the service to check.
286
     *
287
     * @return bool
288
     *   TRUE if the specified service exists, FALSE otherwise.
289
     */
290
    public static function hasService($id)
291
    {
292
        // Check hasContainer() first in order to always return a Boolean.
293
        return static::hasContainer() && static::getContainer()->has($id);
294
    }
295
296
    /**
297
     * Return the result printer object.
298
     *
299
     * @return \Robo\Log\ResultPrinter
300
     */
301
    public static function resultPrinter()
302
    {
303
        return static::service('resultPrinter');
304
    }
305
306
    /**
307
     * @return \Robo\Config
308
     */
309
    public static function config()
310
    {
311
        return static::service('config');
312
    }
313
314
    /**
315
     * @return \Consolidation\Log\Logger
316
     */
317
    public static function logger()
318
    {
319
        return static::service('logger');
320
    }
321
322
    /**
323
     * @return \Robo\Application
324
     */
325
    public static function application()
326
    {
327
        return static::service('application');
328
    }
329
330
    /**
331
     * Return the output object.
332
     *
333
     * @return \Symfony\Component\Console\Output\OutputInterface
334
     */
335
    public static function output()
336
    {
337
        return static::service('output');
338
    }
339
340
    /**
341
     * Return the input object.
342
     *
343
     * @return \Symfony\Component\Console\Input\InputInterface
344
     */
345
    public static function input()
346
    {
347
        return static::service('input');
348
    }
349
350
    public static function process(Process $process)
351
    {
352
        return static::getContainer()->get('processExecutor', [$process]);
0 ignored issues
show
Unused Code introduced by
The call to ContainerInterface::get() has too many arguments starting with array($process).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
353
    }
354
}
355