/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/core/Dispatcher.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\core;
 
10
 
 
11
/**
 
12
 * The Dispatcher class is responsible for dispatching events. Events
 
13
 * are simply aliases for class methods or functions. The Dispatcher
 
14
 * allows you to hook other functions to an event that can modify the
 
15
 * input parameters and/or the output.
 
16
 */
 
17
class Dispatcher {
 
18
    /**
 
19
     * Mapped events.
 
20
     *
 
21
     * @var array
 
22
     */
 
23
    protected $events = array();
 
24
 
 
25
    /**
 
26
     * Method filters.
 
27
     *
 
28
     * @var array
 
29
     */
 
30
    protected $filters = array();
 
31
 
 
32
    /**
 
33
     * Dispatches an event.
 
34
     *
 
35
     * @param string $name Event name
 
36
     * @param array $params Callback parameters
 
37
     * @return string Output of callback
 
38
     */
 
39
    public function run($name, array $params = array()) {
 
40
        $output = '';
 
41
 
 
42
        // Run pre-filters
 
43
        if (!empty($this->filters[$name]['before'])) {
 
44
            $this->filter($this->filters[$name]['before'], $params, $output);
 
45
        }
 
46
 
 
47
        // Run requested method
 
48
        $output = $this->execute($this->get($name), $params);
 
49
 
 
50
        // Run post-filters
 
51
        if (!empty($this->filters[$name]['after'])) {
 
52
            $this->filter($this->filters[$name]['after'], $params, $output);
 
53
        }
 
54
 
 
55
        return $output;
 
56
    }
 
57
 
 
58
    /**
 
59
     * Assigns a callback to an event.
 
60
     *
 
61
     * @param string $name Event name
 
62
     * @param callback $callback Callback function
 
63
     */
 
64
    public function set($name, $callback) {
 
65
        $this->events[$name] = $callback;
 
66
    }
 
67
 
 
68
    /**
 
69
     * Gets an assigned callback.
 
70
     *
 
71
     * @param string $name Event name
 
72
     * @return callback $callback Callback function
 
73
     */
 
74
    public function get($name) {
 
75
        return isset($this->events[$name]) ? $this->events[$name] : null;
 
76
    }
 
77
 
 
78
    /**
 
79
     * Checks if an event has been set.
 
80
     *
 
81
     * @param string $name Event name
 
82
     * @return bool Event status
 
83
     */
 
84
    public function has($name) {
 
85
        return isset($this->events[$name]);
 
86
    }
 
87
 
 
88
    /**
 
89
     * Clears an event. If no name is given,
 
90
     * all events are removed.
 
91
     *
 
92
     * @param string $name Event name
 
93
     */
 
94
    public function clear($name = null) {
 
95
        if ($name !== null) {
 
96
            unset($this->events[$name]);
 
97
            unset($this->filters[$name]);
 
98
        }
 
99
        else {
 
100
            $this->events = array();
 
101
            $this->filters = array();
 
102
        }
 
103
    }
 
104
 
 
105
    /**
 
106
     * Hooks a callback to an event.
 
107
     *
 
108
     * @param string $name Event name
 
109
     * @param string $type Filter type
 
110
     * @param callback $callback Callback function
 
111
     */
 
112
    public function hook($name, $type, $callback) {
 
113
        $this->filters[$name][$type][] = $callback;
 
114
    }
 
115
 
 
116
    /**
 
117
     * Executes a chain of method filters.
 
118
     *
 
119
     * @param array $filters Chain of filters
 
120
     * @param array $params Method parameters
 
121
     * @param mixed $output Method output
 
122
     */
 
123
    public function filter($filters, &$params, &$output) {
 
124
        $args = array(&$params, &$output);
 
125
        foreach ($filters as $callback) {
 
126
            $continue = $this->execute($callback, $args);
 
127
            if ($continue === false) break;
 
128
        }
 
129
    }
 
130
 
 
131
    /**
 
132
     * Executes a callback function.
 
133
     *
 
134
     * @param callback $callback Callback function
 
135
     * @param array $params Function parameters
 
136
     * @return mixed Function results
 
137
     * @throws \Exception
 
138
     */
 
139
    public static function execute($callback, array &$params = array()) {
 
140
        if (is_callable($callback)) {
 
141
            return is_array($callback) ?
 
142
                self::invokeMethod($callback, $params) :
 
143
                self::callFunction($callback, $params);
 
144
        }
 
145
        else {
 
146
            throw new \Exception('Invalid callback specified.');
 
147
        }
 
148
    }
 
149
 
 
150
    /**
 
151
     * Calls a function.
 
152
     *
 
153
     * @param string $func Name of function to call
 
154
     * @param array $params Function parameters
 
155
     * @return mixed Function results
 
156
     */
 
157
    public static function callFunction($func, array &$params = array()) {
 
158
        switch (count($params)) {
 
159
            case 0:
 
160
                return $func();
 
161
            case 1:
 
162
                return $func($params[0]);
 
163
            case 2:
 
164
                return $func($params[0], $params[1]);
 
165
            case 3:
 
166
                return $func($params[0], $params[1], $params[2]);
 
167
            case 4:
 
168
                return $func($params[0], $params[1], $params[2], $params[3]);
 
169
            case 5:
 
170
                return $func($params[0], $params[1], $params[2], $params[3], $params[4]);
 
171
            default:
 
172
                return call_user_func_array($func, $params);
 
173
        }
 
174
    }
 
175
 
 
176
    /**
 
177
     * Invokes a method.
 
178
     *
 
179
     * @param mixed $func Class method
 
180
     * @param array $params Class method parameters
 
181
     * @return mixed Function results
 
182
     */
 
183
    public static function invokeMethod($func, array &$params = array()) {
 
184
        list($class, $method) = $func;
 
185
 
 
186
                $instance = is_object($class);
 
187
                
 
188
        switch (count($params)) {
 
189
            case 0:
 
190
                return ($instance) ?
 
191
                    $class->$method() :
 
192
                    $class::$method();
 
193
            case 1:
 
194
                return ($instance) ?
 
195
                    $class->$method($params[0]) :
 
196
                    $class::$method($params[0]);
 
197
            case 2:
 
198
                return ($instance) ?
 
199
                    $class->$method($params[0], $params[1]) :
 
200
                    $class::$method($params[0], $params[1]);
 
201
            case 3:
 
202
                return ($instance) ?
 
203
                    $class->$method($params[0], $params[1], $params[2]) :
 
204
                    $class::$method($params[0], $params[1], $params[2]);
 
205
            case 4:
 
206
                return ($instance) ?
 
207
                    $class->$method($params[0], $params[1], $params[2], $params[3]) :
 
208
                    $class::$method($params[0], $params[1], $params[2], $params[3]);
 
209
            case 5:
 
210
                return ($instance) ?
 
211
                    $class->$method($params[0], $params[1], $params[2], $params[3], $params[4]) :
 
212
                    $class::$method($params[0], $params[1], $params[2], $params[3], $params[4]);
 
213
            default:
 
214
                return call_user_func_array($func, $params);
 
215
        }
 
216
    }
 
217
 
 
218
    /**
 
219
     * Resets the object to the initial state.
 
220
     */
 
221
    public function reset() {
 
222
        $this->events = array();
 
223
        $this->filters = array();
 
224
    }
 
225
}