Completed
Branch bootstrap-refactoring (b06695)
by Adam
03:28
created

Bootstrap.php (1 issue)

Labels
Severity

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 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
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
}