Completed
Push — master ( 7f33bf...9b09f6 )
by Adam
04:00
created

Bootstrap::terminate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
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 14
	public function run(InputArgs $inputArgs)
22
	{
23 14
		$workingDir = getcwd();
24 14
		if ($inputArgs->getOption('colors') !== NULL && !$inputArgs->getOption('colors')) {
25 14
			Cli::$enableColors = FALSE;
26 14
		}
27 14
		if ($inputArgs->getOption('working-dir')) {
28 14
			$workingDir = realpath($inputArgs->getOption('working-dir'));
29 14
			if (!$workingDir) {
30 1
				$this->log(sprintf("Working dir '%s' does not exists.", $inputArgs->getOption('working-dir')), 'red');
31 1
				$this->terminate(255);
32
			}
33 14
		}
34 14
		if ($workingDir === __DIR__) {
35 3
			$this->log(sprintf("Working dir '%s' is directory with Genesis. You have to choose directory with build.", $workingDir), 'red');
36 1
			$this->terminate(255);
37
		}
38
39 13
		$arguments = $inputArgs->getArguments();
40 13
		if (isset($arguments[0]) && $arguments[0] === 'self-init') {
41 1
			$directoryName = isset($arguments[1]) ? $arguments[1] : 'build';
42 1
			$selfInit = new Commands\SelfInit();
43 1
			$selfInit->setDistDirectory(__DIR__ . '/build-dist');
44 1
			$selfInit->setWorkingDirectory($workingDir);
45 1
			$selfInit->setDirname($directoryName);
46 1
			$selfInit->execute();
47 1
			$this->terminate(0);
48
		}
49
50 12
		$bootstrapFile = $this->detectBootstrapFilename($workingDir);
51 12
		$container = NULL;
52 12
		if (is_file($bootstrapFile)) {
53 11
			$this->log("Info: Found bootstrap.php in working directory.", 'dark_gray');
54 11
			$container = require_once $bootstrapFile;
55 11
			if ($container === 1 || $container === TRUE) { // 1 = success, TRUE = already required
56 2
				$container = NULL;
57 11
			}elseif (!($container instanceof Container)) {
58 1
				$this->log("Returned value from bootstrap.php must be instance of 'Genesis\\Container\\Container' or nothing (NULL).", 'red');
59 1
				$this->terminate(255);
60
			}
61 10
		} else {
62 1
			$this->log("Info: bootstrap.php was not found in working directory.", 'dark_gray');
63
		}
64
65 11
		$arguments = $inputArgs->getArguments();
66 11
		$configFile = $inputArgs->getOption('config') ? $inputArgs->getOption('config') : self::DEFAULT_CONFIG_FILE;
67
		try {
68 11
			$container = $this->createContainer($workingDir, $configFile, $container);
69 11
			$build = $this->createBuild($container, $arguments);
70 11
		} catch (Exception $e) {
71 2
			$this->log("Exited with ERROR:", 'red');
72 2
			$this->log($e->getMessage(), 'red');
73 2
			echo $e->getTraceAsString() . PHP_EOL;
74 2
			$this->terminate(255);
75
		}
76 9
		if (count($arguments) < 1) {
77 2
			$this->log("Running default", 'green');
78 2
			$build->runDefault();
0 ignored issues
show
Bug introduced by
The variable $build does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
79 2
			$this->terminate(0);
80
		}
81
82 7
		$method = 'run' . str_replace('-', '', ucfirst($arguments[0]));
83 7
		if (!method_exists($build, $method)) {
84 2
			$this->log("Task '$arguments[0]' does not exists.", 'red');
85 2
			$this->terminate(255);
86
		}
87 6
		$this->log("Running [$arguments[0]]", 'green');
88
		try {
89 6
			$build->$method();
90 6
		} catch (\Exception $e) { // fault barrier -> catch all
91 1
			$this->log("Exited with ERROR:", 'red');
92 1
			$this->log($e->getMessage(), 'red');
93 1
			echo $e->getTraceAsString() . PHP_EOL;
94 1
			$this->terminate(255);
95
		}
96 5
		$this->log("Exited with SUCCESS", 'black', 'green');
97 5
		echo PHP_EOL;
98 6
		$this->terminate(0);
99
	}
100
101
102 14
	protected function terminate($code)
103
	{
104 14
		throw new TerminateException(NULL, $code);
105
	}
106
107
108 12
	protected function detectBootstrapFilename($workingDir)
109
	{
110 12
		return $workingDir . DIRECTORY_SEPARATOR . 'bootstrap.php';
111
	}
112
113
114
	/**
115
	 * @return Container
116
	 */
117 11
	protected function createContainer($workingDir, $configFile, Container $bootstrapContainer = NULL)
118
	{
119 11
		$factory = new ContainerFactory();
120 11
		$factory->addConfig($workingDir . '/' . $configFile);
121 11
		if (is_file($workingDir . '/config.local.neon')) {
122
			$factory->addConfig($workingDir . '/config.local.neon');
123
		}
124 11
		$factory->setWorkingDirectory($workingDir);
125 11
		if ($bootstrapContainer !== NULL) {
126 10
			$factory->addContainerToMerge($bootstrapContainer);
127 10
		}
128 11
		return $factory->create();
129
	}
130
131
132
	/**
133
	 * @param Container $container
134
	 * @return Build
135
	 */
136 11
	protected function createBuild(Container $container, array $arguments = NULL)
137
	{
138 11
		$class = $container->getClass();
139 11
		if (!class_exists($class, TRUE)) {
140 1
			$this->log(sprintf(
141 1
				"Build class '%s' was not found." . PHP_EOL .
142 1
				"Are you in correct working directory?" . PHP_EOL .
143 1
				"Did you forget add bootstrap.php with class loading into working directory?" . PHP_EOL .
144 1
				"Did you forget to load class %s?", $class, $class), 'red');
145 1
			$this->terminate(255);
146
		}
147 10
		$build = new $class($container, $arguments);
148 10
		if (!($build instanceof IBuild)) {
149
			throw new Exception("Instance of build does not implements interface IBuild.");
150
		}
151 10
		$this->autowire($build, $container);
152 9
		$build->setup();
153 9
		return $build;
154
	}
155
156
157 10
	protected function autowire(IBuild $build, Container $container)
158
	{
159 10
		foreach ($this->getAutowiredProperties($build) as $property => $service) {
160 10
			if(!$container->hasService($service)){
161 1
				throw new Exception("Cannot found service '$service' to inject into " . get_class($build) . "::$property.");
162
			}
163 9
			$build->$property = $container->getService($service);
164 9
		}
165 9
	}
166
167
168 10
	protected function getAutowiredProperties($class)
169
	{
170 10
		$return = [];
171 10
		$reflectionClass = new \ReflectionClass($class);
172 10
		foreach ($reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
173 10
			$reflectionProp = new \ReflectionProperty($class, $property->getName());
174 10
			$doc = $reflectionProp->getDocComment();
175 10
			if (preg_match('#@inject ?([^\s]*)\s#s', $doc, $matches)) {
176 10
				$return[$property->getName()] = trim($matches[1]) !== '' ? $matches[1] : $property->getName();
177 10
			}
178 10
		}
179 10
		return $return;
180
	}
181
182
183 13
	protected function log($message, $color = NULL, $backgroundColor = NULL)
184
	{
185 13
		echo Cli::getColoredString($message . PHP_EOL, $color, $backgroundColor);
186 13
	}
187
188
}