Completed
Push — master ( 27c6b5...777874 )
by Steve
05:09
created

Application::createController()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1
Metric Value
dl 0
loc 9
ccs 4
cts 4
cp 1
rs 9.6666
cc 1
eloc 4
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * @package    Fuel\Foundation
4
 * @version    2.0
5
 * @author     Fuel Development Team
6
 * @license    MIT License
7
 * @copyright  2010 - 2016 Fuel Development Team
8
 * @link       http://fuelphp.com
9
 */
10
11
declare(strict_types=1);
12
13
namespace Fuel\Foundation;
14
15
use Fuel\Config\Container as ConfigContainer;
16
use Fuel\Config\Container;
17
use Fuel\Dependency\Container as DependencyContainer;
18
use Fuel\Foundation\Controller\ControllerInterface;
19
use Fuel\Foundation\Event\AppShutdown;
20
use Fuel\Foundation\Event\AppStarted;
21
use Fuel\Foundation\Event\RequestFinished;
22
use Fuel\Foundation\Event\RequestStarted;
23
use Fuel\Foundation\Event\ResponseFinished;
24
use Fuel\Foundation\Event\ResponseStarted;
25
use Fuel\Foundation\Request\RequestInterface;
26
use Fuel\Foundation\Response\ResponseInterface;
27
use Fuel\Routing\Match;
28
use Fuel\Routing\Router;
29
use League\Container\ContainerInterface;
30
use League\Event\Emitter;
31
use Symfony\Component\BrowserKit\Response;
32
use Zend\Diactoros\CallbackStream;
33
use Zend\Diactoros\Stream;
34
35
class Application
36
{
37
	/**
38
	 * @var ContainerInterface
39
	 */
40
	protected $dependencyContainer;
41
42
	/**
43
	 * @var array
44
	 */
45
	protected $config;
46
47 9
	public static function init(array $config) : Application
48
	{
49
		// Ensure the needed config entries exists
50 9
		$config['events'] = $config['events'] ?? [];
51 9
		$config['components'] = $config['components'] ?? [];
52
53 9
		return new static($config);
54
	}
55
56 9
	public function __construct(array $config, ContainerInterface $dependencyContainer = null)
57
	{
58 9
		$this->initDependencyContainer($config, $dependencyContainer);
59
60
		// register any events from the config
61 9
		$this->registerEvents($config['events']);
62
63
		// Load components
64 9
		$this->loadComponents($config['components']);
65
66 9
		$this->registerRoutes();
67
68
		// trigger app created event
69 9
		$this->dependencyContainer
70 9
			->get('fuel.application.event')
71 9
			->emit(new AppStarted($this));
72 9
	}
73
74 9
	protected function registerRoutes()
75
	{
76
		/** @var Router $router */
77 9
		$router = $this->dependencyContainer->get('fuel.application.router');
78
79
		/** @var Container $config */
80 9
		$config = $this->dependencyContainer->get('fuel.config');
81 9
		$config->load('routing', 'routing');
82
83 9
		foreach ($config->get('routing', []) as $uri => $routeConfig)
84
		{
85 4
			$router->all($uri)->filters($routeConfig);
86
		}
87 9
	}
88
89 9
	public function setDependencyContainer(ContainerInterface $dependencyContainer)
90
	{
91 9
		$this->dependencyContainer = $dependencyContainer;
92 9
	}
93
94 9
	public function getDependencyContainer() : ContainerInterface
95
	{
96 9
		return $this->dependencyContainer;
97
	}
98
99
	/**
100
	 * @param array $events
101
	 */
102 9
	protected function registerEvents(array $events)
103
	{
104
		/** @var Emitter $eventContainer */
105 9
		$eventContainer = $this->dependencyContainer->get('fuel.application.event');
106
107 9
		foreach ($events as $event)
108
		{
109 3
			$eventContainer->addListener(
110 3
				$event['name'],
111 3
				$event['listener'],
112 3
				$event['priority'] ?? $eventContainer::P_NORMAL
113
			);
114
		}
115 9
	}
116
117
	/**
118
	 * @param string[] $components
119
	 */
120 9
	protected function loadComponents(array $components)
121
	{
122
		/** @var ComponentManagerInterface $componentManager */
123 9
		$componentManager = $this->getDependencyContainer()
124 9
			->get('fuel.application.component_manager');
125
126 9
		foreach ($components as $component)
127
		{
128 4
			$componentManager->load($component);
129
		}
130 9
	}
131
132
	/**
133
	 * @param array              $config
134
	 * @param ContainerInterface $dependencyContainer
135
	 */
136 9
	protected function initDependencyContainer(array $config, ContainerInterface $dependencyContainer = null)
137
	{
138 9
		$this->setDependencyContainer($dependencyContainer ?? new DependencyContainer());
139
		// So our application can be fetched
140 9
		$this->dependencyContainer->add('fuel.application', $this);
141
		// And our application config if needed
142 9
		$this->dependencyContainer->add('fuel.application.config', $config);
143
		// Finally add all our application level services
144 9
		$this->dependencyContainer->addServiceProvider(new ApplicationServicesProvider());
145 9
	}
146
147
	public function run()
148
	{
149
		$request = $this->dependencyContainer->get('fuel.application.request');
150
		$response = $this->performRequest($request);
151
152
		// trigger response started event
153
		$this->dependencyContainer
154
			->get('fuel.application.event')
155
			->emit(new ResponseStarted($this));
156
157
		http_response_code($response->getStatusCode());
158
		echo $response->getBody();
159
160
		// send shutdown event
161
		$this->dependencyContainer
162
			->get('fuel.application.event')
163
			->emit(new ResponseFinished($this));
164
165
		$this->dependencyContainer
166
			->get('fuel.application.event')
167
			->emit(new AppShutdown($this));
168
	}
169
170 3
	public function performRequest(RequestInterface $request) : ResponseInterface
171
	{
172 3
		$this->dependencyContainer->add('fuel.application.request', $request);
173
174
		// trigger request started event
175 3
		$this->dependencyContainer
176 3
			->get('fuel.application.event')
177 3
			->emit(new RequestStarted($this));
178
179
		// route to and call controller
180 3
		$match = $this->getRouteMatch($request);
181 3
		$response = $this->getControllerResult($match);
182
183
		// trigger request ended event
184 3
		$this->dependencyContainer
185 3
			->get('fuel.application.event')
186 3
			->emit(new RequestFinished($this));
187
188 3
		return $response;
189
	}
190
191
	/**
192
	 * @param RequestInterface $request
193
	 *
194
	 * @return Match
195
	 */
196 3
	protected function getRouteMatch(RequestInterface $request) : Match
197
	{
198
		/** @var Router $router */
199 3
		$router = $this->dependencyContainer->get('fuel.application.router');
200 3
		$match = $router->translate($request->getUri()->getPath(), $request->getMethod());
201
202 3
		return $match;
203
	}
204
205
	/**
206
	 * @param Match $match
207
	 *
208
	 * @return ResponseInterface
209
	 */
210 3
	protected function getControllerResult(Match $match) : ResponseInterface
211
	{
212 3
		if ($match->controller === null) {
213 1
			$response = $this->dependencyContainer->get('fuel.application.response');
214 1
			return $response->withStatus(404);
215
		}
216
217 2
		$controller = $this->createController($match);
218 2
		$controllerResult = $controller->{$match->action}();
219
220
		// generate and send response
221
		// If the controller response is a response object then just pass that back out
222 2
		if ($controllerResult instanceof ResponseInterface) {
223
			return $controllerResult;
224
		}
225
226
		// Else update the application response with the controller result#
227
		/** @var ResponseInterface $response */
228 2
		$response = $this->dependencyContainer->get('fuel.application.response');
229 2
		$response->withStatus(200);
230 2
		return $response->withBody(new CallbackStream(
231 2
			function() use ($controllerResult) {
232 2
				return $controllerResult;
233 2
			}
234
		));
235
	}
236
237
	/**
238
	 * @param \Fuel\Routing\Match $match
239
	 *
240
	 * @return ControllerInterface
241
	 */
242 2
	protected function createController(Match $match) : ControllerInterface
243
	{
244
		// TODO: Use dependency magic to create the controller instance
245
		/** @var ControllerInterface $controller */
246 2
		$controller = new $match->controller();
247 2
		$controller->setRouteParams($match->parameters);
248
249 2
		return $controller;
250
	}
251
252
}
253