Passed
Pull Request — dev (#47)
by Stone
04:17 queued 01:57
created

Controller::getModuleNamespace()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 4
nop 1
dl 0
loc 22
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
namespace Core;
4
5
use Twig\Template;
6
7
/**
8
 * Class Controller
9
 * @package Core
10
 *
11
 * PHP version 7
12
 */
13
abstract class Controller
14
{
15
    /**
16
     * the data that will be pushed to the view
17
     * @var array
18
     */
19
    protected $data = [];
20
21
    /**
22
     * @var Container dependency injector
23
     */
24
    protected $container;
25
26
    /**
27
     * @var Dependency\Session the session handler
28
     */
29
    protected $session;
30
31
    /**
32
     * this will automaticly load all the modules listed and store them as $moduleName in tle class
33
     * Child classes can call aditional modules by calling $this->
34
     * @var array List of modules to load
35
     */
36
    protected $loadModules = [
37
        'Csrf',
38
        'AlertBox'
39
    ];
40
41
    /**
42
     * We need to declare out modules here, else they will be public
43
     * @var object
44
     */
45
    protected $csrf;
46
    protected $alertBox;
47
48
    /**
49
     * Controller constructor.
50
     * We get the module list and construct it. We can also over wright the module in app but sill has to inherit from core module
51
     * @param Container $container
52
     *
53
     * @throws \ErrorException on module loading error
54
     * @throws \ReflectionException should never be thrown since only child classes call this
55
     */
56
    public function __construct(Container $container)
57
    {
58
        $this->container = $container;
59
60
        //removing any duplicates that could have been passed in child classes
61
        $this->loadModules = array_unique($this->loadModules);
62
63
        //We load all our module objects into our object
64
        foreach ($this->loadModules as $loadModule) {
65
            $this->loadModule($loadModule);
66
        }
67
        $this->session = $this->container->getSession();
68
69
        //Setting up csrf token security for all calls
70
        $this->data['csrf_token'] = $this->csrf->getCsrfKey(); //storing the security id into the data array to be sent to the view and added in the meta head
71
    }
72
73
    /**
74
     * load the module to the object
75
     * We look for module in the namespace, then in app and finally in the core.
76
     * This enables us to over-ride the core or app module with a custom module for the namespace.
77
     * @param $loadModule string the module to search for and load
78
     * @throws \ErrorException if module doesn't exits
79
     * @throws \ReflectionException
80
     */
81
    private function loadModule($loadModule)
82
    {
83
        $loadModuleName = lcfirst($loadModule);
84
        $loadModuleObj = $this->getModuleNamespace($loadModule);
85
        //Modules must be children of the Module template
86
        if (!is_subclass_of($loadModuleObj, 'Core\Modules\Module')) {
87
            throw new \ErrorException('Module ' . $loadModuleName . ' must be a sub class of module');
88
        }
89
        $loadedModule = new $loadModuleObj($this->container);
90
        //we are not allowed to create public modules, they must be a placeholder ready
91
        if (!property_exists($this, $loadModuleName)) {
92
            throw new \ErrorException('the protected or private variable of ' . $loadModuleName . ' is not present');
93
        }
94
        $this->$loadModuleName = $loadedModule;
95
    }
96
97
    /**
98
     * takes a module to load and verifies if exists in the current namespace modules, app modules or core modules
99
     * @param $loadModule string Module to look for
100
     * @return string the full module namespace
101
     * @throws \ErrorException if no module is found
102
     * @throws \ReflectionException Should never happen since we are calling on $this
103
     */
104
    private function getModuleNamespace($loadModule)
105
    {
106
        $childClass = new \ReflectionClass(get_class($this));
107
        $childClassNamespace = $childClass->getNamespaceName();
108
        //check in classNameSpace
109
        if (class_exists($childClassNamespace . '\\Modules\\' . $loadModule)) {
110
            $this->addToDevHelper('module ' . $loadModule . ' loaded', $childClassNamespace . '\\' . $loadModule);
111
            return $childClassNamespace . '\\' . $loadModule;
112
        }
113
        //check in app
114
        if (class_exists('App\\Modules\\' . $loadModule)) {
115
            $this->addToDevHelper('module ' . $loadModule . ' loaded', 'App\\Modules\\' . $loadModule);
116
            return 'App\\Modules\\' . $loadModule;
117
        }
118
        //check in core, send error popup if overcharged
119
        if (class_exists('Core\\Modules\\' . $loadModule)) {
120
            $this->addToDevHelper('module ' . $loadModule . ' loaded', 'Core\\Modules\\' . $loadModule);
121
            return 'Core\\Modules\\' . $loadModule;
122
        }
123
124
        //if we are here then no module found
125
        throw new \ErrorException('module ' . $loadModule . ' does not exist or not loaded');
126
127
    }
128
129
    public function index()
130
    {
131
        //if no index, then redirect to the home page or throw an error if in dev; just for debugging purposes
132
        if (Config::DEV_ENVIRONMENT) {
133
            throw new \ErrorException("no index() available in controller call");
134
        }
135
        $this->container->getResponse()->redirect();
136
    }
137
138
    /**
139
     * Calls the templating engine and returns the rendered view
140
     *
141
     * @param $template string the template file name. .twig will be appended
142
     * @return string the rendered template
143
     * @throws \Twig_Error_Loader
144
     * @throws \Twig_Error_Runtime
145
     * @throws \Twig_Error_Syntax
146
     */
147
    public function getView($template)
148
    {
149
        $twig = $this->container->getTemplate();
150
        return $twig->render($template . '.twig', $this->data);
151
    }
152
153
    /**
154
     * rendering the view
155
     *
156
     * @param $template string the template file
157
     * @throws \Twig_Error_Loader
158
     * @throws \Twig_Error_Runtime
159
     * @throws \Twig_Error_Syntax
160
     * @throws \ReflectionException
161
     */
162
    public function renderView($template): void
163
    {
164
        //checking if any alerts and pas the to the template
165
        if ($this->alertBox->alertsPending()) {
166
            $this->data['alert_messages'] = $this->alertBox->getAlerts();
167
        }
168
        if (Config::DEV_ENVIRONMENT) {
169
            $this->devHelper();
170
        }
171
        $twig = $this->container->getTemplate();
172
        $twig->display($template . '.twig', $this->data);
173
    }
174
175
    /**
176
     * construct a dev helper panel
177
     * @throws \ReflectionException
178
     */
179
    protected function devHelper()
180
    {
181
        $this->data['dev'] = true;
182
183
        $this->addToDevHelper('Class Methods', get_class_methods(get_class($this)));
184
        $this->addToDevHelper('Session Vars', $this->session->getAllSessionVars());
185
        $this->addToDevHelper('uri', $this->container->getRequest()->getUri());
186
        $childClassNamespace = new \ReflectionClass(get_class($this));
187
        $childClassNamespace = $childClassNamespace->getNamespaceName();
188
        $this->addToDevHelper('Child Namespace', $childClassNamespace);
189
190
        //for our object variables, we don't want the devinfo
191
        $objVars = get_object_vars($this);
192
        unset($objVars['data']['dev_info']);
193
        $this->addToDevHelper('Object Variables', $objVars);
194
    }
195
196
    /**
197
     * add info to our dev helper panel
198
     * @param $name
199
     * @param $var
200
     */
201
    protected function addToDevHelper($name, $var)
202
    {
203
        //only populate if in dev environment
204
        if (Config::DEV_ENVIRONMENT){
205
            $classMethods = [];
206
            $classMethods[$name] = $var;
207
            if (!isset($this->data['dev_info'])) {
208
                $this->data['dev_info'] = [];
209
            }
210
            $this->data['dev_info'] += $classMethods;
211
        }
212
    }
213
}