Completed
Pull Request — master (#165)
by Paul
03:21
created

Controller::is()   C

Complexity

Conditions 12
Paths 17

Size

Total Lines 35
Code Lines 21

Duplication

Lines 12
Ratio 34.29 %
Metric Value
dl 12
loc 35
rs 5.1612
cc 12
eloc 21
nc 17
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the PPI Framework.
4
 *
5
 * @copyright  Copyright (c) 2012 Paul Dragoonis <[email protected]>
6
 * @license    http://opensource.org/licenses/mit-license.php MIT
7
 *
8
 * @link       http://www.ppi.io
9
 */
10
11
namespace PPI\Framework\Module;
12
13
use Symfony\Component\HttpFoundation\RedirectResponse;
14
use Zend\ServiceManager\ServiceLocatorAwareInterface;
15
use Zend\ServiceManager\ServiceLocatorInterface;
16
17
/**
18
 * The base PPI controller class.
19
 *
20
 * @author     Paul Dragoonis <[email protected]>
21
 */
22
class Controller implements ServiceLocatorAwareInterface
23
{
24
    /**
25
     * Service Locator.
26
     *
27
     * @var null|object
28
     */
29
    protected $serviceLocator = null;
30
31
    /**
32
     * Caching the results of results from $this->is() lookups.
33
     *
34
     * @var array
35
     */
36
    protected $isCache = array();
37
38
    /**
39
     * The options for this controller.
40
     *
41
     * @var array
42
     */
43
    protected $options = array();
44
45
    /**
46
     * Controller helpers.
47
     *
48
     * @var array
49
     */
50
    protected $helpers = array();
51
52
    /**
53
     * Get the request object.
54
     *
55
     * @return object
56
     */
57
    protected function getRequest()
58
    {
59
        return $this->serviceLocator->get('Request');
60
    }
61
62
    /**
63
     * Get the response object.
64
     *
65
     * @return object
66
     */
67
    protected function getResponse()
68
    {
69
        return $this->serviceLocator->get('Response');
70
    }
71
72
    /**
73
     * Obtain a controller helper by its key name.
74
     *
75
     * @param string $helperName
76
     *
77
     * @throws \InvalidArgumentException
78
     *
79
     * @return mixed
80
     */
81
    protected function helper($helperName)
82
    {
83
        if (!isset($this->helpers[$helperName])) {
84
            throw new \InvalidArgumentException('Unable to locate controller helper: ' . $helperName);
85
        }
86
87
        return $this->helpers[$helperName];
88
    }
89
90
    /**
91
     * Set a helper object.
92
     *
93
     * @param string $helperName
94
     * @param object $helper
95
     */
96
    public function setHelper($helperName, $helper)
97
    {
98
        $this->helpers[$helperName] = $helper;
99
    }
100
101
    /**
102
     * Returns a server parameter by name.
103
     *
104
     * @param string $key     The key
105
     * @param mixed  $default The default value if the parameter key does not exist
106
     * @param bool   $deep    If true, a path like foo[bar] will find deeper items
107
     *
108
     * @return string
109
     */
110
    protected function server($key = null, $default = null, $deep = false)
111
    {
112
        return $key === null ? $this->getServer()->all() : $this->getServer()->get($key, $default, $deep);
113
    }
114
115
    /**
116
     * Returns a post parameter by name.
117
     *
118
     * @param string $key     The key
119
     * @param mixed  $default The default value if the parameter key does not exist
120
     * @param bool   $deep    If true, a path like foo[bar] will find deeper items
121
     *
122
     * @return string
123
     */
124
    protected function post($key = null, $default = null, $deep = false)
125
    {
126
        return $key === null ? $this->getPost()->all() : $this->getPost()->get($key, $default, $deep);
127
    }
128
129
    /**
130
     * Returns a files parameter by name.
131
     *
132
     * @param string $key     The key
133
     * @param mixed  $default The default value if the parameter key does not exist
134
     * @param bool   $deep    If true, a path like foo[bar] will find deeper items
135
     *
136
     * @return string
137
     */
138
    protected function files($key = null, $default = null, $deep = false)
139
    {
140
        return $key === null ? $this->getFiles()->all() : $this->getFiles()->get($key, $default, $deep);
141
    }
142
143
    /**
144
     * Returns a query string parameter by name.
145
     *
146
     * @param string $key     The key
147
     * @param mixed  $default The default value if the parameter key does not exist
148
     * @param bool   $deep    If true, a path like foo[bar] will find deeper items
149
     *
150
     * @return string
151
     */
152
    protected function queryString($key = null, $default = null, $deep = false)
153
    {
154
        return $key === null ? $this->getQueryString()->all() : $this->getQueryString()->get($key, $default, $deep);
155
    }
156
157
    /**
158
     * Returns a server parameter by name.
159
     *
160
     * @param string $key     The key
161
     * @param mixed  $default The default value if the parameter key does not exist
162
     * @param bool   $deep    If true, a path like foo[bar] will find deeper items
163
     *
164
     * @return string
165
     */
166
    protected function cookie($key = null, $default = null, $deep = false)
167
    {
168
        return $key === null ? $this->getCookie()->all() : $this->getCookie()->get($key, $default, $deep);
169
    }
170
171
    /**
172
     * Get/Set a session value.
173
     *
174
     * @param string     $key
175
     * @param null|mixed $default If this is not null, it enters setter mode
176
     *
177
     * @return mixed
178
     */
179
    protected function session($key = null, $default = null)
180
    {
181
        return $key === null ? $this->getSession()->all() : $this->getSession()->get($key, $default);
182
    }
183
184
    /**
185
     * Shortcut for getting the server object.
186
     *
187
     * @return object
188
     */
189
    protected function getServer()
190
    {
191
        return $this->getService('Request')->server;
192
    }
193
194
    /**
195
     * Shortcut for getting the files object.
196
     *
197
     * @return object
198
     */
199
    protected function getFiles()
200
    {
201
        return $this->getService('Request')->files;
202
    }
203
204
    /**
205
     * Shortcut for getting the cookie object.
206
     *
207
     * @return object
208
     */
209
    protected function getCookie()
210
    {
211
        return $this->getService('Request')->cookies;
212
    }
213
214
    /**
215
     * Shortcut for getting the query string object.
216
     *
217
     * @return object
218
     */
219
    protected function getQueryString()
220
    {
221
        return $this->getService('Request')->query;
222
    }
223
224
    /**
225
     * Shortcut for getting the post object.
226
     *
227
     * @return object
228
     */
229
    protected function getPost()
230
    {
231
        return $this->getService('Request')->request;
232
    }
233
234
    /**
235
     * Shortcut for getting the session object.
236
     *
237
     * @return mixed
238
     */
239
    protected function getSession()
240
    {
241
        return $this->getService('session');
242
    }
243
244
    /**
245
     * Check if a condition 'is' true.
246
     *
247
     * @param string $key
248
     *
249
     * @throws InvalidArgumentException
250
     *
251
     * @return bool
252
     */
253
    protected function is($key)
254
    {
255
        switch ($key = strtolower($key)) {
256
257 View Code Duplication
            case 'ajax':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
                if (!isset($this->isCache['ajax'])) {
259
                    return $this->isCache['ajax'] = $this->getService('Request')->isXmlHttpRequest();
260
                }
261
262
                return $this->isCache['ajax'];
263
264
            case 'put':
265
            case 'delete':
266
            case 'post':
267
            case 'patch':
268
                if (!isset($this->isCache['requestMethod'][$key])) {
269
                    $this->isCache['requestMethod'][$key] = $this->getService('Request')->getMethod() === strtoupper($key);
270
                }
271
272
                return $this->isCache['requestMethod'][$key];
273
274
            case 'ssl':
275
            case 'https':
276 View Code Duplication
            case 'secure':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
277
                if (!isset($this->isCache['secure'])) {
278
                    $this->isCache['secure'] = $this->getService('Request')->isSecure();
279
                }
280
281
                return $this->isCache['secure'];
282
283
            default:
284
                throw new \InvalidArgumentException("Invalid 'is' key supplied: {$key}");
285
286
        }
287
    }
288
289
    /**
290
     * Get the remote users ip address.
291
     *
292
     * @return string
293
     */
294
    protected function getIP()
295
    {
296
        return $this->server('REMOTE_ADDR');
297
    }
298
299
    /**
300
     * Get a routing param's value.
301
     *
302
     * @param string $param
303
     *
304
     * @return mixed
305
     */
306
    protected function getRouteParam($param)
307
    {
308
        return $this->helper('routing')->getParam($param);
309
    }
310
311
    /**
312
     * Get the remote users user agent.
313
     *
314
     * @return string
315
     */
316
    protected function getUserAgent()
317
    {
318
        return $this->server('HTTP_USER_AGENT');
319
    }
320
321
    /**
322
     * Set service locator.
323
     *
324
     * @param ServiceLocatorInterface $serviceLocator
325
     */
326
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
327
    {
328
        $this->serviceLocator = $serviceLocator;
329
    }
330
331
    /**
332
     * Get service locator.
333
     *
334
     * @return ServiceLocatorInterface
335
     */
336
    public function getServiceLocator()
337
    {
338
        return $this->serviceLocator;
339
    }
340
341
    /**
342
     * Get a registered service.
343
     *
344
     * @param string $service
345
     *
346
     * @return mixed
347
     */
348
    protected function getService($service)
349
    {
350
        return $this->getServiceLocator()->get($service);
351
    }
352
353
    /**
354
     * Get the data source service.
355
     *
356
     * @return mixed
357
     */
358
    protected function getDataSource()
359
    {
360
        return $this->getService('DataSource');
361
    }
362
363
    /**
364
     * Render a template.
365
     *
366
     * @param string $template The template to render
367
     * @param array  $params   The params to pass to the renderer
368
     * @param array  $options  Extra options
369
     *
370
     * @return string
371
     */
372
    protected function render($template, array $params = array(), array $options = array())
373
    {
374
        $renderer = $this->serviceLocator->get('templating');
375
376
        // Helpers
377
        if (isset($options['helpers'])) {
378
            foreach ($options['helpers'] as $helper) {
379
                $renderer->addHelper($helper);
380
            }
381
        }
382
383
        return $renderer->render($template, $params);
384
    }
385
386
    /**
387
     * Set Flash Message.
388
     *
389
     * @param string $flashType The flash type
390
     * @param string $message   The flash message
391
     */
392
    protected function setFlash($flashType, $message)
393
    {
394
        $this->getSession()->getFlashBag()->set($flashType, $message);
395
    }
396
397
    /**
398
     * Create a RedirectResponse object with your $url and $statusCode.
399
     *
400
     * @param string $url
401
     * @param int    $statusCode
402
     *
403
     * @return RedirectResponse
404
     */
405
    protected function redirect($url, $statusCode = 302)
406
    {
407
        $response = new RedirectResponse($url, $statusCode);
408
        $this->getServiceLocator()->set('Response', $response);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: PPI\Framework\ServiceManager\ServiceManager, PPI\Framework\ServiceManager\ServiceManagerBuilder.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
409
410
        return $response;
411
    }
412
413
    /**
414
     * Shortcut function for redirecting to a route without manually calling $this->generateUrl()
415
     * You just specify a route name and it goes there.
416
     *
417
     * @param $route
418
     * @param array      $parameters
419
     * @param bool|false $absolute
420
     *
421
     * @return RedirectResponse
422
     */
423
    protected function redirectToRoute($route, $parameters = array(), $absolute = false)
424
    {
425
        return $this->redirect($this->getService('Router')->generate($route, $parameters, $absolute));
426
    }
427
428
    /**
429
     * Generate a URL from the specified route name.
430
     *
431
     * @param string $route
432
     * @param array  $parameters
433
     * @param bool   $absolute
434
     *
435
     * @return string
436
     */
437
    protected function generateUrl($route, $parameters = array(), $absolute = false)
438
    {
439
        return $this->getService('Router')->generate($route, $parameters, $absolute);
440
    }
441
442
    /**
443
     * Get the app's global configuration.
444
     *
445
     * @return mixed
446
     */
447
    protected function getConfig()
448
    {
449
        return $this->getService('Config');
450
    }
451
452
    /**
453
     * Set the options for this controller.
454
     *
455
     * @param array $options
456
     *
457
     * @return $this
458
     */
459
    public function setOptions($options)
460
    {
461
        $this->options = $options;
462
463
        return $this;
464
    }
465
466
    /**
467
     * Get an option from the controller.
468
     *
469
     * @param string $option  The option name
470
     * @param null   $default The default value if the option does not exist
471
     *
472
     * @return mixed
473
     */
474
    public function getOption($option, $default = null)
475
    {
476
        return isset($this->options[$option]) ? $this->options[$option] : $default;
477
    }
478
479
    /**
480
     * Get the environment type, defaulting to 'development' if it has not been set.
481
     *
482
     * @return string
483
     */
484
    public function getEnv()
485
    {
486
        return $this->getOption('environment', 'development');
487
    }
488
489
    /**
490
     * Add a template global variable.
491
     *
492
     * @param string $param
493
     * @param mixed  $value
494
     */
495
    protected function addTemplateGlobal($param, $value)
496
    {
497
        $this->getService('templating')->addGlobal($param, $value);
498
    }
499
}
500