aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/restapi/UriTemplate.php
blob: f2e70d3322bc69b1559cd48dfc2f76efb992dc55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?php
namespace RESTAPI;

/**
 * @author     Jan-Hendrik Willms <tleilax+studip@gmail.com>
 * @author     <mlunzena@uos.de>
 * @license    GPL 2 or later
 * @since      Stud.IP 3.0
 * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 5.2.
 */
class UriTemplate
{
    public function __construct($uri_template, $conditions = [])
    {
        $this->uri_template = $uri_template;
        $this->conditions = $conditions;
    }

    /**
     * Tests whether an uri matches a template.
     *
     * The template may contain placeholders by prefixing an appropriate,
     * unique placeholder name with a colon (:).
     *
     * <code>$template = '/hello/:name';</code>
     *
     * If the uri matches the template, all evaluated placeholders will
     * be stored in the parameters array.
     *
     * @param String $uri        The uri to test
     * @param Array  $parameters Stores evaluated parameters on match (optional)
     *
     * @return bool Returns true if the uri matches the template
     */
    public function match($uri, &$parameters = null)
    {
        // Initialize parameters array
        $parameters = [];

        // Split and normalize uri and template
        $given = array_filter(explode('/', $uri), 'mb_strlen');
        $rules = array_filter(explode('/', $this->uri_template));

        // Leave if uri and template do not contain the same number of
        // elements
        if (count($given) !== count($rules)) {
            return false;
        }

        // Combine uri and template element-wise (simplifies iteration)
        $combined = array_combine($rules, $given);

        // Iterate over uri and template and compare element by element
        foreach ($combined as $rule => $actual) {
            if ($rule[0] === ':') {
                // Rule is a placeholder
                $parameter_name = mb_substr($rule, 1);

                if (isset($this->conditions[$parameter_name])
                    && !preg_match($this->conditions[$parameter_name], $actual)) {
                    return false;
                }

                $parameters[$parameter_name] = $actual;

            } elseif ($actual !== $rule) {
                // Elements do not match
                $parameters = [];
                return false;
            }
        }

        return true;
    }


    public function inject($params)
    {
        // Initialize parameters array
        $parameters = [];

        // Split and normalize template
        $rules = array_filter(explode('/', $this->uri_template));

        foreach ($rules as &$rule) {

            // Rule is a placeholder
            if ($rule[0] === ':') {
                $parameter_name = mb_substr($rule, 1);

                if (!isset($params[$parameter_name])) {
                    $reason = sprintf('UriTemplate parameter :%s missing.',
                                      htmlReady($parameter_name));
                    throw new \RuntimeException($reason);
                }

                $actual = $params[$parameter_name];

                if (isset($this->conditions[$parameter_name])
                    && !preg_match($this->conditions[$parameter_name], $actual)) {
                    $reason = sprintf('UriTemplate parameter :%s did not satisfy its condition.',
                                      htmlReady($parameter_name));
                    throw new \RuntimeException($reason);
                }

                $rule = htmlReady($actual);
            }
        }

        return join('/', $rules);
    }
}