App   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 6
dl 0
loc 124
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 37 4
A registerParameters() 0 6 2
B registerServices() 0 21 5
A handle() 0 21 2
1
<?php
2
/**
3
 * Veto.
4
 * PHP Microframework.
5
 *
6
 * @author Damien Walsh <[email protected]>
7
 * @copyright Damien Walsh 2013-2014
8
 * @version 0.1
9
 * @package veto
10
 */
11
namespace Veto;
12
13
use Veto\Configuration\Hive;
14
use Veto\DependencyInjection\AbstractContainerAccessor;
15
use Veto\DependencyInjection\Container;
16
use Veto\DependencyInjection\Definition;
17
use Veto\Http\Request;
18
use Veto\Http\Response;
19
use Veto\Http\RequestStack;
20
use Veto\Layer\LayerChainBuilder;
21
22
/**
23
 * App
24
 *
25
 * Represents the kernel of a web application.
26
 *
27
 * @since 0.1
28
 */
29
class App extends AbstractContainerAccessor
30
{
31
    /**
32
     * @var bool Whether or not the application is running in Debug mode
33
     */
34
    public $debug = false;
35
36
    /**
37
     * @var RequestStack
38
     */
39
    private $requestStack = null;
40
41
    /**
42
     * Create a new application instance.
43
     *
44
     * @param bool $debug A flag indicating whether or not to start the application in Debug mode.
45
     * @param array $config An associative array of configuration settings for the application.
46
     */
47
    public function __construct($debug = false, array $config = array())
48
    {
49
        // The debug mode flag
50
        $this->debug = $debug;
51
        
52
        // Load the base configuration
53
        $baseConfig = new Hive();
54
        $baseConfig->load(dirname(__DIR__) . '/config/base.yml');
55
56
        // Load the debug configuration if this application will start in Debug mode
57
        if ($this->debug) {
58
            $baseConfig->load(dirname(__DIR__) . '/config/debug.yml');
59
        }
60
61
        // Merge the actual config onto the base config
62
        $baseConfig->merge($config);
63
64
        // Initialise service container
65
        $this->container = new Container;
66
67
        // Register the kernel & configuration hive
68
        $this->container->defineInstance('config', $baseConfig);
69
        $this->container->defineInstance('app', $this);
70
        $this->container->defineInstance('container', $this->container);
71
72
        // Create the request stack and register it with the container
73
        $this->requestStack = new RequestStack;
74
        $this->container->defineInstance('request_stack', $this->requestStack);
75
76
        // Register parameters & services
77
        $this->registerParameters(isset($baseConfig['parameters']) ? $baseConfig['parameters'] : array());
78
        $this->registerServices(isset($baseConfig['services']) ? $baseConfig['services'] : array());
79
80
        // Set up layers
81
        $layerChain = LayerChainBuilder::initWithConfigurationAndContainer($baseConfig, $this->container);
82
        $this->container->defineInstance('chain', $layerChain);
83
    }
84
85
    /**
86
     * Register an array of parameters with the service container.
87
     *
88
     * @param array $parameters The parameters to register
89
     */
90
    private function registerParameters(array $parameters)
91
    {
92
        foreach ($parameters as $name => $value) {
93
            $this->container->setParameter($name, $value);
94
        }
95
    }
96
97
    /**
98
     * Recursively register an array of services as presented in the configuration JSON.
99
     *
100
     * @param array $services The services to register
101
     * @param string $namespace The namespace under which to register services
102
     */
103
    private function registerServices(array $services, $namespace = '')
104
    {
105
        foreach ($services as $name => $element) {
106
107
            if (isset($element['class'])) {
108
109
                // This is a service definition
110
                $definition = Definition::initWithArray($namespace . ($namespace ? '.' : '') . $name, $element);
111
                $this->container->define($definition);
112
113
            } else {
114
115
                // This is an array of services in a namespace
116
                $this->registerServices(
117
                    $element,
118
                    $namespace . ($namespace ? '.' : '') . $name
119
                );
120
121
            }
122
        }
123
    }
124
125
    /**
126
     * Handle a request using the defined layer chain.
127
     *
128
     * @param Request $request
129
     * @return Response
130
     */
131
    public function handle(Request $request)
132
    {
133
        $this->requestStack->push($request);
134
135
        try {
136
137
            // TODO: Not keen on this, need to find a way to avoid referencing the chain service, tags?
138
            $layerChain = $this->container->get('chain');
139
            $response = $layerChain->processLayers($request);
140
            $this->requestStack->pop();
141
142
        } catch (\Exception $exception) {
143
144
            // Invoke the exception controller action method
145
            $exceptionHandler = $this->container->get('controller._exception_handler');
146
            $exceptionHandler->setContainer($this->container);
147
            $response = $exceptionHandler->handleExceptionAction($request, $exception);
148
        }
149
150
        return $response;
151
    }
152
}
153