Completed
Push — master ( 93f6e0...a7ea34 )
by Aydin
27:25 queued 18:55
created

ServiceProvider   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 424
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 39
c 2
b 0
f 1
lcom 2
cbo 5
dl 0
loc 424
rs 8.2857

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A bind() 0 8 3
A sharedData() 0 4 1
A startSession() 0 11 3
A flash() 0 14 4
A flashes() 0 21 4
B markdown() 0 28 4
A escape() 0 4 1
A refresh() 0 8 1
A back() 0 12 2
A layout() 0 10 2
A yieldView() 0 4 1
B render() 0 23 4
A partial() 0 7 1
A addValidator() 0 4 1
A validate() 0 4 1
A validateParam() 0 4 1
A __isset() 0 4 1
A __get() 0 4 1
A __set() 0 4 1
A __unset() 0 4 1
1
<?php
2
/**
3
 * Klein (klein.php) - A fast & flexible router for PHP
4
 *
5
 * @author      Chris O'Hara <[email protected]>
6
 * @author      Trevor Suarez (Rican7) (contributor and v2 refactorer)
7
 * @copyright   (c) Chris O'Hara
8
 * @link        https://github.com/chriso/klein.php
9
 * @license     MIT
10
 */
11
12
namespace Klein;
13
14
use Klein\DataCollection\DataCollection;
15
16
/**
17
 * ServiceProvider 
18
 *
19
 * Service provider class for handling logic extending between
20
 * a request's data and a response's behavior
21
 */
