Completed
Push — master ( b3af43...6273ca )
by Todd
19:01
created

CallbackRoute::getPatternRegex()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 9.4286
cc 2
eloc 14
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2014 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden;
9
10
/**
11
 * A route that maps urls to callbacks.
12
 */
13
class CallbackRoute extends Route {
14
    /// Properties ///
15
16
    /**
17
     *
18
     * @var callable The callback to call on a matching pattern.
19
     */
20
    protected $callback;
21
22
    /// Methods ///
23
24
    /**
25
     * Initialize an instance of the {@link CallbackRoute} class.
26
     *
27
     * @param string $pattern The pattern to match to.
28
     * @param callable $callback The callback to call when the url matches.
29
     */
30 10
    public function __construct($pattern, callable $callback) {
31 10
        $this->pattern($pattern);
32 10
        $this->setCallback($callback);
33 10
    }
34
35
    /**
36
     * Dispatch the matched route and call its callback.
37
     *
38
     * @param Request $request The request to dispatch.
39
     * @param array &$args The arguments returned from {@link CallbackRoute::dispatch()}.
40
     * @return mixed Returns the result of the callback.
41
     */
42 9
    public function dispatch(Request $request, array &$args) {
43 9
        $callback = $args['callback'];
44 9
        $callback_args = reflect_args($callback, $args['args']);
45
46 9
        $result = call_user_func_array($callback, $callback_args);
47 8
        return $result;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53 10
    public function matches(Request $request, Application $app) {
54 10
        if (!$this->matchesMethods($request)) {
55 1
            return null;
56
        }
57
58 10
        if ($this->getMatchFullPath()) {
59 1
            $path = $request->getFullPath();
60
        } else {
61 9
            $path = $request->getPath();
62
        }
63 10
        $regex = $this->getPatternRegex($this->pattern());
64
65 10
        if (preg_match($regex, $path, $matches)) {
66
            // This route matches so extract the args.
67 9
            $args = array();
68 9
            foreach ($matches as $key => $value) {
69 9
                if (!is_numeric($key)) {
70 9
                    $args[$key] = $value;
71
                }
72
            }
73
            $result = array(
74 9
                'callback' => $this->callback,
75 9
                'args' => $args,
76
                );
77 9
            return $result;
78
        } else {
79 2
            return null;
80
        }
81
    }
82
83
    /**
84
     * Convert a path pattern into its regex.
85
     *
86
     * @param string $pattern The route pattern to convert into a regular expression.
87
     * @return string Returns the regex pattern for the route.
88
     */
89
    protected function getPatternRegex($pattern) {
90 10
        $result = preg_replace_callback('`{([^}]+)}`i', function ($match) {
91 5
            if (preg_match('`(.*?)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(.*?)`', $match[1], $matches)) {
92 5
                $before = preg_quote($matches[1], '`');
93 5
                $param = $matches[2];
94 5
                $after = preg_quote($matches[3], '`');
95
            } else {
96
                throw new \Exception("Invalid route parameter: $match[1].", 500);
97
            }
98
99 5
            $param_pattern = val($param, $this->conditions, val($param, self::$globalConditions, '[^/]+?'));
100 5
            $result = "(?<$param>$before{$param_pattern}$after)";
101
102 5
            return $result;
103 10
        }, $pattern);
104
105 10
        $result = '`^'.$result.'$`i';
106 10
        return $result;
107
    }
108
109
    /**
110
     * Get the callback for the route.
111
     *
112
     * @return callable Returns the current callback.
113
     */
114
    public function getCallback() {
115
        return $this->callback;
116
    }
117
118
    /**
119
     * Set the callback for the route.
120
     *
121
     * @param callable $callback The new callback to set.
122
     * @return CallbackRoute Retuns $this for fluent calls.
123
     */
124 10
    public function setCallback(callable $callback) {
125 10
        $this->callback = $callback;
126 10
        return $this;
127
    }
128
}
129
130