Controller::renderView()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 4
nop 1
dl 0
loc 15
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Core;
4
5
use Twig\Template;
6
use Core\Traits\StringFunctions;
7
8
/**
9
 * Class Controller
10
 * @package Core
11
 *
12
 * PHP version 7
13
 */
14
abstract class Controller
15
{
16
    use StringFunctions;
17
    /**
18
     * the data that will be pushed to the view
19
     * @var array
20
     */
21
    protected $data = [];
22
23
    /**
24
     * @var Container dependency injector
25
     */
26
    protected $container;
27
28
    /**
29
     * @var Dependency\Session the session handler
30
     */
31
    protected $session;
32
33
    /**
34
     * The request object to handle all gets and posts
35
     * @var Dependency\Request
36
     *
37
     */
38
    protected $request;
39
40
    /**
41
     * The response module to handle response messages
42
     * @var Dependency\Response
43
     */
44
    protected $response;
45
46
    protected $cookie;
47
48
    /**
49
     * this will automaticly load all the modules listed and store them as $moduleName in tle class
50
     * Child classes can call aditional modules by calling $this->
51
     * @var array List of modules to load
52
     */
53
    protected $loadModules = [
54
        'Csrf',
55
        'AlertBox',
56
        'Auth',
57
        'Pagination'
58
    ];
59
60
    /**
61
     * We need to declare out modules here, else they will be public
62
     * @var object
63
     */
64
    protected $csrf;
65
    protected $alertBox;
66
    protected $auth;
67
    protected $pagination;
68
69
    /**
70
     * Controller constructor.
71
     * 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
72
     * @param Container $container
73
     *
74
     * @throws \ErrorException on module loading error
75
     * @throws \ReflectionException should never be thrown since only child classes call this
76
     */
77
    public function __construct(Container $container)
78
    {
79
        $this->container = $container;
80
81
        //removing any duplicates that could have been passed in child classes
82
        $this->loadModules = array_unique($this->loadModules);
83
84
        //We load all our module objects into our object
85
        foreach ($this->loadModules as $loadModule) {
86
            $this->loadModule($loadModule);
87
        }
88
        $this->session = $this->container->getSession();
89
90
        $this->request = $container->getRequest(); //adding our request object as it will be needed in the ajax calls
91
        $this->response = $container->getResponse();
92
        $this->cookie = $container->getCookie();
93
94
        //Setting up csrf token security for all calls
95
        $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
96
        $this->data['levelConst'] = $this->auth->getLevelConst();
97
        $this->data['recapchaPublicKey'] = Config::GOOGLE_RECAPCHA_PUBLIC_KEY;
98
    }
99
100
    /**
101
     * load the module to the object
102
     * We look for module in the namespace, then in app and finally in the core.
103
     * This enables us to over-ride the core or app module with a custom module for the namespace.
104
     * @param $loadModule string the module to search for and load
105
     * @throws \ErrorException if module doesn't exits
106
     * @throws \ReflectionException
107
     */
108
    private function loadModule($loadModule)
109
    {
110
        $loadModuleName = lcfirst($loadModule);
111
        $loadModuleObj = $this->getModuleNamespace($loadModule);
112
        //Modules must be children of the Module template
113
        if (!is_subclass_of($loadModuleObj, 'Core\Modules\Module')) {
114
            throw new \ErrorException('Module ' . $loadModuleName . ' must be a sub class of module');
115
        }
116
        $loadedModule = new $loadModuleObj($this->container);
117
        //we are not allowed to create public modules, they must be a placeholder ready
118
        if (!property_exists($this, $loadModuleName)) {
119
            throw new \ErrorException('the protected or private variable of ' . $loadModuleName . ' is not present');
120
        }
121
        $this->$loadModuleName = $loadedModule;
122
    }
123
124
    /**
125
     * takes a module to load and verifies if exists in the current namespace modules, app modules or core modules
126
     * @param $loadModule string Module to look for
127
     * @return string the full module namespace
128
     * @throws \ErrorException if no module is found
129
     * @throws \ReflectionException Should never happen since we are calling on $this
130
     */
131
    private function getModuleNamespace($loadModule)
132
    {
133
        $childClass = new \ReflectionClass(get_class($this));
134
        $childClassNamespace = $childClass->getNamespaceName();
135
        //check in classNameSpace
136
        if (class_exists($childClassNamespace . '\\Modules\\' . $loadModule)) {
137
            $this->addToDevHelper('module ' . $loadModule . ' loaded', $childClassNamespace . '\\' . $loadModule);
138
            return $childClassNamespace . '\\' . $loadModule;
139
        }
140
        //check in app
141
        if (class_exists('App\\Modules\\' . $loadModule)) {
142
            $this->addToDevHelper('module ' . $loadModule . ' loaded', 'App\\Modules\\' . $loadModule);
143
            return 'App\\Modules\\' . $loadModule;
144
        }
145
        //check in core, send error popup if overcharged
146
        if (class_exists('Core\\Modules\\' . $loadModule)) {
147
            $this->addToDevHelper('module ' . $loadModule . ' loaded', 'Core\\Modules\\' . $loadModule);
148
            return 'Core\\Modules\\' . $loadModule;
149
        }
150
151
        //if we are here then no module found
152
        throw new \ErrorException('module ' . $loadModule . ' does not exist or not loaded');
153
154
    }
155
156
    public function index()
157
    {
158
        //if no index, then redirect to the home page or throw an error if in dev; just for debugging purposes
159
        if (Config::DEV_ENVIRONMENT) {
160
            throw new \ErrorException("no index() available in controller call");
161
        }
162
        $this->container->getResponse()->redirect();
163
    }
164
165
    /**
166
     * Calls the templating engine and returns the rendered view
167
     *
168
     * @param $template string the template file name. .twig will be appended
169
     * @return string the rendered template
170
     * @throws \Twig_Error_Loader
171
     * @throws \Twig_Error_Runtime
172
     * @throws \Twig_Error_Syntax
173
     */
174
    public function getView($template)
175
    {
176
        $twig = $this->container->getTemplate();
177
        return $twig->render($template . '.twig', $this->data);
178
    }
179
180
    /**
181
     * rendering the view
182
     *
183
     * @param $template string the template file
184
     * @throws \Twig_Error_Loader
185
     * @throws \Twig_Error_Runtime
186
     * @throws \Twig_Error_Syntax
187
     * @throws \ReflectionException
188
     */
189
    public function renderView($template): void
190
    {
191
        //checking if any alerts and pas the to the template
192
        if ($this->alertBox->alertsPending()) {
193
            $this->data['alert_messages'] = $this->alertBox->getAlerts();
194
        }
195
        //adding the session vars to the page
196
        $this->sendSessionVars();
197
        //adding the dev helper to the page
198
        if (Config::DEV_ENVIRONMENT) {
199
            $this->devHelper();
200
        }
201
202
        $twig = $this->container->getTemplate();
203
        $twig->display($template . '.twig', $this->data);
204
    }
205
206
    /**
207
     * construct a dev helper panel
208
     * @throws \ReflectionException
209
     */
210
    protected function devHelper()
211
    {
212
        $this->data['dev'] = true;
213
214
        $this->addToDevHelper('Class Methods', get_class_methods(get_class($this)));
215
        $this->addToDevHelper('Session Vars', $this->session->getAllSessionVars());
216
        $this->addToDevHelper('uri', $this->container->getRequest()->getUri());
217
        $childClassNamespace = new \ReflectionClass(get_class($this));
218
        $childClassNamespace = $childClassNamespace->getNamespaceName();
219
        $this->addToDevHelper('Child Namespace', $childClassNamespace);
220
221
        //for our object variables, we don't want the devinfo
222
        $objVars = get_object_vars($this);
223
        unset($objVars['data']['dev_info']);
224
        $this->addToDevHelper('Object Variables', $objVars);
225
    }
226
227
    /**
228
     * add info to our dev helper panel
229
     * @param $name
230
     * @param $var
231
     */
232
    protected function addToDevHelper($name, $var)
233
    {
234
        //only populate if in dev environment
235
        if (Config::DEV_ENVIRONMENT) {
236
            $classMethods = [];
237
            $classMethods[$name] = $var;
238
            if (!isset($this->data['dev_info'])) {
239
                $this->data['dev_info'] = [];
240
            }
241
            $this->data['dev_info'] += $classMethods;
242
        }
243
    }
244
245
    /**
246
     * get all the session variables
247
     * @return mixed
248
     */
249
    protected function getSessionVars()
250
    {
251
        return $this->container->getSession()->getAllSessionVars();
252
    }
253
254
    /**
255
     * Send the session variables to the data variable to enable access in twig
256
     */
257
    protected function sendSessionVars()
258
    {
259
        $this->data['session'] = $this->getSessionVars();
260
    }
261
262
    /**
263
     * Only allow post messages
264
     */
265
    protected function onlyPost()
266
    {
267
        //is post
268
        if (!$this->request->isPost()) {
269
            $this->alertBox->setAlert('Only post messages allowed', 'error');
270
            $this->response->redirect('/');
271
        }
272
    }
273
274
    /**
275
     * only allow registered users
276
     */
277
    protected function onlyUser()
278
    {
279
        if (!$this->auth->isUser()) {
280
            $this->alertBox->setAlert("Only registered users can access this", 'error');
281
            $this->container->getResponse()->redirect();
282
        }
283
    }
284
}