Application   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Coupling/Cohesion

Dependencies 14

Importance

Changes 0
Metric Value
wmc 21
cbo 14
dl 0
loc 246
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 4 1
A __construct() 0 9 1
A setEnvironmentVariables() 0 4 1
A getBldrVersion() 0 10 2
A getCommands() 0 8 1
A setBuildName() 0 20 2
A getHelp() 0 4 1
A doRun() 0 21 2
A buildContainer() 0 11 2
A find() 0 10 2
A getDefinition() 0 9 2
A getEmbeddedComposer() 0 4 1
A getDefaultInputDefinition() 0 18 1
A doRunCommand() 0 8 2
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;
13
14
use Bldr\DependencyInjection\ContainerBuilder;
15
use Dflydev\EmbeddedComposer\Console\Command as ComposerCmd;
16
use Dflydev\EmbeddedComposer\Core\EmbeddedComposerAwareInterface;
17
use Dflydev\EmbeddedComposer\Core\EmbeddedComposerInterface;
18
use Symfony\Component\Console\Application as BaseApplication;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
24
use Symfony\Component\DependencyInjection\ContainerInterface;
25
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
26
27
/**
28
 * @author Aaron Scherer <[email protected]>
29
 */
30
class Application extends BaseApplication implements EmbeddedComposerAwareInterface
31
{
32
    /**
33
     * @var string $BUILD_NAME
34
     */
35
    public static $BUILD_NAME;
36
37
    /**
38
     * @var string $logo
39
     */
40
    public static $logo = <<<EOF
41
  ______    __       _______   ______
42
 |   _  \  |  |     |       \ |   _  \
43
 |  |_)  | |  |     |  .--.  ||  |_)  |
44
 |   _  <  |  |     |  |  |  ||      /
45
 |  |_)  | |  `----.|  `--`  ||  |\  \
46
 |______/  |_______||_______/ | _| `._|
47
EOF;
48
49
    /**
50
     * @var ContainerInterface $container
51
     */
52
    private $container;
53
54
    /**
55
     * @var EmbeddedComposerInterface $embeddedComposer
56
     */
57
    private $embeddedComposer;
58
59
    /**
60
     * Are we building via shortcut
61
     *
62
     * @var bool $shortcut
63
     */
64
    private $shortcut = false;
65
66
    /**
67
     * @param EmbeddedComposerInterface $embeddedComposer
68
     *
69
     * @return Application
70
     */
71
    public static function create(EmbeddedComposerInterface $embeddedComposer)
72
    {
73
        return new Application($embeddedComposer);
74
    }
75
76
    /**
77
     * @param EmbeddedComposerInterface $embeddedComposer
78
     */
79
    public function __construct(EmbeddedComposerInterface $embeddedComposer)
80
    {
81
        $this->embeddedComposer = $embeddedComposer;
82
83
        parent::__construct('Bldr', $this->getBldrVersion());
84
85
        $this->addCommands($this->getCommands());
86
        $this->setEnvironmentVariables();
87
    }
88
89
    /**
90
     * Sets Environment Variables
91
     */
92
    private function setEnvironmentVariables()
93
    {
94
        putenv('WORK_DIR='.__DIR__);
95
    }
96
97
    /**
98
     * @return string
99
     */
100
    private function getBldrVersion()
101
    {
102
        $version = '@package_version@';
103
        if ($version === '@'.'package_version@') {
104
            $package = $this->embeddedComposer->findPackage('bldr-io/bldr');
105
            $version = $package->getPrettyVersion();
106
        }
107
108
        return $version;
109
    }
110
111
    /**
112
     * @return Command[]
113
     */
114
    public function getCommands()
115
    {
116
        return [
117
            new ComposerCmd\DumpAutoloadCommand('blocks-'),
118
            new ComposerCmd\InstallCommand('blocks-'),
119
            new ComposerCmd\UpdateCommand('blocks-')
120
        ];
121
    }
122
123
    public function setBuildName()
