Completed
Pull Request — master (#552)
by Greg
03:15
created

Robo::createConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 4
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 Robo\Config\Config;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Robo\Config.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use Robo\Config\ConfigProcessor;
9
use Robo\Config\YamlConfigLoader;
10
use Symfony\Component\Console\Input\StringInput;
11
use Symfony\Component\Console\Application as SymfonyApplication;
12
use Symfony\Component\Process\Process;
13
14
/**
15
 * Manages the container reference and other static data.  Favor
16
 * using dependency injection wherever possible.  Avoid using
17
 * this class directly, unless setting up a custom DI container.
18
 */
19
class Robo
20
{
21
    const APPLICATION_NAME = 'Robo';
22
    const VERSION = '1.0.6-dev';
23
24
    /**
25
     * The currently active container object, or NULL if not initialized yet.
26
     *
27
     * @var ContainerInterface|null
28
     */
29
    protected static $container;
30
31
    /**
32
     * Entrypoint for standalone Robo-based tools.  See docs/framework.md.
33
     *
34
     * @param string[] $argv
35
     * @param string $commandClasses
36
     * @param null|string $appName
37
     * @param null|string $appVersion
38
     * @param null|\Symfony\Component\Console\Output\OutputInterface $output
39
     *
40
     * @return int
41
     */
42
    public static function run($argv, $commandClasses, $appName = null, $appVersion = null, $output = null)
43
    {
44
        $runner = new \Robo\Runner($commandClasses);
45
        $statusCode = $runner->execute($argv, $appName, $appVersion, $output);
46
        return $statusCode;
47
    }
48
49
    /**
50
     * Sets a new global container.
51
     *
52
     * @param ContainerInterface $container
53
     *   A new container instance to replace the current.
54
     */
55
    public static function setContainer(ContainerInterface $container)
56
    {
57
        static::$container = $container;
58
    }
59
60
    /**
61
     * Unsets the global container.
62
     */
63
    public static function unsetContainer()
64
    {
65
        static::$container = null;
66
    }
67
68
    /**
69
     * Returns the currently active global container.
70
     *
71
     * @return \League\Container\ContainerInterface
72
     *
73
     * @throws \RuntimeException
74
     */
75
    public static function getContainer()
76
    {
77
        if (static::$container === null) {
78
            throw new \RuntimeException('container is not initialized yet. \Robo\Robo::setContainer() must be called with a real container.');
79
        }
80
        return static::$container;
81
    }
82
83
    /**
84
     * Returns TRUE if the container has been initialized, FALSE otherwise.
85
     *
86
     * @return bool
87
     */
88
    public static function hasContainer()
89
    {
90
        return static::$container !== null;
91
    }
92
93
    /**
94
     * Create a config object and load it from the provided paths.
95
     */
96
    public static function createConfiguration($paths)
97
    {
98
        $config = new Config();
99
        static::loadConfiguration($config, $paths);
100
        return $config;
101
    }
102
103
    /**
104
     * Use a simple config loader to load configuration values from specified paths
105
     */
106
    public static function loadConfiguration($config, $paths)
107
    {
108
        $loader = new YamlConfigLoader();
109
        $processor = new ConfigProcessor();
110
        foreach ($paths as $path) {
111
            $processor->extend($loader->load($path));
112
        }
113
        $config->import($loader->export());
114
    }
115
116
    /**
117
     * Create a container and initiailze it.  If you wish to *change*
118
     * anything defined in the container, then you should call
119
     * \Robo::configureContainer() instead of this function.
120
     *
121
     * @param null|\Symfony\Component\Console\Input\InputInterface $input
122
     * @param null|\Symfony\Component\Console\Output\OutputInterface $output
123
     * @param null|\Robo\Application $app
124
     * @param null|\Robo\Config\Config $config
125
     *
126
     * @return \League\Container\Container|\League\Container\ContainerInterface
127
     */
128
    public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null)
129
    {
130
        // Do not allow this function to be called more than once.
131
        if (static::hasContainer()) {
132
            return static::getContainer();
133
        }
134
135
        if (!$app) {
136
            $app = static::createDefaultApplication();
137
        }
138
139
        if (!$config) {
140
            $config = new Config();
141
        }
142
143
        // Set up our dependency injection container.
144
        $container = new Container();
145
        static::configureContainer($container, $app, $config, $input, $output);
146
147
        // Set the application dispatcher
148
        $app->setDispatcher($container->get('eventDispatcher'));
149
150
        return $container;
151
    }
152
153
    /**
154
     * Initialize a container with all of the default Robo services.
155
     * IMPORTANT:  after calling this method, clients MUST call:
156
     *
157
     * $dispatcher = $container->get('eventDispatcher');
158
     * $app->setDispatcher($dispatcher);
159
     *
160
     * Any modification to the container should be done prior to fetching
161
     * objects from it.
162
     *
163
     * It is recommended to use \Robo::createDefaultContainer()
164
     * instead, which does all required setup for the caller, but has
165
     * the limitation that the container it creates can only be
166
     * extended, not modified.
167
     *
168
     * @param \League\Container\ContainerInterface $container
169
     * @param \Symfony\Component\Console\Application $app
170
     * @param \Robo\Config\Config $config
171
     * @param null|\Symfony\Component\Console\Input\InputInterface $input
172
     * @param null|\Symfony\Component\Console\Output\OutputInterface $output
173
     */
174
    public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, Config $config, $input = null, $output = null)
