/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 fight.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
/**
 
4
 * Fight: an extension to Flight, in the form of useful configuration changes
 
5
 * and extra library code.
 
6
 *
 
7
 * @copyright Copyright (c) 2015, Tim Marston <tim@ed.am>
 
8
 * @licence   MIT
 
9
 *
 
10
 * FIGHT! ...brings the following changes to Flight:
 
11
 *
 
12
 *  1. Global $app object.
 
13
 *
 
14
 *  2. App directorties.
 
15
 *
 
16
 * It is expected that your app has the following layout, and class and view
 
17
 * paths are set up to reflect this:
 
18
 *
 
19
 *     /
 
20
 *     +-- index.php          (see note below)
 
21
 *     +-- app/
 
22
 *         +-- controllers/
 
23
 *         +-- models/
 
24
 *         +-- views/
 
25
 *
 
26
 * Note that index.php MUST go in the top-level directory, or autoloading
 
27
 * breaks.  If you want to keep it in the app/ directory, add a shim index.php
 
28
 * that just requires app/bootstrap.php (or whatever you want to call it).
 
29
 *
 
30
 *  3. The route() method now accepts a class name and routes to class methods.
 
31
 *
 
32
 * The flight route() method now accepts a class name in an array (so, like a
 
33
 * callable, except with no method specified) which indicates a class in which
 
34
 * the part of the URL beyond the route specified should be looked up as a
 
35
 * method and additional URL parts beyond those represented by the name of the
 
36
 * method passed as arguments to the method.
 
37
 *
 
38
 * For example, you could configure routing to a class's methods like this:
 
39
 *
 
40
 *     $app->route( '/some/path', array( 'MyClass' ) );
 
41
 *
 
42
 * Then, for example, /some/path/list will route to MyClass::action_list(),
 
43
 * assuming it exists.
 
44
 *
 
45
 * If MyClass::default_action() exists, then /some/path will route to it.  If
 
46
 * you don't require default functionality, you might still want to use this to
 
47
 * call some other action method.
 
48
 *
 
49
 * If other URL parts are specified beyond the name of the matched method, for
 
50
 * example /some/path/list/1/2, then these are passed as arguments to the
 
51
 * action.  You would define the action method as follows:
 
52
 *
 
53
 *     public static function action_list( $foo = 0, $bar = 0 )
 
54
 *
 
55
 * NOTE: the use of default values for arguments is REQUIRED, or a PHP error
 
56
 * would occur where if they were missing in the HTTP request.
 
57
 *
 
58
 * You can also specify either "special cases" of actions, or actions for a
 
59
 * lower level of the URL path, by using a double-underscore to represent a path
 
60
 * separator in your action method name.  For example, using the above routing,
 
61
 * /some/path/list/1 will route to MyClass::action_list__1(), if it exists,
 
62
 * leaving URLs that have other values in the last part of their path (for
 
63
 * example, /some/path/list/2) to still route to MyClass::action_list() as
 
64
 * before (passing 2 as the first argument).
 
65
 *
 
66
 * Also note that hyphens in URLs are converted to underscores (or they wouldn't
 
67
 * be usable as method names), and multiple underscores are contracred to a
 
68
 * single underscore (so that the path separators can be represented as a
 
69
 * double-underscode in method names)
 
70
 */
 
71
 
 
72
// instantiate flight app
 
73
require 'flight/autoload.php';
 
74
$app = new flight\Engine();
 
75
 
 
76
// set fight class path
 
77
$app->path( __DIR__.'/classes' );
 
78
 
 
79
// set app paths
 
80
$app->set( 'flight.views.path', 'app/views' );
 
81
$app->path( 'app/controllers' );
 
82
 
 
83
// config
 
84
$app->set( 'flight.log_errors', true );
 
85
 
 
86
// add class method router advice to route() method
 
87
$app->before( 'route',
 
88
        function( &$params, &$output ) use( &$app )
 
89
        {
 
90
                // is the callback an array containing only a classname?
 
91
                if( count( $params ) >= 2 &&
 
92
                        is_array( $params[ 1 ] ) &&
 
93
                        count( $params[ 1 ] ) == 1 )
 
94
                {
 
95
                        $class = $params[ 1 ][ 0 ];
 
96
 
 
97
                        // fix-up pattern
 
98
                        $params[ 0 ] = preg_replace( '/\/$/', '', $params[ 0 ] ).'/*';
 
99
 
 
100
                        // replace callback with method router
 
101
                        $params[ 1 ] =
 
102
                                function( $route ) use( &$app, &$class )
 
103
                                {
 
104
                                        // clean up splat
 
105
                                        $splat = preg_replace(
 
106
                                                array( '/(.)\/$/', '/-/', '/_+/' ),
 
107
                                                array( '\1', '_', '_' ), $route->splat );
 
108
 
 
109
                                        // default action?
 
110
                                        if( $splat === '' ) {
 
111
                                                if( method_exists( $class, 'default_action' ) ) {
 
112
                                                        $obj = new $class();
 
113
                                                        return $obj->default_action();
 
114
                                                }
 
115
                                        }
 
116
                                        else {
 
117
                                                // method parts
 
118
                                                $parts = explode( '/', $splat );
 
119
 
 
120
                                                // find method
 
121
                                                $params = array();
 
122
                                                while( count( $parts ) )
 
123
                                                {
 
124
                                                        // check to see if combined parts make a method name
 
125
                                                        $method = 'action_'.implode( '__', $parts );
 
126
                                                        if( method_exists( $class, $method ) ) {
 
127
                                                                $obj = new $class();
 
128
                                                                return call_user_func_array(
 
129
                                                                        array( $obj, $method ), $params );
 
130
                                                        }
 
131
 
 
132
                                                        // discard last part as a param and keep looking
 
133
                                                        array_unshift( $params, array_pop( $parts ) );
 
134
                                                }
 
135
                                        }
 
136
 
 
137
                                        // 404
 
138
                                        $app->notFound();
 
139
                                };
 
140
 
 
141
                        // pass route to callback
 
142
                        $params[ 2 ] = true;
 
143
                }
 
144
        } );
 
145
 
 
146
// add $app to view parameters
 
147
$app->view()->set( 'app', $app );