124
    {
125
        $date = new \DateTime('now');
126
127
        if (getenv('TRAVIS') === 'true') {
128
            $name = sprintf(
129
                "travis_%s",
130
                getenv('TRAVIS_JOB_NUMBER')
131
            );
132
        } else {
133
            $name = sprintf(
134
                'local_%s_%s',
135
                str_replace('/', '_', $this->container->getParameter('name')),
136
                $date->format("Y-m-d_H-i-s")
137
            );
138
        }
139
140
        putenv('BUILD_NAME='.$name);
141
        static::$BUILD_NAME = $name;
142
    }
143
144
    /**
145
     * {@inheritDoc}
146
     *
147
     * @codeCoverageIgnore
148
     */
149
    public function getHelp()
150
    {
151
        return "\n".self::$logo."\n\n".parent::getHelp();
152
    }
153
154
    /**
155
     * {@inheritDoc}
156
     */
157
    public function doRun(InputInterface $input, OutputInterface $output)
158
    {
159
        try {
160
            $this->buildContainer($input, $output);
161
        } catch (\Exception $e) {
162
            $output->write(
163
                [
164
                    "\n\n",
165
                    $this->getHelperSet()->get('formatter')->formatBlock(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method formatBlock() does only exist in the following implementations of said interface: Symfony\Component\Console\Helper\FormatterHelper.

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...
166
                        " [Error] Either you have no config file, or the config file is invalid.",
167
                        "bg=red;fg=white",
168
                        true
169
                    )
170
                ]
171
            );
172
173
            throw $e;
174
        }
175
176
        return parent::doRun($input, $output);
177
    }
178
179
    /**
180
     * Builds the container with extensions
181
     *
182
     * @param InputInterface  $input
183
     * @param OutputInterface $output
184
     *
185
     * @throws InvalidArgumentException
186
     */
187
    private function buildContainer(InputInterface $input, OutputInterface $output)
188
    {
189
        $nonContainerCommands = ['blocks-install', 'blocks-update', 'blocks-dumpautoload', 'help'];
190
191
        if (in_array($input->getFirstArgument(), $nonContainerCommands)) {
192
            return;
193
        }
194
195
        $this->container = new ContainerBuilder($this, $input, $output);
196
        $this->container->compile();
197
    }
198
199
    /**
200
     * Falls back to "run" for a shortcut
201
     *
202
     * @param string $name
203
     *
204
     * @return Command
205
     */
206
    public function find($name)
207
    {
208
        try {
209
            return parent::find($name);
210
        } catch (\InvalidArgumentException $e) {
211
            $this->shortcut = true;
212
213
            return parent::find('run');
214
        }
215
    }
216
217
    /**
218
     * Resets arguments if shortcutting
219
     *
220
     * @return \Symfony\Component\Console\Input\InputDefinition
221
     */
222
    public function getDefinition()
223
    {
224
        $definition = parent::getDefinition();
225
        if ($this->shortcut) {
226
            $definition->setArguments();
227
        }
228
229
        return $definition;
230
    }
231
232
    /**
233
     * @return EmbeddedComposerInterface
234
     */
235
    public function getEmbeddedComposer()
236
    {
237
        return $this->embeddedComposer;
238
    }
239
240
    /**
241
     * @return \Symfony\Component\Console\Input\InputDefinition
242
     */
243
    protected function getDefaultInputDefinition()
244
    {
245
        $definition = parent::getDefaultInputDefinition();
246
        $definition->addOptions(
247
            [
248
                new InputOption('config-file', null, InputOption::VALUE_REQUIRED, 'Config File to use'),
249
                new InputOption(
250
                    'config-format',
251
                    null,
252
                    InputOption::VALUE_REQUIRED,
253
                    'Config Format to use: '.implode(', ', Config::$TYPES)
254
                ),
255
                new InputOption('global', null, InputOption::VALUE_NONE, 'Read the global config')
256
            ]
257
        );
258
259
        return $definition;
260
    }
261
262
    /**
263
     * Adds a container to Container Aware Commands
264
     *
265
     * {@inheritDoc}
266
     */
267
    protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
268
    {
269
        if ($command instanceof ContainerAwareInterface) {
270
            $command->setContainer($this->container);
271
        }
272
273
        return parent::doRunCommand($command, $input, $output);
274
    }
275
}
276