Changeset 161

Show
Ignore:
Timestamp:
03/02/06 17:20:34 (6 years ago)
Author:
haas
Message:

Finish Router class doc, regression test

Location:
trunk/trax
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • trunk/trax/config/routes.php

    r138 r161  
    11<?php                        
    22/** 
     3 *  Configuration file to define URL to action mapping 
     4 * 
     5 *  This file contains one or more PHP statements that call 
     6 *  {@link Router::connect() $router->connect()} to add routes to the 
     7 *  route table stored in the {@link Router} object pointed to by 
     8 *  $router. 
     9 * 
    310 *  Add your own custom routes here. 
    411 *  The priority is based upon order of creation: first created -> 
  • trunk/trax/test/RouterTest.php

    r159 r161  
    6565 
    6666    /** 
    67      * @todo Implement testGet_selected_route(). 
     67     *  Test build_route_regexp(). 
    6868     */ 
    69     public function testGet_selected_route() { 
    70         // Remove the following line when you implement this test. 
    71         throw new PHPUnit2_Framework_IncompleteTestError; 
     69    public function testBuild_route_regexp() { 
     70        $r = new Router; 
     71        // Two abstract route components 
     72        $regexp = $r->build_route_regexp(':foo/:bar'); 
     73        $this->assertEquals($regexp, 
     74                            '^[a-z0-9_\-]+\/[a-z0-9_\-]+$'); 
     75        // Three abstract route components 
     76        $regexp = $r->build_route_regexp(':foo/:bar/:mumble'); 
     77        $this->assertEquals($regexp, 
     78                            '^[a-z0-9_\-]+\/[a-z0-9_\-]+\/[a-z0-9_\-]+$'); 
     79        // Abstract, concrete, abstract route components 
     80        $regexp = $r->build_route_regexp(':foo/bar/:mumble'); 
     81        $this->assertEquals($regexp, 
     82                            '^[a-z0-9_\-]+\/bar\/[a-z0-9_\-]+$'); 
     83        // Two concrete route components 
     84        $regexp = $r->build_route_regexp('foo/bar'); 
     85        $this->assertEquals($regexp, 
     86                            '^foo\/bar$'); 
    7287    } 
    7388 
    7489    /** 
    75      * @todo Implement testConnect(). 
     90     * Test default route table 
    7691     */ 
    77     public function testConnect() { 
    78         // Remove the following line when you implement this test. 
    79         throw new PHPUnit2_Framework_IncompleteTestError; 
     92    public function testDefault_route() { 
     93        $r = new Router; 
     94        // Should find default route 
     95        $route = $r->find_route('a/b/mumble'); 
     96        $this->assertEquals(':controller/:action/:id', $route['path']); 
     97        $this->assertNull($route['params']); 
    8098    } 
    8199 
    82100    /** 
    83      * @todo Implement testFind_route(). 
     101     * Test route table with one simple entry besides default 
    84102     */ 
    85     public function testFind_route() { 
    86         // Remove the following line when you implement this test. 
    87         throw new PHPUnit2_Framework_IncompleteTestError; 
     103    public function testSimple_route() { 
     104        $r = new Router; 
     105        //  Build route table 
     106        $r->connect(':foo/:bar/mumble', array('mumble route')); 
     107        //  Params not an array ignored, null is stored 
     108        $r->connect(':controller/:action/:id', 'not-an-array'); 
     109 
     110        //  Match first route 
     111        $route = $r->find_route('a/b/mumble'); 
     112        $this->assertEquals(':foo/:bar/mumble', $route['path']); 
     113        $this->assertEquals(array('mumble route'), $route['params']); 
     114        $selected = $r->get_selected_route(); 
     115        $this->assertEquals(':foo/:bar/mumble', $selected['path']); 
     116        $this->assertEquals(array('mumble route'), $selected['params']); 
     117 
     118        //  Match second route 
     119        $route = $r->find_route('a/b/c'); 
     120        $this->assertEquals(':controller/:action/:id', $route['path']); 
     121        $this->assertNull($route['params']); 
     122        $selected = $r->get_selected_route(); 
     123        $this->assertEquals(':controller/:action/:id', $selected['path']); 
     124        $this->assertNull($selected['params']); 
    88125    } 
    89126 
    90127    /** 
    91      * @todo Implement testBuild_route_regexp(). 
     128     * Test route table with one regexp entry besides default 
    92129     */ 
    93     public function testBuild_route_regexp() { 
    94         // Remove the following line when you implement this test. 
    95         throw new PHPUnit2_Framework_IncompleteTestError; 
     130    public function testRegexp_route() { 
     131        $r = new Router; 
     132        //  Build route table 
     133        $r->connect(':foo/:bar/\?(catalog|part)number=.*', 
     134                    array('number route')); 
     135        $r->connect(':controller/:action/:id', array('default route')); 
     136 
     137        //  Match first route 
     138        $route = $r->find_route('a/b/?catalognumber=17'); 
     139        $this->assertEquals(':foo/:bar/\?(catalog|part)number=.*', 
     140                            $route['path']); 
     141        $this->assertEquals(array('number route'), $route['params']); 
     142        $route = $r->find_route('a/b/?partnumber=123-456'); 
     143        $this->assertEquals(':foo/:bar/\?(catalog|part)number=.*', 
     144                            $route['path']); 
     145        $this->assertEquals(array('number route'), $route['params']); 
     146        $route = $r->find_route('a/b/?personnumber=156'); 
     147        $this->assertEquals(':controller/:action/:id', $route['path']); 
     148        $this->assertEquals(array('default route'), $route['params']); 
     149    } 
     150 
     151    /** 
     152     * Test route table with route with empty path 
     153     */ 
     154    public function testEmpty_route() { 
     155        $r = new Router; 
     156        //  Build route table with only an empty path 
     157        $r->connect('', array('empty route')); 
     158        $route = $r->find_route(''); 
     159        $this->assertEquals('', $route['path']); 
     160        $this->assertEquals(array('empty route'), $route['params']); 
     161        //  This route shouldn't match anything 
     162        $route = $r->find_route('mumble/foo'); 
     163        $this->assertNull($route); 
    96164    } 
    97165} 
  • trunk/trax/tutorials/PHPonTrax/Router.cls

    r155 r161  
    22 <refnamediv> 
    33  <refname>Router</refname> 
    4   <refpurpose>@todo Router tutorial</refpurpose> 
     4  <refpurpose>Convert a URL to an action</refpurpose> 
    55 </refnamediv> 
    66 <refsynopsisdiv> 
     
    1515 <refsect1 id="{@id intro}"> 
    1616  <title>Introduction</title> 
     17 
     18  <para>The {@link Router Router class} owns the information and 
     19   algorithms that convert URLs to actions.  An object of this class 
     20   holds a {@link Router::$routes route table} containing routes to be 
     21   matched to URLs.</para> 
     22 
     23  <para>In normal operation, a Router object is created by  
     24   {@link ActionController::load_router()} which reads routes from the 
     25   configuration file {@link routes.php config/routes.php}.</para> 
     26 
    1727 </refsect1> 
     28 <refsect1 id="{@id table}"> 
     29  <title>Structure of the Route Table</title> 
     30 
     31  <para>The route table is an ordered list of routes.  A route consists 
     32   of a path and a (possibly null) parameter array. The structure of 
     33   the table is:</para> 
     34 
     35  <example> 
     36$routes[0]['path']    First route path 
     37          ['params']  First route parameters 
     38       [1]['path']    Second route path 
     39          ['params']  Second route parameters 
     40... 
     41  </example> 
     42 
     43  <para>A route path consists of character strings separated by 
     44   forward slash ('/') characters.  The route path must not begin 
     45   or end with '/', and the character strings in the path must 
     46   not contain '/'.  There are two kinds of character strings in 
     47   route paths:</para> 
     48 
     49  <unorderedlist> 
     50   <listitem>Placeholder strings start with a colon (':') followed by 
     51    one or more alphameric characters chosen from "a..z0..9_-".  A 
     52    placeholder string matches any alphameric string in the same 
     53    position of a URL.  The actual contents of the placeholder string 
     54    following ':' are irrelevant.</listitem>  
     55   <listitem>Pattern strings start with any character except ':' or 
     56    '/' followed by any character except '/'.  The contents of 
     57    the pattern string are a 
     58    {@link http://www.php.net/manual/en/ref.pcre.php Perl regular expression}. 
     59   </listitem> 
     60  </unorderedlist> 
     61 
     62  <para>The order of routes in the table is significant.  When a URL 
     63   is to be matched, the route table is searched in order from first 
     64   entry to last.  The first route entry that matches is 
     65   returned.</para> 
     66 
     67  <para>{@link Router::find_route()} guarantees that there will always be 
     68   at least one route in the table by inserting 
     69   {@link Router::$default_route_path} if the table is empty when 
     70   find_route() is called.</para> 
     71 </refsect1> 
     72 
     73 <refsect1 id="{@id build}"> 
     74  <title>Constructing the Route Table</title> 
     75 
     76  <para>To construct a route table, first create a new Router object, 
     77   then  make multiple calls to {@link Router::connect()} to add route 
     78   entries to the object's table.  The second argument to connect(), if 
     79   specified, must be an array, but the array can hold anything (or 
     80   nothing).</para> 
     81 
     82  <para>There is no way to change or delete an existing route table 
     83   entry.</para> 
     84  <para>Either assure that any path you search for will return some 
     85  route, or prepare to deal with a null return from 
     86  {@link Router::find_route()} </para> 
     87 
     88  <para><important>CAUTION:</important> Do not call 
     89   {@link Router::find_route()} before calling 
     90   {@link Router::connect()}, unless you want the default route to be 
     91   the first entry in the route table.</para> 
     92 
     93 </refsect1> 
     94 <refsect1 id="{@id search}"> 
     95  <title>Searching the Route Table</title> 
     96 
     97  <para>To look up a URL in the route table, call 
     98   {@link Router::find_route()} with the URL as argument.  A copy of 
     99   the first matching route table entry, if any, will be returned.  If 
     100   none matches, null will be returned.</para> 
     101 
     102  <para>A URL consisting of a null string '' matches a route 
     103   whose path is a null string.</para> 
     104 
     105  <para>A copy of the last route table entry returned by find_route() 
     106   is saved in {@link Router::$selected_route}.  It can be fetched by 
     107   a call to {@link Router::get_selected_route()}.  The next call to 
     108   find_route() overwrites the previous value in 
     109   $selected_route.</para> 
     110 
     111 </refsect1> 
     112<!-- 
     113Local variables: 
     114mode: xml 
     115c-basic-offset: 1 
     116indent-tabs-mode: nil 
     117End: 
     118--> 
    18119</refentry> 
  • trunk/trax/vendor/trax/action_controller.php

    r155 r161  
    182182 *   } 
    183183 *  </pre> 
    184  * 
    185  *  @package PHPonTrax 
    186184 */ 
    187185class ActionController { 
    188186 
    189     private 
    190         $controller, 
    191         $action, 
    192         $id, 
    193         $controllers_path, 
    194         $helpers_path, 
    195         $helpers_base_path, 
    196         $layouts_path, 
    197         $url_path, 
    198         $default_layout_file, 
    199         $helper_file, 
    200         $application_controller_file, 
    201         $application_helper_file, 
    202         $loaded = false, 
    203         $router_loaded = false, 
    204         $helpers = array(), 
    205         $before_filters = array(), 
    206         $after_filters = array();      
    207     protected 
    208         $before_filter = null, 
    209         $after_filter = null; 
    210     public 
    211         $controller_file, 
    212         $view_file, 
    213         $views_path, 
    214         $controller_class,  
    215         $controller_object, 
    216         $asset_host = null, 
    217         $views_file_extention = TRAX_VIEWS_EXTENTION; 
    218  
     187    /** 
     188     *  @todo Document this attribute 
     189     */ 
     190    private $controller; 
     191 
     192    /** 
     193     *  @todo Document this attribute 
     194     */ 
     195    private $action; 
     196 
     197    /** 
     198     *  @todo Document this attribute 
     199     */ 
     200    private $id; 
     201 
     202    /** 
     203     *  @todo Document this attribute 
     204     */ 
     205    private $controllers_path; 
     206 
     207    /** 
     208     *  @todo Document this attribute 
     209     */ 
     210    private $helpers_path; 
     211 
     212    /** 
     213     *  @todo Document this attribute 
     214     */ 
     215    private $helpers_base_path; 
     216 
     217    /** 
     218     *  @todo Document this attribute 
     219     */ 
     220    private $layouts_path; 
     221 
     222    /** 
     223     *  @todo Document this attribute 
     224     */ 
     225    private $url_path; 
     226 
     227    /** 
     228     *  @todo Document this attribute 
     229     */ 
     230    private $default_layout_file; 
     231 
     232    /** 
     233     *  @todo Document this attribute 
     234     */ 
     235    private $helper_file; 
     236 
     237    /** 
     238     *  @todo Document this attribute 
     239     */ 
     240    private $application_controller_file; 
     241 
     242    /** 
     243     *  @todo Document this attribute 
     244     */ 
     245    private $application_helper_file; 
     246 
     247    /** 
     248     *  @todo Document this attribute 
     249     */ 
     250    private $loaded = false; 
     251 
     252    /** 
     253     *  Whether a Router object was loaded 
     254     * 
     255     *  @var boolean 
     256     *  <ul> 
     257     *    <li>true => $router points to the Router object</li> 
     258     *    <li>false => no Router object exists</li> 
     259     *  </ul> 
     260     */ 
     261    private $router_loaded = false; 
     262 
     263    /** 
     264     *  @todo Document this attribute 
     265     */ 
     266    private $helpers = array(); 
     267 
     268    /** 
     269     *  @todo Document this attribute 
     270     */ 
     271    private $before_filters = array(); 
     272 
     273    /** 
     274     *  @todo Document this attribute 
     275     */ 
     276    private $after_filters = array();      
     277 
     278    /** 
     279     *  @todo Document this attribute 
     280     */ 
     281    protected $before_filter = null; 
     282 
     283    /** 
     284     *  @todo Document this attribute 
     285     */ 
     286    protected $after_filter = null; 
     287 
     288    /** 
     289     *  @todo Document this attribute 
     290     */ 
     291    public $controller_file; 
     292 
     293    /** 
     294     *  @todo Document this attribute 
     295     */ 
     296    public $view_file; 
     297 
     298    /** 
     299     *  @todo Document this attribute 
     300     */ 
     301    public $views_path; 
     302 
     303    /** 
     304     *  @todo Document this attribute 
     305     */ 
     306    public $controller_class; 
     307 
     308    /** 
     309     *  @todo Document this attribute 
     310     */ 
     311    public $controller_object; 
     312 
     313    /** 
     314     *  @todo Document this attribute 
     315     */ 
     316    public $asset_host = null; 
     317 
     318    /** 
     319     *  @todo Document this attribute 
     320     */ 
     321    public $views_file_extention = TRAX_VIEWS_EXTENTION; 
     322 
     323    /** 
     324     *  @todo Document this method 
     325     */ 
    219326    function __construct() { 
    220327      if(!isset($this->router) || !is_object($this->router)) { 
     
    223330    } 
    224331 
     332    /** 
     333     *  @todo Document this method 
     334     */ 
    225335    function __set($key, $value) { 
    226336        #echo "setting: $key = $value<br>"; 
     
    236346    } 
    237347 
     348    /** 
     349     *  @todo Document this method 
     350     */ 
    238351    function __call($method_name, $parameters) { 
    239352        if(method_exists($this, $method_name)) { 
     
    252365    } 
    253366 
     367    /** 
     368     *  Load routes from configuration file routes.php 
     369     * 
     370     *  Routes are loaded by requiring {@link routes.php} from the 
     371     *  configuration directory. 
     372     *  @uses Router 
     373     *  @uses $router 
     374     *  @uses $router_loaded 
     375     */ 
    254376    function load_router() { 
    255377        $this->router_loaded = false; 
     
    263385    } 
    264386 
     387    /** 
     388     *  @todo Document this method 
     389     *  @uses load_router() 
     390     *  @uses $router 
     391     *  @uses $router_loaded 
     392     *  @uses set_paths() 
     393     *  @uses $url_path 
     394     */ 
    265395    function recognize_route() { 
    266396 
     
    341471    } 
    342472 
     473    /** 
     474     *  @todo Document this method 
     475     */ 
    343476    function process_route() { 
    344477 
     
    346479        if(!$this->loaded) { 
    347480            if(!$this->recognize_route()) { 
    348                 $this->raise("Failed to load any defined routes", "Controller ".$this->controller." not found", "404"); 
     481                $this->raise("Failed to load any defined routes", 
     482                 "Controller ".$this->controller." not found", 
     483                 "404"); 
    349484            } 
    350485        } 
     
    496631 
    497632        return true; 
    498     } 
    499  
     633    }                                // function process_route() 
     634 
     635    /** 
     636     *  @todo Document this method 
     637     */ 
    500638    function set_paths() { 
    501639        if(is_array($this->url_path)) { 
     
    681819    } 
    682820 
     821    /** 
     822     *  @todo Document this method 
     823     */ 
    683824    function determine_layout() { 
    684825        # I guess you don't want any layout 
     
    788929} 
    789930 
     931// -- set Emacs parameters -- 
     932// Local variables: 
     933// tab-width: 4 
     934// c-basic-offset: 4 
     935// c-hanging-comment-ender-p: nil 
     936// indent-tabs-mode: nil 
     937// End: 
    790938?> 
  • trunk/trax/vendor/trax/router.php

    r138 r161  
    3030 
    3131/** 
    32  * 
    33  *  @todo Document this class 
    34  *  @package PHPonTrax 
     32 *  Convert a URL to an action 
     33 *  @tutorial PHPonTrax/Router.cls 
    3534 */ 
    3635class Router { 
    3736 
     37    /** 
     38     *  Route table 
     39     * 
     40     *  For a description of the structure, see 
     41     *  {@tutorial PHPonTrax/Router.cls#table the Router tutorial}. 
     42     *  Routes are added by calling {@link connect()} and looked up 
     43     *  by calling {@link find_route()}. 
     44     *  <b>FIXME:</b> Should we have a Route class to describe an 
     45     *  entry in the route table? 
     46     *  @var string[][] 
     47     */ 
    3848    private $routes = array(); 
     49 
     50    /** 
     51     *  Last route found by a call to find_route() 
     52     *  @var string[] 
     53     */ 
    3954    private $selected_route = null; 
     55 
     56    /** 
     57     *  Default route path 
     58     * 
     59     *  This route path is added to the route table if the table is 
     60     *  empty when find_route() is called. 
     61     *  @var string constant 
     62     */ 
    4063    private $default_route_path = ":controller/:action/:id"; 
     64 
     65    /** 
     66     *  Count of the number of elements in $routes 
     67     *  @var integer 
     68     */ 
    4169    public $routes_count = 0; 
    4270 
    4371    /** 
    44      * 
    45      *  @todo Document this method 
     72     *  Accessor method to return contents of $selected_route 
     73     *  @return string[] Contents of $selected_route 
     74     *  @uses $selected_route 
    4675     */ 
    4776    function get_selected_route() { 
     
    5079 
    5180    /** 
     81     *  Accessor method to add a route to the route table 
    5282     * 
    53      *  @todo Document this method 
     83     *  The route is added to the end of 
     84     *  {@link $routes the route table}. If $params is not an array, 
     85     *  NULL is stored in the route parameter area. 
     86     *  @param string $path 
     87     *  @param mixed[] $params 
     88     *  @uses $routes 
     89     *  @uses $routes_count 
    5490     */ 
    5591    function connect($path, $params = null) { 
     
    6197 
    6298    /** 
     99     *  Find first route in route table with path that matches argument 
    63100     * 
    64      *  @todo Document this method 
     101     *  First, assure that the route table {@link $routes} has at 
     102     *  least one route by adding 
     103     *  {@link $default_route_path the default route} if the table is 
     104     *  empty.  Then search the table to find the first route in the 
     105     *  table whose path matches the argument $url. If $url is an 
     106     *  empty string, it matches a path that is an empty string. 
     107     *  Otherwise, try to match $url to the path part of the table 
     108     *  entry according to {@link http://www.php.net/manual/en/ref.pcre.php Perl regular expression} 
     109     *  rules.  Return the first matching route to the caller, and 
     110     *  also save a copy in {@link $selected_route}. 
     111     *  @param string $url 
     112     *  @uses build_route_regexp() 
     113     *  @uses $default_route_path 
     114     *  @uses $routes 
     115     *  @uses $routes_count 
     116     *  @uses $selected_route 
     117     *  @return string[] Selected route. Path is in return['path'], 
     118     *                   params in return['params'], 
    65119     */ 
    66120    function find_route($url) { 
    67  
    68121        // ensure at least one route (the default route) exists 
    69122        if($this->routes_count == 0) { 
    70             $this->routes['path'] = $this->default_route_path; 
    71             $this->routes['params'] = null; 
     123            $this->connect($this->default_route_path); 
    72124        } 
    73125 
     
    78130            unset($reg_exp); 
    79131            $route_regexp = $this->build_route_regexp($route['path']); 
    80  
    81132            if($url == "" && $route_regexp == "") { 
    82133                $this->selected_route = $route; 
     
    92143 
    93144        return $this->selected_route; 
    94     } 
     145    }                                 // function find_route($url) 
    95146 
    96147    /** 
     148     *  Build a regular expression that matches a route 
    97149     * 
    98      *  @todo Document this method 
     150     *  <b>FIXME:</b> Should this method be private? 
     151     *  @param string $route_path  A route path. 
     152     *  @return string Regular expression that matches the route in 
     153     *                $route_path  
    99154     */ 
    100155    function build_route_regexp($route_path) { 
     156        //        echo "entering build_route_regexp(), \$route_path is '$route_path'\n"; 
    101157 
    102158        $route_regexp = null; 
     
    105161            $route_path = explode("/",$route_path); 
    106162        } 
    107  
     163        //        echo "route path:\n"; 
     164        //        var_dump($route_path); 
    108165        if(count($route_path) > 0) { 
    109166            foreach($route_path as $path_element) { 
     
    124181} 
    125182 
     183// -- set Emacs parameters -- 
     184// Local variables: 
     185// tab-width: 4 
     186// c-basic-offset: 4 
     187// c-hanging-comment-ender-p: nil 
     188// indent-tabs-mode: nil 
     189// End: 
    126190?>