175
    {
176
        // Self-referential container refernce for the inflector
177
        $container->add('container', $container);
178
        static::setContainer($container);
179
180
        // Create default input and output objects if they were not provided
181
        if (!$input) {
182
            $input = new StringInput('');
183
        }
184
        if (!$output) {
185
            $output = new \Symfony\Component\Console\Output\ConsoleOutput();
186
        }
187
        $config->setDecorated($output->isDecorated());
188
189
        $container->share('application', $app);
190
        $container->share('config', $config);
191
        $container->share('input', $input);
192
        $container->share('output', $output);
193
        $container->share('outputAdapter', \Robo\Common\OutputAdapter::class);
194
195
        // Register logging and related services.
196
        $container->share('logStyler', \Robo\Log\RoboLogStyle::class);
197
        $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...
198
            ->withArgument('output')
199
            ->withMethodCall('setLogOutputStyler', ['logStyler']);
200
        $container->add('progressBar', \Symfony\Component\Console\Helper\ProgressBar::class)
201
            ->withArgument('output');
202
        $container->share('progressIndicator', \Robo\Common\ProgressIndicator::class)
203
            ->withArgument('progressBar')
204
            ->withArgument('output');
205
        $container->share('resultPrinter', \Robo\Log\ResultPrinter::class);
206
        $container->add('simulator', \Robo\Task\Simulator::class);
207
        $container->share('globalOptionsEventListener', \Robo\GlobalOptionsEventListener::class);
208
        $container->share('injectConfigEventListener', \Robo\InjectConfigEventListener::class);
209
        $container->share('collectionProcessHook', \Robo\Collection\CollectionProcessHook::class);
210
        $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...
211
            ->withMethodCall('addResultProcessor', ['collectionProcessHook', '*']);
212
        $container->share('alterOptionsCommandEvent', \Consolidation\AnnotatedCommand\Options\AlterOptionsCommandEvent::class)
213
            ->withArgument('application');
214
        $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...
215
            ->withMethodCall('addSubscriber', ['injectConfigEventListener'])
216
            ->withMethodCall('addSubscriber', ['globalOptionsEventListener'])
217
            ->withMethodCall('addSubscriber', ['alterOptionsCommandEvent'])
218
            ->withMethodCall('addSubscriber', ['hookManager']);
219
        $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...
220
            ->withMethodCall('addDefaultFormatters', [])
221
            ->withMethodCall('addDefaultSimplifiers', []);
222
        $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...
223
            ->withMethodCall('setApplication', ['application']);
224
        $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...
225
            ->withArgument('hookManager')
226
            ->withMethodCall('setFormatterManager', ['formatterManager'])
227
            ->withMethodCall('addPrepareFormatter', ['prepareTerminalWidthOption'])
228
            ->withMethodCall(
229
                'setDisplayErrorFunction',
230
                [
231
                    function ($output, $message) use ($container) {
232
                        $logger = $container->get('logger');
233
                        $logger->error($message);
234
                    }
235
                ]
236
            );
237
        $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...
238
            ->withMethodCall('setCommandProcessor', ['commandProcessor']);
239
240
        // Deprecated: favor using collection builders to direct use of collections.
241
        $container->add('collection', \Robo\Collection\Collection::class);
242
        // Deprecated: use CollectionBuilder::create() instead -- or, better
243
        // yet, BuilderAwareInterface::collectionBuilder() if available.
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
244
        $container->add('collectionBuilder', \Robo\Collection\CollectionBuilder::class);
245
246
        static::addInflectors($container);
247
248
        // Make sure the application is appropriately initialized.
249
        $app->setAutoExit(false);
250
    }
