Completed
Push — develop ( 3414b7...190898 )
by John
03:53
created

FrontController::getRouteCallback()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 36
Code Lines 18

Duplication

Lines 20
Ratio 55.56 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 20
loc 36
rs 8.439
cc 6
eloc 18
nc 8
nop 1
1
<?php
2
3
namespace Alpha\Controller\Front;
4
5
use Alpha\Util\Logging\Logger;
6
use Alpha\Util\Config\ConfigProvider;
7
use Alpha\Util\Security\SecurityUtils;
8
use Alpha\Util\Http\Filter\FilterInterface;
9
use Alpha\Util\Http\Response;
10
use Alpha\Util\Http\Request;
11
use Alpha\Exception\BadRequestException;
12
use Alpha\Exception\ResourceNotFoundException;
13
use Alpha\Exception\SecurityException;
14
use Alpha\Exception\IllegalArguementException;
15
use Alpha\Exception\AlphaException;
16
use Alpha\Controller\Controller;
17
use Alpha\Controller\ArticleController;
18
use Alpha\Controller\AttachmentController;
19
use Alpha\Controller\CacheController;
20
use Alpha\Controller\DEnumController;
21
use Alpha\Controller\ExcelController;
22
use Alpha\Controller\FeedController;
23
use Alpha\Controller\GenSecureQueryStringController;
24
use Alpha\Controller\ImageController;
25
use Alpha\Controller\ListActiveRecordsController;
26
use Alpha\Controller\LogController;
27
use Alpha\Controller\LoginController;
28
use Alpha\Controller\LogoutController;
29
use Alpha\Controller\MetricController;
30
use Alpha\Controller\RecordSelectorController;
31
use Alpha\Controller\SearchController;
32
use Alpha\Controller\SequenceController;
33
use Alpha\Controller\TagController;
34
use Alpha\Controller\IndexController;
35
use Alpha\Controller\InstallController;
36
use Alpha\Controller\ActiveRecordController;
37
use Alpha\Controller\PhpinfoController;
38
39
/**
40
 * The front controller designed to optionally handle all requests.
41
 *
42
 * @since 1.0
43
 *
44
 * @author John Collins <[email protected]>
45
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
46
 * @copyright Copyright (c) 2017, John Collins (founder of Alpha Framework).
47
 * All rights reserved.
48
 *
49
 * <pre>
50
 * Redistribution and use in source and binary forms, with or
51
 * without modification, are permitted provided that the
52
 * following conditions are met:
53
 *
54
 * * Redistributions of source code must retain the above
55
 *   copyright notice, this list of conditions and the
56
 *   following disclaimer.
57
 * * Redistributions in binary form must reproduce the above
58
 *   copyright notice, this list of conditions and the
59
 *   following disclaimer in the documentation and/or other
60
 *   materials provided with the distribution.
61
 * * Neither the name of the Alpha Framework nor the names
62
 *   of its contributors may be used to endorse or promote
63
 *   products derived from this software without specific
64
 *   prior written permission.
65
 *
66
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
67
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
68
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
69
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
70
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
71
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
72
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
73
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
74
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
76
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
77
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
78
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
79
 * </pre>
80
 */