22
class ServiceProvider
23
{
24
25
    /**
26
     * Class properties
27
     */
28
29
    /**
30
     * The Request instance containing HTTP request data and behaviors
31
     *
32
     * @type Request
33
     */
34
    protected $request;
35
36
    /**
37
     * The Response instance containing HTTP response data and behaviors
38
     *
39
     * @type AbstractResponse
40
     */
41
    protected $response;
42
43
    /**
44
     * The id of the current PHP session
45
     *
46
     * @type string|boolean
47
     */
48
    protected $session_id;
49
50
    /**
51
     * The view layout
52
     *
53
     * @type string
54
     */
55
    protected $layout;
56
57
    /**
58
     * The view to render
59
     *
60
     * @type string
61
     */
62
    protected $view;
63
64
    /**
65
     * Shared data collection
66
     *
67
     * @type DataCollection
68
     */
69
    protected $shared_data;
70
71
72
    /**
73
     * Methods
74
     */
75
76
    /**
77
     * Constructor
78
     *
79
     * @param Request $request              Object containing all HTTP request data and behaviors
80
     * @param AbstractResponse $response    Object containing all HTTP response data and behaviors
81
     */
82
    public function __construct(Request $request = null, AbstractResponse $response = null)
83
    {
84
        // Bind our objects
85
        $this->bind($request, $response);
86
87
        // Instantiate our shared data collection
88
        $this->shared_data = new DataCollection();
89
    }
90
91
    /**
92
     * Bind object instances to this service
93
     *
94
     * @param Request $request              Object containing all HTTP request data and behaviors
95
     * @param AbstractResponse $response    Object containing all HTTP response data and behaviors
96
     * @return ServiceProvider
97
     */
98
    public function bind(Request $request = null, AbstractResponse $response = null)
99
    {
100
        // Keep references
101
        $this->request  = $request  ?: $this->request;
102
        $this->response = $response ?: $this->response;
103
104
        return $this;
105
    }
106
107
    /**
108
     * Returns the shared data collection object
109
     *
110
     * @return \Klein\DataCollection\DataCollection
111
     */
112
    public function sharedData()
113
    {
114
        return $this->shared_data;
115
    }
116
117
    /**
118
     * Get the current session's ID
119
     *
120
     * This will start a session if the current session id is null
121
     *
122
     * @return string|false
123
     */
124
    public function startSession()
125
    {
126
        if (session_id() === '') {
127
            // Attempt to start a session
128
            session_start();
129
130
            $this->session_id = session_id() ?: false;
131
        }
132
133
        return $this->session_id;
134
    }
135
136
    /**
137
     * Stores a flash message of $type
138
     *
139
     * @param string $msg       The message to flash
140
     * @param string $type      The flash message type
141
     * @param array $params     Optional params to be parsed by markdown
142
     * @return void
143
     */
144
    public function flash($msg, $type = 'info', $params = null)
0 ignored issues
show
Coding Style introduced by
flash uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
145
    {
146
        $this->startSession();
147
        if (is_array($type)) {
148
            $params = $type;
149
            $type = 'info';
150
        }
151
        if (!isset($_SESSION['__flashes'])) {
152
            $_SESSION['__flashes'] = array($type => array());
153
        } elseif (!isset($_SESSION['__flashes'][$type])) {
154
            $_SESSION['__flashes'][$type] = array();
155
        }
156
        $_SESSION['__flashes'][$type][] = $this->markdown($msg, $params);
157
    }
158
159
    /**
160
     * Returns and clears all flashes of optional $type
161
     *
162
     * @param string $type  The name of the flash message type
163
     * @return array
164
     */
165
    public function flashes($type = null)
0 ignored issues
show
Coding Style introduced by
flashes uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
166
    {
167
        $this->startSession();
168
169
        if (!isset($_SESSION['__flashes'])) {
170
            return array();
171
        }
172
173
        if (null === $type) {
174
            $flashes = $_SESSION['__flashes'];
175
            unset($_SESSION['__flashes']);
176
        } else {
177
            $flashes = array();
178
            if (isset($_SESSION['__flashes'][$type])) {
179
                $flashes = $_SESSION['__flashes'][$type];
180
                unset($_SESSION['__flashes'][$type]);
181
            }
182
        }
183
184
        return $flashes;
185
    }
186
187
    /**
188
     * Render a text string as markdown
189
     *
190
     * Supports basic markdown syntax
191
     *
192
     * Also, this method takes in EITHER an array of optional arguments (as the second parameter)
193
     * ... OR this method will simply take a variable number of arguments (after the initial str arg)
194
     *
195
     * @param string $str   The text string to parse
196
     * @param array $args   Optional arguments to be parsed by markdown
197
     * @return string
198
     */
199
    public static function markdown($str, $args = null)
0 ignored issues
show
Unused Code introduced by
The parameter $str is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
200
    {
201
        // Create our markdown parse/conversion regex's
202
        $md = array(
203
            '/\[([^\]]++)\]\(([^\)]++)\)/' => '<a href="$2">$1</a>',
204
            '/\*\*([^\*]++)\*\*/'          => '<strong>$1</strong>',
205
            '/\*([^\*]++)\*/'              => '<em>$1</em>'
206
        );
207
208
        // Let's make our arguments more "magical"
209
        $args = func_get_args(); // Grab all of our passed args
210
        $str = array_shift($args); // Remove the initial arg from the array (and set the $str to it)
211
        if (isset($args[0]) && is_array($args[0])) {
212
            /**
213
             * If our "second" argument (now the first array item is an array)
214
             * just use the array as the arguments and forget the rest
215
             */
216
            $args = $args[0];
217
        }
218
219
        // Encode our args so we can insert them into an HTML string
220
        foreach ($args as &$arg) {
221
            $arg = htmlentities($arg, ENT_QUOTES, 'UTF-8');
222
        }
223
224
        // Actually do our markdown conversion
225
        return vsprintf(preg_replace(array_keys($md), $md, $str), $args);
226
    }
227
228
    /**
229
     * Escapes a string for UTF-8 HTML displaying
230
     *
231
     * This is a quick macro for escaping strings designed
232
     * to be shown in a UTF-8 HTML environment. Its options
233
     * are otherwise limited by design
234
     *
235
     * @param string $str   The string to escape
236
     * @param int $flags    A bitmask of `htmlentities()` compatible flags
237
     * @return string
238
     */
239
    public static function escape($str, $flags = ENT_QUOTES)
240
    {
241
        return htmlentities($str, $flags, 'UTF-8');
242
    }
243
244
    /**
245
     * Redirects the request to the current URL
246
     *
247
     * @return ServiceProvider
248
     */
249
    public function refresh()
250
    {
251
        $this->response->redirect(
252
            $this->request->uri()
253
        );
254
255
        return $this;
256
    }
257
258
    /**
259
     * Redirects the request back to the referrer
260
     *
261
     * @return ServiceProvider
262
     */
263
    public function back()
264
    {
265
        $referer = $this->request->server()->get('HTTP_REFERER');
266
267
        if (null !== $referer) {
268
            $this->response->redirect($referer);
269
        } else {
270
            $this->refresh();
271
        }
272
273
        return $this;
274
    }
275
276
    /**
277
     * Get (or set) the view's layout
278
     *
279
     * Simply calling this method without any arguments returns the current layout.
280
     * Calling with an argument, however, sets the layout to what was provided by the argument.
281
     *
282
     * @param string $layout    The layout of the view
283
     * @return string|ServiceProvider
284
     */
285
    public function layout($layout = null)
286
    {
287
        if (null !== $layout) {
288
            $this->layout = $layout;
289
290
            return $this;
291
        }
292
293
        return $this->layout;
294
    }
295
296
    /**
297
     * Renders the current view
298
     *
299
     * @return void
300
     */
301
    public function yieldView()
302
    {
303
        require $this->view;
304
    }
305
306
    /**
307
     * Renders a view + optional layout
308
     *
309
     * @param string $view  The view to render
310
     * @param array $data   The data to render in the view
311
     * @return void
312
     */
313
    public function render($view, array $data = array())
314
    {
315
        $original_view = $this->view;
316
317
        if (!empty($data)) {
318
            $this->shared_data->merge($data);
319
        }
320
321
        $this->view = $view;
322
323
        if (null === $this->layout) {
324
            $this->yieldView();
325
        } else {
326
            require $this->layout;
327
        }
328
329
        if (false !== $this->response->chunked) {
330
            $this->response->chunk();
331
        }
332
333
        // restore state for parent render()
334
        $this->view = $original_view;
335
    }
336
337
    /**
338
     * Renders a view without a layout
339
     *
340
     * @param string $view  The view to render
341
     * @param array $data   The data to render in the view
342
     * @return void
343
     */
344
    public function partial($view, array $data = array())
345
    {
346
        $layout = $this->layout;
347
        $this->layout = null;
348
        $this->render($view, $data);
349
        $this->layout = $layout;
350
    }
351
352
    /**
353
     * Add a custom validator for our validation method
354
     *
355
     * @param string $method        The name of the validator method
356
     * @param callable $callback    The callback to perform on validation
357
     * @return void
358
     */
359
    public function addValidator($method, $callback)
360
    {
361
        Validator::addValidator($method, $callback);
362
    }
363
364
    /**
365
     * Start a validator chain for the specified string
366
     *
367
     * @param string $string    The string to validate
368
     * @param string $err       The custom exception message to throw
369
     * @return Validator
370
     */
371
    public function validate($string, $err = null)
372
    {
373
        return new Validator($string, $err);
374
    }
375
376
    /**
377
     * Start a validator chain for the specified parameter
378
     *
379
     * @param string $param     The name of the parameter to validate
380
     * @param string $err       The custom exception message to throw
381
     * @return Validator
382
     */
383
    public function validateParam($param, $err = null)
384
    {
385
        return $this->validate($this->request->param($param), $err);
386
    }
387
388
389
    /**
390
     * Magic "__isset" method
391
     *
392
     * Allows the ability to arbitrarily check the existence of shared data
393
     * from this instance while treating it as an instance property
394
     *
395
     * @param string $key     The name of the shared data
396
     * @return boolean
397
     */
398
    public function __isset($key)
399
    {
400
        return $this->shared_data->exists($key);
401
    }
402
403
    /**
404
     * Magic "__get" method
405
     *
406
     * Allows the ability to arbitrarily request shared data from this instance
407
     * while treating it as an instance property
408
     *
409
     * @param string $key     The name of the shared data
410
     * @return string
411
     */
412
    public function __get($key)
413
    {
414
        return $this->shared_data->get($key);
415
    }
416
417
    /**
418
     * Magic "__set" method
419
     *
420
     * Allows the ability to arbitrarily set shared data from this instance
421
     * while treating it as an instance property
422
     *
423
     * @param string $key     The name of the shared data
424
     * @param mixed $value      The value of the shared data
425
     * @return void
426
     */
427
    public function __set($key, $value)
428
    {
429
        $this->shared_data->set($key, $value);
430
    }
431
432
    /**
433
     * Magic "__unset" method
434
     *
435
     * Allows the ability to arbitrarily remove shared data from this instance
436
     * while treating it as an instance property
437
     *
438
     * @param string $key     The name of the shared data
439
     * @return void
440
     */
441
    public function __unset($key)
442
    {
443
        $this->shared_data->remove($key);
444
    }
445
}
446