251
252
    /**
253
     * @param null|string $appName
254
     * @param null|string $appVersion
255
     *
256
     * @return \Robo\Application
257
     */
258
    public static function createDefaultApplication($appName = null, $appVersion = null)
259
    {
260
        $appName = $appName ?: self::APPLICATION_NAME;
261
        $appVersion = $appVersion ?: self::VERSION;
262
263
        $app = new \Robo\Application($appName, $appVersion);
264
        $app->setAutoExit(false);
265
        return $app;
266
    }
267
268
    /**
269
     * Add the Robo League\Container inflectors to the container
270
     *
271
     * @param \League\Container\ContainerInterface $container
272
     */
273
    public static function addInflectors($container)
274
    {
275
        // Register our various inflectors.
276
        $container->inflector(\Robo\Contract\ConfigAwareInterface::class)
277
            ->invokeMethod('setConfig', ['config']);
278
        $container->inflector(\Psr\Log\LoggerAwareInterface::class)
279
            ->invokeMethod('setLogger', ['logger']);
280
        $container->inflector(\League\Container\ContainerAwareInterface::class)
281
            ->invokeMethod('setContainer', ['container']);
282
        $container->inflector(\Symfony\Component\Console\Input\InputAwareInterface::class)
283
            ->invokeMethod('setInput', ['input']);
284
        $container->inflector(\Robo\Contract\OutputAwareInterface::class)
285
            ->invokeMethod('setOutput', ['output']);
286
        $container->inflector(\Robo\Contract\ProgressIndicatorAwareInterface::class)
287
            ->invokeMethod('setProgressIndicator', ['progressIndicator']);
288
        $container->inflector(\Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface::class)
289
            ->invokeMethod('setHookManager', ['hookManager']);
290
        $container->inflector(\Robo\Contract\VerbosityThresholdInterface::class)
291
            ->invokeMethod('setOutputAdapter', ['outputAdapter']);
292
    }
293
294
    /**
295
     * Retrieves a service from the container.
296
     *
297
     * Use this method if the desired service is not one of those with a dedicated
298
     * accessor method below. If it is listed below, those methods are preferred
299
     * as they can return useful type hints.
300
     *
301
     * @param string $id
302
     *   The ID of the service to retrieve.
303
     *
304
     * @return mixed
305
     *   The specified service.
306
     */
307
    public static function service($id)
308
    {
309
        return static::getContainer()->get($id);
310
    }
311
312
    /**
313
     * Indicates if a service is defined in the container.
314
     *
315
     * @param string $id
316
     *   The ID of the service to check.
317
     *
318
     * @return bool
319
     *   TRUE if the specified service exists, FALSE otherwise.
320
     */
321
    public static function hasService($id)
322
    {
323
        // Check hasContainer() first in order to always return a Boolean.
324
        return static::hasContainer() && static::getContainer()->has($id);
325
    }
326
327
    /**
328
     * Return the result printer object.
329
     *
330
     * @return \Robo\Log\ResultPrinter
331
     */
332
    public static function resultPrinter()
333
    {
334
        return static::service('resultPrinter');
335
    }
336
337
    /**
338
     * @return \Robo\Config\Config
339
     */
340
    public static function config()
341
    {
342
        return static::service('config');
343
    }
344
345
    /**
346
     * @return \Consolidation\Log\Logger
347
     */
348
    public static function logger()
349
    {
350
        return static::service('logger');
351
    }
352
353
    /**
354
     * @return \Robo\Application
355
     */
356
    public static function application()
357
    {
358
        return static::service('application');
359
    }
360
361
    /**
362
     * Return the output object.
363
     *
364
     * @return \Symfony\Component\Console\Output\OutputInterface
365
     */
366
    public static function output()
367
    {
368
        return static::service('output');
369
    }
370
371
    /**
372
     * Return the input object.
373
     *
374
     * @return \Symfony\Component\Console\Input\InputInterface
375
     */
376
    public static function input()
377
    {
378
        return static::service('input');
379
    }
380
381
    public static function process(Process $process)
382
    {
383
        return ProcessExecutor::create(static::getContainer(), $process);
384
    }
385
}
386