Completed
Push — master ( fcb528...526e62 )
by Adam
05:41 queued 02:18
created

Bootstrap.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
4
namespace Genesis;
5
6
7
use Genesis\Config\Container;
8
use Genesis\Config\ContainerFactory;
9
10
/**
11
 * @author Adam Bisek <[email protected]>
12
 *
13
 * Bootstrap
14
 */
15
class Bootstrap
16
{
17
18
	const DEFAULT_CONFIG_FILE = 'config.neon';
19
20
21
	public function run(InputArgs $inputArgs)
22
	{
23
		$workingDir = getcwd();
24
		if ($inputArgs->getOption('colors') !== NULL && !$inputArgs->getOption('colors')) {
25
			Cli::$enableColors = FALSE;
26
		}
27
		if ($inputArgs->getOption('working-dir')) {
28
			$workingDir = realpath($inputArgs->getOption('working-dir'));
29
			if (!$workingDir) {
30
				$this->log(sprintf("Working dir '%s' does not exists.", $inputArgs->getOption('working-dir')), 'red');
31
				exit(255);
32
			}
33
		}
34
		if ($workingDir === __DIR__) {
35
			$this->log(sprintf("Working dir '%s' is directory with Genesis. You have to choose directory with build.", $workingDir), 'red');
36
			exit(255);
37
		}
38
39
		$arguments = $inputArgs->getArguments();
40
		if(isset($arguments[0]) && $arguments[0] === 'self-init'){
41
			$directoryName = isset($arguments[1]) ? $arguments[1] : 'build';
42
			$selfInit = new Commands\SelfInit();
43
			$selfInit->setDistDirectory(__DIR__ . '/build-dist');
44
			$selfInit->setWorkingDirectory($workingDir);
45
			$selfInit->setDirname($directoryName);
46
			$selfInit->execute();
47
			exit(0);
48
		}
49
50
		$bootstrapFile = $this->detectBootstrapFilename($workingDir);
51
		$container = NULL;
52
		if (is_file($bootstrapFile)) {
53
			$this->log("Info: Found bootstrap.php in working directory.", 'dark_gray');
54
			$container = require_once $bootstrapFile;
55
			if($container === 1 || $container === TRUE){ // 1 = success, TRUE = already required
56
				$container = NULL;
57
			}elseif(!($container instanceof Container)){
58
				$this->log("Returned value from bootstrap.php must be instance of 'Genesis\\Container\\Container' or nothing (NULL).", 'red');
59
				exit(255);
60
			}
61
		} else {
62
			$this->log("Info: bootstrap.php was not found in working directory.", 'dark_gray');
63
		}
64
65
		$arguments = $inputArgs->getArguments();
66
		$configFile = $inputArgs->getOption('config') ? $inputArgs->getOption('config') : self::DEFAULT_CONFIG_FILE;
67
		try {
68
			$container = $this->createContainer($workingDir, $configFile, $container);
69
			$build = $this->createBuild($container, $arguments);
70
		} catch (\Exception $e) {
71
			$this->log("Exited with ERROR:", 'red');
72
			$this->log($e->getMessage(), 'red');
73
			echo $e->getTraceAsString() . PHP_EOL;
74
			exit(255);
75
		}
76
		if (count($arguments) < 1) {
77
			$this->log("Running default", 'green');
78
			$build->runDefault();
79
			exit(0);
80
		}
81
82
		$method = 'run' . str_replace('-', '', ucfirst($arguments[0]));
83
		if (!method_exists($build, $method)) {
84
			$this->log("Task '$arguments[0]' does not exists.", 'red');
85
			exit(255);
86
		}
87
		$this->log("Running [$arguments[0]]", 'green');
88
		try {
89
			$build->$method();
90
		} catch (\Exception $e) {
91
			$this->log("Exited with ERROR:", 'red');
92
			$this->log($e->getMessage(), 'red');
93
			echo $e->getTraceAsString() . PHP_EOL;
94
			exit(255);
95
		}
96
		$this->log("Exited with SUCCESS", 'black', 'green');
97
		echo PHP_EOL;
98
		exit(0);
99
	}
100
101
102
	protected function detectBootstrapFilename($workingDir)
103
	{
104
		return $workingDir . DIRECTORY_SEPARATOR . 'bootstrap.php';
105
	}
106
107
108
	/**
109
	 * @return Container
110
	 */
111
	protected function createContainer($workingDir, $configFile, Container $bootstrapContainer = NULL)
112
	{
113
		$factory = new ContainerFactory();
114
		$factory->addConfig($workingDir . '/' . $configFile);
115
		if(is_file($workingDir . '/config.local.neon')){
116
			$factory->addConfig($workingDir . '/config.local.neon');
117
		}
118
		$factory->setWorkingDirectory($workingDir);
119
		if($bootstrapContainer !== NULL){
120
			$factory->addContainerToMerge($bootstrapContainer);
121
		}
122
		return $factory->create();
123
	}
124
125
126
	/**
127
	 * @param Container $container
128
	 * @return Build
129
	 */
130
	protected function createBuild(Container $container, array $arguments = NULL)
131
	{
132
		$class = $container->getClass();
133
		if (!class_exists($class, TRUE)) {
134
			$this->log(sprintf(
135
				"Build class '%s' was not found." . PHP_EOL .
136
				"Are you in correct working directory?" . PHP_EOL .
137
				"Did you forget add bootstrap.php with class loading into working directory?" . PHP_EOL .
138
				"Did you forget to load class %s?", $class, $class), 'red');
139
			exit(255);
1 ignored issue
show
Coding Style Compatibility introduced by
The method createBuild() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
140
		}
141
		$build = new $class($container, $arguments);
142
		if (!($build instanceof IBuild)) {
143
			throw new \RuntimeException("Instance of build does not implements interface IBuild.");
144
		}
145
		$this->autowire($build, $container);
146
		$build->setup();
147
		return $build;
148
	}
149
150
151
	protected function autowire(IBuild $build, Container $container)
152
	{
153
		foreach ($this->getAutowiredProperties($build) as $property => $service) {
154
			if(!$container->hasService($service)){
155
				throw new \RuntimeException("Cannot found service '$service' to inject into " . get_class($build) . "::$property.");
156
			}
157
			$build->$property = $container->getService($service);
158
		}
159
	}
160
161
162
	protected function getAutowiredProperties($class)
163
	{
164
		$return = [];
165
		$reflectionClass = new \ReflectionClass($class);
166
		foreach($reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $property){
167
			$reflectionProp = new \ReflectionProperty($class, $property->getName());
168
			$doc = $reflectionProp->getDocComment();
169
			if(preg_match('#@inject ?([^\s]*)\s#s', $doc, $matches)){
170
				$return[$property->getName()] = trim($matches[1]) !== '' ? $matches[1] : $property->getName();
171
			}
172
		}
173
		return $return;
174
	}
175
176
177
	protected function log($message, $color = NULL, $backgroundColor = NULL)
178
	{
179
		echo Cli::getColoredString($message . PHP_EOL, $color, $backgroundColor);
180
	}
181
182
}