Completed
Push — master ( bf56b8...8a700d )
by Joas
10:21
created

Application::loadCommandsFromInfoXml()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 13
Ratio 86.67 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 1
dl 13
loc 15
rs 9.2
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 Lukas Reschke <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin McCorkell <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 * @author Victor Dubiniuk <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
namespace OC\Console;
28
29
use OC_App;
30
use OCP\AppFramework\QueryException;
31
use OCP\Console\ConsoleEvent;
32
use OCP\IConfig;
33
use OCP\IRequest;
34
use Symfony\Component\Console\Application as SymfonyApplication;
35
use Symfony\Component\Console\Input\InputInterface;
36
use Symfony\Component\Console\Input\InputOption;
37
use Symfony\Component\Console\Output\OutputInterface;
38
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
39
40
class Application {
41
	/** @var IConfig */
42
	private $config;
43
	/** @var EventDispatcherInterface */
44
	private $dispatcher;
45
	/** @var IRequest */
46
	private $request;
47
48
	/**
49
	 * @param IConfig $config
50
	 * @param EventDispatcherInterface $dispatcher
51
	 * @param IRequest $request
52
	 */
53
	public function __construct(IConfig $config, EventDispatcherInterface $dispatcher, IRequest $request) {
54
		$defaults = \OC::$server->getThemingDefaults();
55
		$this->config = $config;
56
		$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...
57
		$this->dispatcher = $dispatcher;
58
		$this->request = $request;
59
	}
60
61
	/**
62
	 * @param InputInterface $input
63
	 * @param OutputInterface $output
64
	 * @throws \Exception
65
	 */
66
	public function loadCommands(InputInterface $input, OutputInterface $output) {
67
		// $application is required to be defined in the register_command scripts
68
		$application = $this->application;
69
		$inputDefinition = $application->getDefinition();
70
		$inputDefinition->addOption(
71
			new InputOption(
72
				'no-warnings', 
73
				null, 
74
				InputOption::VALUE_NONE, 
75
				'Skip global warnings, show command output only', 
76
				null
77
			)
78
		);
79
		try {
80
			$input->bind($inputDefinition);
81
		} catch (\RuntimeException $e) {
82
			//expected if there are extra options
83
		}
84
		if ($input->getOption('no-warnings')) {
85
			$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
86
		}
87
		require_once __DIR__ . '/../../../core/register_command.php';
88
		if ($this->config->getSystemValue('installed', false)) {
89
			if (\OCP\Util::needUpgrade()) {
90
				if ($input->getArgument('command') !== '_completion') {
91
					$output->writeln("Nextcloud or one of the apps require upgrade - only a limited number of commands are available");
92
					$output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
93
				}
94
			} elseif ($this->config->getSystemValue('maintenance', false)) {
95
				if ($input->getArgument('command') !== '_completion') {
96
					$output->writeln("Nextcloud is in maintenance mode - no apps have been loaded");
97
				}
98
			} else {
99
				OC_App::loadApps();
100
				foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
101
					$appPath = \OC_App::getAppPath($app);
102
					if($appPath === false) {
103
						continue;
104
					}
105
					// load commands using info.xml
106
					$info = \OC_App::getAppInfo($app);
107
					if (isset($info['commands'])) {
108
						$this->loadCommandsFromInfoXml($info['commands']);
109
					}
110
					// load from register_command.php
111
					\OC_App::registerAutoloading($app, $appPath);
112
					$file = $appPath . '/appinfo/register_command.php';
113
					if (file_exists($file)) {
114
						require $file;
115
					}
116
				}
117
			}
118
		} else if ($input->getArgument('command') !== '_completion') {
119
			$output->writeln("Nextcloud is not installed - only a limited number of commands are available");
120
		}
121
122
		if ($input->getFirstArgument() !== 'check') {
123
			$errors = \OC_Util::checkServer(\OC::$server->getConfig());
124
			if (!empty($errors)) {
125
				foreach ($errors as $error) {
126
					$output->writeln((string)$error['error']);
127
					$output->writeln((string)$error['hint']);
128
					$output->writeln('');
129
				}
130
				throw new \Exception("Environment not properly prepared.");
131
			}
132
		}
133
	}
134
135
	/**
136
	 * Sets whether to automatically exit after a command execution or not.
137
	 *
138
	 * @param bool $boolean Whether to automatically exit after a command execution or not
139
	 */
140
	public function setAutoExit($boolean) {
141
		$this->application->setAutoExit($boolean);
142
	}
143
144
	/**
145
	 * @param InputInterface $input
146
	 * @param OutputInterface $output
147
	 * @return int
148
	 * @throws \Exception
149
	 */
150
	public function run(InputInterface $input = null, OutputInterface $output = null) {
151
		$this->dispatcher->dispatch(ConsoleEvent::EVENT_RUN, new ConsoleEvent(
152
			ConsoleEvent::EVENT_RUN,
153
			$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...
154
		));
155
		return $this->application->run($input, $output);
156
	}
157
158
	private function loadCommandsFromInfoXml($commands) {
159 View Code Duplication
		foreach ($commands as $command) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
160
			try {
161
				$c = \OC::$server->query($command);
162
			} catch (QueryException $e) {
163
				if (class_exists($command)) {
164
					$c = new $command();
165
				} else {
166
					throw new \Exception("Console command '$command' is unknown and could not be loaded");
167
				}
168
			}
169
170
			$this->application->add($c);
171
		}
172
	}
173
}
174