Completed
Branch FET/11412/legacy-middleware (374f62)
by
unknown
61:08 queued 45:31
created

validateMiddlewareAppDetails()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 11
c 0
b 0
f 0
nc 5
nop 2
dl 0
loc 20
rs 8.8571
1
<?php
2
3
namespace EventEspresso\core\services\request;
4
5
use EventEspresso\core\services\loaders\LoaderInterface;
6
use SplDoublyLinkedList;
7
8
defined('EVENT_ESPRESSO_VERSION') || exit;
9
10
11
12
/**
13
 * Class RequestStackBuilder
14
 * Assembles the EventEspresso RequestStack
15
 * ! IMPORTANT ! middleware stack operates FIRST IN FIRST OUT
16
 * so items at the beginning of the final middleware array will run last
17
 *
18
 * @package EventEspresso\core\services\request
19
 * @author  Brent Christensen
20
 * @since   4.9.53
21
 */
22
class RequestStackBuilder extends SplDoublyLinkedList
23
{
24
25
    /**
26
     * @type LoaderInterface $loader
27
     */
28
    private $loader;
29
30
31
    /**
32
     * RequestStackBuilder constructor.
33
     *
34
     * @param LoaderInterface $loader
35
     */
36
    public function __construct(LoaderInterface $loader)
37
    {
38
        $this->loader = $loader;
39
        $this->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO | SplDoublyLinkedList::IT_MODE_KEEP);
40
    }
41
42
43
    /**
44
     * builds decorated middleware stack
45
     * by continuously injecting previous middleware app into the next
46
     *
47
     * @param RequestStackCoreAppInterface $application
48
     * @return RequestStack
49
     * @throws InvalidRequestStackMiddlewareException
50
     */
51
    public function resolve(RequestStackCoreAppInterface $application)
52
    {
53
        $core_app = $application;
54
        // NOW... because the RequestStack is following the decorator pattern,
55
        // the first stack app we add will end up at the center of the stack,
56
        // and will end up being the last item to actually run, but we don't want that!
57
        // Basically we're dealing with TWO stacks, and transferring items from one to the other,
58
        // BUT... we want the final stack to be in the same order as the first.
59
        // So we need to reverse the iterator mode when transferring items,
60
        // because if we don't, the second stack will end  up in the incorrect order.
61
        $this->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_KEEP);
62
        for ($this->rewind(); $this->valid(); $this->next()) {
63
            $middleware_app       = $this->validateMiddlewareAppDetails($this->current(), true);
64
            $middleware_app_class = array_shift($middleware_app);
65
            $middleware_app_args  = is_array($middleware_app) ? $middleware_app : array();
66
            $middleware_app_args  = array($application, $this->loader) + $middleware_app_args;
67
            $application = $this->loader->getShared($middleware_app_class, $middleware_app_args);
68
        }
69
        return new RequestStack($application, $core_app);
70
    }
71
72
73
    /**
74
     * Ensures that the app details that have been pushed onto RequestStackBuilder
75
     * are all ordered correctly so that the middleware can be properly constructed
76
     *
77
     * @param array $middleware_app
78
     * @param bool  $recurse
79
     * @return array
80
     * @throws InvalidRequestStackMiddlewareException
81
     */
82
    private function validateMiddlewareAppDetails(array $middleware_app, $recurse = false)
83
    {
84
        $middleware_app_class = reset($middleware_app);
85
        // is array empty ?
86
        if($middleware_app_class === false) {
87
            throw new InvalidRequestStackMiddlewareException($middleware_app_class);
88
        }
89
        // are the class and arguments in the wrong order ?
90
        if(is_array($middleware_app_class)) {
91
            if ($recurse === true) {
92
                return $this->validateMiddlewareAppDetails(array_reverse($middleware_app));
93
            }
94
            throw new InvalidRequestStackMiddlewareException($middleware_app_class);
95
        }
96
        // is $middleware_app_class a valid FQCN (or class is already loaded) ?
97
        if(! class_exists($middleware_app_class)) {
98
            throw new InvalidRequestStackMiddlewareException($middleware_app_class);
99
        }
100
        return $middleware_app;
101
    }
102
}
103