Completed
Push — master ( 22bb83...6142cd )
by Morris
56:36 queued 24:40
created

Application::writeMaintenanceModeInfo()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 2
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Joas Schilling <[email protected]>
6
 * @author Jörn Friedrich Dreyer <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Miha Frangez <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author noveens <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Victor Dubiniuk <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
namespace OC\Console;
31
32
use OC\NeedsUpdateException;
33
use OC_App;
34
use OCP\AppFramework\QueryException;
35
use OCP\Console\ConsoleEvent;
36
use OCP\IConfig;
37
use OCP\ILogger;
38
use OCP\IRequest;
39
use Symfony\Component\Console\Application as SymfonyApplication;
40
use Symfony\Component\Console\Input\InputInterface;
41
use Symfony\Component\Console\Input\InputOption;
42
use Symfony\Component\Console\Output\ConsoleOutputInterface;
43
use Symfony\Component\Console\Output\OutputInterface;
44
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
45
46
class Application {
47
	/** @var IConfig */
48
	private $config;
49
	/** @var EventDispatcherInterface */
50
	private $dispatcher;
51
	/** @var IRequest */
52
	private $request;
53
	/** @var ILogger  */
54
	private $logger;
55
56
	/**
57
	 * @param IConfig $config
58
	 * @param EventDispatcherInterface $dispatcher
59
	 * @param IRequest $request
60
	 * @param ILogger $logger
61
	 */
62
	public function __construct(IConfig $config, EventDispatcherInterface $dispatcher, IRequest $request, ILogger $logger) {
63
		$defaults = \OC::$server->getThemingDefaults();
64
		$this->config = $config;
65
		$this->application = new SymfonyApplication($defaults->getName(), \OC_Util::getVersionString());
0 ignored issues
show
Bug introduced by
The property application does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
66
		$this->dispatcher = $dispatcher;
67
		$this->request = $request;
68
		$this->logger = $logger;
69
	}
70
71
	/**
72
	 * @param InputInterface $input
73
	 * @param ConsoleOutputInterface $output
74
	 * @throws \Exception
75
	 */
76
	public function loadCommands(
77
		InputInterface $input,
78
		ConsoleOutputInterface $output
79
	) {
80
		// $application is required to be defined in the register_command scripts
81
		$application = $this->application;
82
		$inputDefinition = $application->getDefinition();
83
		$inputDefinition->addOption(
84
			new InputOption(
85
				'no-warnings', 
86
				null, 
87
				InputOption::VALUE_NONE, 
88
				'Skip global warnings, show command output only', 
89
				null
90
			)
91
		);
92
		try {
93
			$input->bind($inputDefinition);
94
		} catch (\RuntimeException $e) {
95
			//expected if there are extra options
96
		}
97
		if ($input->getOption('no-warnings')) {
98
			$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
99
		}
100
		try {
101
			require_once __DIR__ . '/../../../core/register_command.php';
102
			if ($this->config->getSystemValue('installed', false)) {
103
				if (\OCP\Util::needUpgrade()) {
104
					throw new NeedsUpdateException();
105
				} elseif ($this->config->getSystemValue('maintenance', false)) {
106
					$this->writeMaintenanceModeInfo($input, $output);
107
				} else {
108
					OC_App::loadApps();
109
					foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
110
						$appPath = \OC_App::getAppPath($app);
111
						if ($appPath === false) {
112
							continue;
113
						}
114
						// load commands using info.xml
115
						$info = \OC_App::getAppInfo($app);
116
						if (isset($info['commands'])) {
117
							$this->loadCommandsFromInfoXml($info['commands']);
118
						}
119
						// load from register_command.php
120
						\OC_App::registerAutoloading($app, $appPath);
121
						$file = $appPath . '/appinfo/register_command.php';
122
						if (file_exists($file)) {
123
							try {
124
								require $file;
125
							} catch (\Exception $e) {
126
								$this->logger->logException($e);
0 ignored issues
show
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127
							}
128
						}
129
					}
130
				}
131
			} else if ($input->getArgument('command') !== '_completion' && $input->getArgument('command') !== 'maintenance:install') {
132
				$output->writeln("Nextcloud is not installed - only a limited number of commands are available");
133
			}
134
		} catch(NeedsUpdateException $e) {
135
			if ($input->getArgument('command') !== '_completion') {
136
				$output->writeln("Nextcloud or one of the apps require upgrade - only a limited number of commands are available");
137
				$output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
138
			}
139
		}
140
141
		if ($input->getFirstArgument() !== 'check') {
142
			$errors = \OC_Util::checkServer(\OC::$server->getSystemConfig());
143
			if (!empty($errors)) {
144
				foreach ($errors as $error) {
145
					$output->writeln((string)$error['error']);
146
					$output->writeln((string)$error['hint']);
147
					$output->writeln('');
148
				}
149
				throw new \Exception("Environment not properly prepared.");
150
			}
151
		}
152
	}
153
154
	/**
155
	 * Write a maintenance mode info.
156
	 * The commands "_completion" and "maintenance:mode" are excluded.
157
	 *
158
	 * @param InputInterface $input The input implementation for reading inputs.
159
	 * @param ConsoleOutputInterface $output The output implementation
160
	 * for writing outputs.
161
	 * @return void
162
	 */
163
	private function writeMaintenanceModeInfo(
164
		InputInterface $input, ConsoleOutputInterface $output
165
	) {
166
		if ($input->getArgument('command') !== '_completion'
167
			&& $input->getArgument('command') !== 'maintenance:mode') {
168
			$errOutput = $output->getErrorOutput();
169
			$errOutput->writeln(
170
				'<comment>Nextcloud is in maintenance mode - ' .
171
				'no apps have been loaded</comment>' . PHP_EOL
172
			);
173
		}
174
	}
175
176
	/**
177
	 * Sets whether to automatically exit after a command execution or not.
178
	 *
179
	 * @param bool $boolean Whether to automatically exit after a command execution or not
180
	 */
181
	public function setAutoExit($boolean) {
182
		$this->application->setAutoExit($boolean);
183
	}
184
185
	/**
186
	 * @param InputInterface $input
187
	 * @param OutputInterface $output
188
	 * @return int
189
	 * @throws \Exception
190
	 */
191
	public function run(InputInterface $input = null, OutputInterface $output = null) {
192
		$this->dispatcher->dispatch(ConsoleEvent::EVENT_RUN, new ConsoleEvent(
193
			ConsoleEvent::EVENT_RUN,
194
			$this->request->server['argv']
0 ignored issues
show
Bug introduced by
Accessing server on the interface OCP\IRequest suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
195
		));
196
		return $this->application->run($input, $output);
197
	}
198
199
	private function loadCommandsFromInfoXml($commands) {
200
		foreach ($commands as $command) {
201
			try {
202
				$c = \OC::$server->query($command);
203
			} catch (QueryException $e) {
204
				if (class_exists($command)) {
205
					$c = new $command();
206
				} else {
207
					throw new \Exception("Console command '$command' is unknown and could not be loaded");
208
				}
209
			}
210
211
			$this->application->add($c);
212
		}
213
	}
214
}
215