81
class FrontController
82
{
83
    /**
84
     * The GET query string.
85
     *
86
     * @var string
87
     *
88
     * @since 1.0
89
     */
90
    private $queryString;
91
92
    /**
93
     * The name of the page controller we want to invoke.
94
     *
95
     * @var string
96
     *
97
     * @since 1.0
98
     */
99
    private $pageController;
100
101
    /**
102
     * Boolean to flag if the GET query string is encrypted or not.
103
     *
104
     * @var bool
105
     *
106
     * @since 1.0
107
     */
108
    private $encryptedQuery = false;
109
110
    /**
111
     * An array of HTTP filters applied to each request to the front controller.  Each
112
     * member must implement FilterInterface!
113
     *
114
     * @var array
115
     *
116
     * @since 1.0
117
     */
118
    private $filters = array();
119
120
    /**
121
     * An associative array of URIs to callable methods to service matching requests.
122
     *
123
     * @var array
124
     *
125
     * @since 2.0
126
     */
127
    private $routes;
128
129
    /**
130
     * The route for the current request.
131
     *
132
     * @var string
133
     *
134
     * @since 2.0
135
     */
136
    private $currentRoute;
137
138
    /**
139
     * An optional 2D hash array of default request parameter values to use when those params are left off the request.
140
     *
141
     * @var array
142
     *
143
     * @since 2.0
144
     */
145
    private $defaultParamValues;
146
147
    /**
148
     * Trace logger.
149
     *
150
     * @var \Alpha\Util\Logging\Logger
151
     *
152
     * @since 1.0
153
     */
154
    private static $logger = null;
155
156
    /**
157
     * The constructor method.
158
     *
159
     * @throws \Alpha\Exception\BadRequestException
160
     *
161
     * @since 1.0
162
     */
163
    public function __construct()
164
    {
165
        self::$logger = new Logger('FrontController');
166
167
        self::$logger->debug('>>__construct()');
168
169
        $config = ConfigProvider::getInstance();
170
171
        mb_internal_encoding('UTF-8');
172
        mb_http_output('UTF-8');
173
        mb_http_input('UTF-8');
174
        if (!mb_check_encoding()) {
175
            throw new BadRequestException('Request character encoding does not match expected UTF-8');
176
        }
177
178
        $this->addRoute('/', function ($request) {
179
            $controller = new IndexController();
180
181
            return $controller->process($request);
182
        });
183
184
        $this->addRoute('/a/{title}/{view}', function ($request) {
185
            $controller = new ArticleController();
186
187
            return $controller->process($request);
188
        })->value('title', null)->value('view', 'detailed');
189
190
        $this->addRoute('/articles/{start}/{limit}', function ($request) {
191
            $controller = new ArticleController();
192
193
            return $controller->process($request);
194
        })->value('start', 0)->value('limit', $config->get('app.list.page.amount'));
195
196
        $this->addRoute('/attach/{articleOID}/{filename}', function ($request) {
197
            $controller = new AttachmentController();
198
199
            return $controller->process($request);
200
        });
201
202
        $this->addRoute('/cache', function ($request) {
203
            $controller = new CacheController();
204
205
            return $controller->process($request);
206
        });
207
208
        $this->addRoute('/denum/{denumOID}', function ($request) {
209
            $controller = new DEnumController();
210
211
            return $controller->process($request);
212
        })->value('denumOID', null);
213
214
        $this->addRoute('/excel/{ActiveRecordType}/{ActiveRecordOID}', function ($request) {
215
            $controller = new ExcelController();
216
217
            return $controller->process($request);
218
        })->value('ActiveRecordOID', null);
219
220
        $this->addRoute('/feed/{ActiveRecordType}/{type}', function ($request) {
221
            $controller = new FeedController();
222
223
            return $controller->process($request);
224
        })->value('type', 'Atom');
225
226
        $this->addRoute('/gensecure', function ($request) {
227
            $controller = new GenSecureQueryStringController();
228
229
            return $controller->process($request);
230
        });
231
232
        $this->addRoute('/image/{source}/{width}/{height}/{type}/{quality}/{scale}/{secure}/{var1}/{var2}', function ($request) {
233
            $controller = new ImageController();
234
235
            return $controller->process($request);
236
        })->value('var1', null)->value('var2', null);
237
238
        $this->addRoute('/listactiverecords', function ($request) {
239
            $controller = new ListActiveRecordsController();
240
241
            return $controller->process($request);
242
        });
243
244
        $this->addRoute('/log/{logPath}', function ($request) {
245
            $controller = new LogController();
246
247
            return $controller->process($request);
248
        });
249
250
        $this->addRoute('/login', function ($request) {
251
            $controller = new LoginController();
252
253
            return $controller->process($request);
254
        });
255
256
        $this->addRoute('/logout', function ($request) {
257
            $controller = new LogoutController();
258
259
            return $controller->process($request);
260
        });
261
262
        $this->addRoute('/metric', function ($request) {
263
            $controller = new MetricController();
264
265
            return $controller->process($request);
266
        });
267
268
        $this->addRoute('/recordselector/12m/{ActiveRecordOID}/{field}/{relatedClass}/{relatedClassField}/{relatedClassDisplayField}/{relationType}', function ($request) {
269
            $controller = new RecordSelectorController();
270
271
            return $controller->process($request);
272
        })->value('relationType', 'ONE-TO-MANY');
273
274
        $this->addRoute('/recordselector/m2m/{ActiveRecordOID}/{field}/{relatedClassLeft}/{relatedClassLeftDisplayField}/{relatedClassRight}/{relatedClassRightDisplayField}/{accessingClassName}/{lookupOIDs}/{relationType}', function ($request) {
275
            $controller = new RecordSelectorController();
276
277
            return $controller->process($request);
278
        })->value('relationType', 'MANY-TO-MANY');
279
280
        $this->addRoute('/search/{query}/{start}/{limit}', function ($request) {
281
            $controller = new SearchController();
282
283
            return $controller->process($request);
284
        })->value('start', 0)->value('limit', $config->get('app.list.page.amount'));
285
286
        $this->addRoute('/sequence/{start}/{limit}', function ($request) {
287
            $controller = new SequenceController();
288
289
            return $controller->process($request);
290
        })->value('start', 0)->value('limit', $config->get('app.list.page.amount'));
291
292
        $this->addRoute('/tag/{ActiveRecordType}/{ActiveRecordOID}', function ($request) {
293
            $controller = new TagController();
294
295
            return $controller->process($request);
296
        });
297
298
        $this->addRoute('/install', function ($request) {
299
            $controller = new InstallController();
300
301
            return $controller->process($request);
302
        });
303
304
        $this->addRoute('/record/{ActiveRecordType}/{ActiveRecordOID}/{view}', function ($request) {
305
            $controller = new ActiveRecordController();
306
307
            return $controller->process($request);
308
        })->value('ActiveRecordOID', null)->value('view', 'detailed');
309
310
        $this->addRoute('/records/{ActiveRecordType}/{start}/{limit}', function ($request) {
311
            $controller = new ActiveRecordController();
312
313
            return $controller->process($request);
314
        })->value('start', 0)->value('limit', $config->get('app.list.page.amount'));
315
316
        $this->addRoute('/tk/{token}', function ($request) {
317
            $params = self::getDecodeQueryParams($request->getParam('token'));
318
319
            if (isset($params['act'])) {
320
                $className = $params['act'];
321
322
                if (class_exists($className)) {
323
                    $controller = new $className();
324
325
                    if (isset($params['ActiveRecordType']) && $params['act'] == 'Alpha\Controller\ActiveRecordController') {
326
                        $customController = $controller->getCustomControllerName($params['ActiveRecordType']);
327
                        if ($customController != null) {
328
                            $controller = new $customController();
329
                        }
330
                    }
331
332
                    $request->setParams(array_merge($params, $request->getParams()));
333
334
                    return $controller->process($request);
335
                }
336
            }
337
338
            self::$logger->warn('Bad params ['.print_r($params, true).'] provided on a /tk/ request');
339
340
            return new Response(404, 'Resource not found');
341
        });
342
343
        $this->addRoute('/alpha/service', function ($request) {
344
            $controller = new LoginController();
345
            $controller->setUnitOfWork(array('Alpha\Controller\LoginController', 'Alpha\Controller\ListActiveRecordsController'));
346
347
            return $controller->process($request);
348
        });
349
350
        $this->addRoute('/phpinfo', function ($request) {
351
            $controller = new PhpinfoController();
352
353
            return $controller->process($request);
354
        });
355
356
        self::$logger->debug('<<__construct');
357
    }
358
359
    /**
360
     * Sets the encryption flag.
361
     *
362
     * @param bool $encryptedQuery
363
     *
364
     * @since 1.0
365
     */
366
    public function setEncrypt($encryptedQuery)
367
    {
368
        $this->encryptedQuery = $encryptedQuery;
369
    }
370
371
    /**
372
     * Static method for generating an absolute, secure URL for a page controller.
373
     *
374
     * @param string $params
375
     *
376
     * @return string
377
     *
378
     * @since 1.0
379
     */
380
    public static function generateSecureURL($params)
381
    {
382
        $config = ConfigProvider::getInstance();
383
384
        if ($config->get('app.use.mod.rewrite')) {
385
            return $config->get('app.url').'/tk/'.self::encodeQuery($params);
386
        } else {
387
            return $config->get('app.url').'?tk='.self::encodeQuery($params);
388
        }
389
    }
390
391
    /**
392
     * Static method for encoding a query string.
393
     *
394
     * @param string $queryString
395
     *
396
     * @return string
397
     *
398
     * @since 1.0
399
     */
400
    public static function encodeQuery($queryString)
401
    {
402
        $config = ConfigProvider::getInstance();
0 ignored issues
show
Unused Code introduced by
$config is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
403
404
        $return = base64_encode(SecurityUtils::encrypt($queryString));
405
        // remove any characters that are likely to cause trouble on a URL
406
        $return = strtr($return, '+/', '-_');
407
408
        return $return;
409
    }
410
411
    /**
412
     * Method to decode the current query string.
413
     *
414
     * @throws \Alpha\Exception\SecurityException
415
     *
416
     * @since 1.0
417
     * @deprecated
418
     */
419
    private function decodeQuery()
420
    {
421
        $config = ConfigProvider::getInstance();
0 ignored issues
show
Unused Code introduced by
$config is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
422
423
        $params = $this->request->getParams();
0 ignored issues
show
Bug introduced by
The property request does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
424
425
        if (!isset($params['token'])) {
426
            throw new SecurityException('No token provided for the front controller!');
427
        } else {
428
            // replace any troublesome characters from the URL with the original values
429
            $token = strtr($params['token'], '-_', '+/');
430
            $token = base64_decode($token);
431
            $this->queryString = SecurityUtils::decrypt($token);
432
        }
433
    }
434
435
    /**
436
     * Static method to return the decoded GET paramters from an encrytpted tk value.
437
     *
438
     * @return string
439
     *
440
     * @since 1.0
441
     */
442
    public static function decodeQueryParams($tk)
443
    {
444
        $config = ConfigProvider::getInstance();
0 ignored issues
show
Unused Code introduced by
$config is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
445
446
        // replace any troublesome characters from the URL with the original values
447
        $token = strtr($tk, '-_', '+/');
448
        $token = base64_decode($token);
449
        $params = SecurityUtils::decrypt($token);
450
451
        return $params;
452
    }
453
454
    /**
455
     * Static method to return the decoded GET paramters from an encrytpted tk value as an array of key/value pairs.
456
     *
457
     * @return array
458
     *
459
     * @since 1.0
460
     */
461
    public static function getDecodeQueryParams($tk)
462
    {
463
        $config = ConfigProvider::getInstance();
0 ignored issues
show
Unused Code introduced by
$config is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
464
465
        // replace any troublesome characters from the URL with the original values
466
        $token = strtr($tk, '-_', '+/');
467
        $token = base64_decode($token);
468
        $params = SecurityUtils::decrypt($token);
469
470
        $pairs = explode('&', $params);
471
472
        $parameters = array();
473
474
        foreach ($pairs as $pair) {
475
            $split = explode('=', $pair);
476
            $parameters[$split[0]] = $split[1];
477
        }
478
479
        return $parameters;
480
    }
481
482
    /**
483
     * Getter for the page controller.
484
     *
485
     * @return string
486
     *
487
     * @since 1.0
488
     */
489
    public function getPageController()
490
    {
491
        return $this->pageController;
492
    }
493
494
    /**
495
     * Add the supplied filter object to the list of filters ran on each request to the front controller.
496
     *
497
     * @param \Alpha\Util\Http\Filter\FilterInterface $filterObject
498
     *
499
     * @throws \Alpha\Exception\IllegalArguementException
500
     *
501
     * @since 1.0
502
     */
503
    public function registerFilter($filterObject)
504
    {
505
        if ($filterObject instanceof FilterInterface) {
506
            array_push($this->filters, $filterObject);
507
        } else {
508
            throw new IllegalArguementException('Supplied filter object is not a valid FilterInterface instance!');
509
        }
510
    }
511
512
    /**
513
     * Returns the array of filters currently attached to this FrontController.
514
     *
515
     * @return array
516
     *
517
     * @since 1.0
518
     */
519
    public function getFilters()
520
    {
521
        return $this->filters;
522
    }
523
524
    /**
525
     * Add a new route to map a URI to the callback that will service its requests,
526
     * normally by invoking a controller class.
527
     *
528
     * @param string   $URI      The URL to match, can include params within curly {} braces.
529
     * @param callable $callback The method to service the matched requests (should return a Response!).
530
     *
531
     * @throws \Alpha\Exception\IllegalArguementException
532
     *
533
     * @return \Alpha\Controller\Front\FrontController
534
     *
535
     * @since 2.0
536
     */
537
    public function addRoute($URI, $callback)
538
    {
539
        if (is_callable($callback)) {
540
            $this->routes[$URI] = $callback;
541
            $this->currentRoute = $URI;
542
543
            return $this;
544
        } else {
545
            throw new IllegalArguementException('Callback provided for route ['.$URI.'] is not callable');
546
        }
547
    }
548
549
    /**
550
     * Method to allow the setting of default request param values to be used when they are left off the request URI.
551
     *
552
     * @param string $param        The param name (as defined on the route between {} braces)
553
     * @param mixed  $defaultValue The value to use
554
     *
555
     * @return \Alpha\Controller\Front\FrontController
556
     *
557
     * @since 2.0
558
     */
559
    public function value($param, $defaultValue)
560
    {
561
        $this->defaultParamValues[$this->currentRoute][$param] = $defaultValue;
562
563
        return $this;
564
    }
565
566
    /**
567
     * Get the defined callback in the routes array for the URI provided.
568
     *
569
     * @param string $URI The URI to search for.
570
     *
571
     * @return callable
572
     *
573
     * @throws \Alpha\Exception\IllegalArguementException
574
     *
575
     * @since 2.0
576
     */
577
    public function getRouteCallback($URI)
578
    {
579
        if (array_key_exists($URI, $this->routes)) { // direct hit due to URL containing no params
580
            $this->currentRoute = $URI;
581
582
            return $this->routes[$URI];
583
        } else { // we need to use a regex to match URIs with params
584
585
            // route URIs with params provided to callback
586 View Code Duplication
            foreach ($this->routes as $route => $callback) {
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...
587
                $pattern = '#^'.$route.'$#s';
588
                $pattern = preg_replace('#\{\S+\}#', '\S+', $pattern);
589
590
                if (preg_match($pattern, $URI)) {
591
                    $this->currentRoute = $route;
0 ignored issues
show
Documentation Bug introduced by
It seems like $route can also be of type integer. However, the property $currentRoute is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
592
593
                    return $callback;
594
                }
595
            }
596
597
             // route URIs with params missing (will attempt to layer on defaults later on in Request class)
598 View Code Duplication
            foreach ($this->routes as $route => $callback) {
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...
599
                $pattern = '#^'.$route.'$#s';
600
                $pattern = preg_replace('#\/\{\S+\}#', '\/?', $pattern);
601
602
                if (preg_match($pattern, $URI)) {
603
                    $this->currentRoute = $route;
604
605
                    return $callback;
606
                }
607
            }
608
        }
609
610
        // if we made it this far then no match was found
611
        throw new IllegalArguementException('No callback defined for URI ['.$URI.']');
612
    }
613
614
    /**
615
     * Processes the supplied request by invoking the callable defined matching the request's URI.
616
     *
617
     * @param \Alpha\Util\Http\Request $request The request to process
618
     *
619
     * @return \Alpha\Util\Http\Response
620
     *
621
     * @throws \Alpha\Exception\ResourceNotFoundException
622
     * @throws \Alpha\Exception\ResourceNotAllowedException
623
     * @throws \Alpha\Exception\AlphaException
624
     *
625
     * @since 2.0
626
     */
627
    public function process($request)
628
    {
629
        foreach ($this->filters as $filter) {
630
            $filter->process($request);
631
        }
632
633
        try {
634
            $callback = $this->getRouteCallback($request->getURI());
635
        } catch (IllegalArguementException $e) {
636
            self::$logger->info($e->getMessage());
637
            throw new ResourceNotFoundException('Resource not found');
638
        }
639
640
        if ($request->getURI() != $this->currentRoute) {
641
            if (isset($this->defaultParamValues[$this->currentRoute])) {
642
                $request->parseParamsFromRoute($this->currentRoute, $this->defaultParamValues[$this->currentRoute]);
643
            } else {
644
                $request->parseParamsFromRoute($this->currentRoute);
645
            }
646
        }
647
648
        try {
649
            $response = call_user_func($callback, $request);
650
        } catch (ResourceNotFoundException $rnfe) {
651
            self::$logger->info('ResourceNotFoundException throw, source message ['.$rnfe->getMessage().']');
652
653
            return new Response(404, $rnfe->getMessage());
654
        }
655
656
        if ($response instanceof Response) {
657
            return $response;
658
        } else {
659
            self::$logger->error('The callable defined for route ['.$request->getURI().'] does not return a Response object');
660
            throw new AlphaException('Unable to process request');
661
        }
662
    }
663
}
664