/www/slight

To get this branch, use:
bzr branch http://bzr.ed.am/www/slight

« back to all changes in this revision

Viewing changes to flight/net/Route.php

  • Committer: Tim Marston
  • Date: 2015-08-05 18:48:29 UTC
  • Revision ID: tim@ed.am-20150805184829-c3qj13d1h89pkb2l
initial commit

Show diffs side-by-side

added added

removed removed

 
1
<?php
 
2
/**
 
3
 * Flight: An extensible micro-framework.
 
4
 *
 
5
 * @copyright   Copyright (c) 2011, Mike Cao <mike@mikecao.com>
 
6
 * @license     MIT, http://flightphp.com/license
 
7
 */
 
8
 
 
9
namespace flight\net;
 
10
 
 
11
/**
 
12
 * The Route class is responsible for routing an HTTP request to
 
13
 * an assigned callback function. The Router tries to match the
 
14
 * requested URL against a series of URL patterns.
 
15
 */
 
16
class Route {
 
17
    /**
 
18
     * @var string URL pattern
 
19
     */
 
20
    public $pattern;
 
21
 
 
22
    /**
 
23
     * @var mixed Callback function
 
24
     */
 
25
    public $callback;
 
26
 
 
27
    /**
 
28
     * @var array HTTP methods
 
29
     */
 
30
    public $methods = array();
 
31
 
 
32
    /**
 
33
     * @var array Route parameters
 
34
     */
 
35
    public $params = array();
 
36
 
 
37
    /**
 
38
     * @var string Matching regular expression
 
39
     */
 
40
    public $regex;
 
41
 
 
42
    /**
 
43
     * @var string URL splat content
 
44
     */
 
45
    public $splat = '';
 
46
 
 
47
    /**
 
48
     * @var boolean Pass self in callback parameters
 
49
     */
 
50
    public $pass = false;
 
51
 
 
52
    /**
 
53
     * Constructor.
 
54
     *
 
55
     * @param string $pattern URL pattern
 
56
     * @param mixed $callback Callback function
 
57
     * @param array $methods HTTP methods
 
58
     * @param boolean $pass Pass self in callback parameters
 
59
     */
 
60
    public function __construct($pattern, $callback, $methods, $pass) {
 
61
        $this->pattern = $pattern;
 
62
        $this->callback = $callback;
 
63
        $this->methods = $methods;
 
64
        $this->pass = $pass;
 
65
    }
 
66
 
 
67
    /**
 
68
     * Checks if a URL matches the route pattern. Also parses named parameters in the URL.
 
69
     *
 
70
     * @param string $url Requested URL
 
71
     * @return boolean Match status
 
72
     */
 
73
    public function matchUrl($url) {
 
74
        // Wildcard or exact match
 
75
        if ($this->pattern === '*' || $this->pattern === $url) {
 
76
            if ($this->pass) {
 
77
                $this->params[] = $this;
 
78
            }
 
79
            return true;
 
80
        }
 
81
 
 
82
        $ids = array();
 
83
        $last_char = substr($this->pattern, -1);
 
84
 
 
85
        // Get splat
 
86
        if ($last_char === '*') {
 
87
            $n = 0;
 
88
            $len = strlen($url);
 
89
            $count = substr_count($this->pattern, '/');
 
90
 
 
91
            for ($i = 0; $i < $len; $i++) {
 
92
                if ($url[$i] == '/') $n++;
 
93
                if ($n == $count) break;
 
94
            }
 
95
 
 
96
            $this->splat = (string)substr($url, $i+1);
 
97
        }
 
98
 
 
99
        // Build the regex for matching
 
100
        $regex = str_replace(array(')','/*'), array(')?','(/?|/.*?)'), $this->pattern);
 
101
 
 
102
        $regex = preg_replace_callback(
 
103
            '#@([\w]+)(:([^/\(\)]*))?#',
 
104
            function($matches) use (&$ids) {
 
105
                $ids[$matches[1]] = null;
 
106
                if (isset($matches[3])) {
 
107
                    return '(?P<'.$matches[1].'>'.$matches[3].')';
 
108
                }
 
109
                return '(?P<'.$matches[1].'>[^/\?]+)';
 
110
            },
 
111
            $regex
 
112
        );
 
113
 
 
114
        // Fix trailing slash
 
115
        if ($last_char === '/') {
 
116
            $regex .= '?';
 
117
        }
 
118
        // Allow trailing slash
 
119
        else {
 
120
            $regex .= '/?';
 
121
        }
 
122
 
 
123
        // Attempt to match route and named parameters
 
124
        if (preg_match('#^'.$regex.'(?:\?.*)?$#i', $url, $matches)) {
 
125
            foreach ($ids as $k => $v) {
 
126
                $this->params[$k] = (array_key_exists($k, $matches)) ? urldecode($matches[$k]) : null;
 
127
            }
 
128
 
 
129
            if ($this->pass) {
 
130
                $this->params[] = $this;
 
131
            }
 
132
 
 
133
            $this->regex = $regex;
 
134
 
 
135
            return true;
 
136
        }
 
137
 
 
138
        return false;
 
139
    }
 
140
 
 
141
    /**
 
142
     * Checks if an HTTP method matches the route methods.
 
143
     *
 
144
     * @param string $method HTTP method
 
145
     * @return bool Match status
 
146
     */
 
147
    public function matchMethod($method) {
 
148
        return count(array_intersect(array($method, '*'), $this->methods)) > 0;
 
149
    }
 
150
}