Completed
Push — master ( 31e3fa...9e9db7 )
by Martijn van
02:34
created

SilverstripeApplication::add()   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
3
use Symfony\Component\Console\Application as SymfonyApplication;
4
use Symfony\Component\Console\Command\Command as SymfonyCommand;
5
use Symfony\Component\Console\Input\ArrayInput;
6
use Symfony\Component\Console\Input\InputInterface;
7
use Symfony\Component\Console\Input\InputOption;
8
use Symfony\Component\Console\Output\BufferedOutput;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
/**
12
 * Class Application.
13
 *
14
 * Shameless copy/paste from Taylor Otwell's Laravel
15
 */
16
class SilverstripeApplication extends SymfonyApplication
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /**
19
     * The output from the previous command.
20
     *
21
     * @var \Symfony\Component\Console\Output\BufferedOutput
22
     */
23
    protected $lastOutput;
24
25
    public function __construct()
26
    {
27
        parent::__construct();
28
29
        $this->loadCommands();
30
31
        $this->add($default = new DefaultCommand());
32
        $this->setDefaultCommand($default->getName());
33
34
        $this->setAutoExit(false);
35
        $this->setCatchExceptions(false);
36
    }
37
38
    public function run(InputInterface $input = null, OutputInterface $output = null)
39
    {
40
        return parent::run($input, $output);
41
    }
42
43
    /**
44
     * Run an Silverstripe console command by name.
45
     *
46
     * @param string $command
47
     * @param array  $parameters
48
     *
49
     * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be null|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
50
     */
51
    public function call($command, array $parameters = [])
52
    {
53
        $parameters = array_merge((array) $command, $parameters);
54
55
        $this->lastOutput = new BufferedOutput();
56
57
        $this->setCatchExceptions(false);
58
59
        $result = $this->run(new ArrayInput($parameters), $this->lastOutput);
60
61
        $this->setCatchExceptions(true);
62
63
        return $result;
64
    }
65
66
    /**
67
     * Get the output for the last run command.
68
     *
69
     * @return string
70
     */
71
    public function output()
72
    {
73
        return $this->lastOutput ? $this->lastOutput->fetch() : '';
74
    }
75
76
    /**
77
     * Get the default input definitions for the applications.
78
     *
79
     * This is used to add the --env option to every available command.
80
     *
81
     * @return \Symfony\Component\Console\Input\InputDefinition
82
     */
83
    protected function getDefaultInputDefinition()
84
    {
85
        $definition = parent::getDefaultInputDefinition();
86
87
        $definition->addOption($this->getEnvironmentOption());
88
89
        return $definition;
90
    }
91
92
    /**
93
     * Get the global environment option for the definition.
94
     *
95
     * @return \Symfony\Component\Console\Input\InputOption
96
     */
97
    protected function getEnvironmentOption()
98
    {
99
        $message = 'The environment the command should run under.';
100
101
        return new InputOption('--env', null, InputOption::VALUE_OPTIONAL, $message);
102
    }
103
104
    /**
105
     * Load all available commands into the console application.
106
     */
107
    protected function loadCommands()
108
    {
109
       // somehow ClassInfo::subclassesFor('SilverstripeCommand'); does not work
110
        $classes = SS_ClassLoader::instance()->getManifest()->getClasses();
111
112
        /* @var SilverstripeCommand $command */
113
        foreach ($classes as $class => $path) {
114
            $this->addCommandOrSilentlyFail($class, $path);
115
        }
116
    }
117
118
    /**
119
     * When developing and renaming or removing a Command, the manifest is not always updated.
120
     *
121
     * We don't want file_not_found or class_does_not_exists error for commands,
122
     * because that prevente running commands like cache:clear etc.
123
     *
124
     * @param string $class
125
     * @param string $path
126
     */
127
    protected function addCommandOrSilentlyFail($class, $path)
128
    {
129
        if (is_file($path) && class_exists($class)) {
130
            $reflection = new ReflectionClass($class);
131
            if (!$reflection->isAbstract() && $reflection->isSubclassOf('SilverstripeCommand')) {
132
                $this->add(new $class());
133
            }
134
        }
135
    }
136
}
137