package.xml 0000664 0001750 0001750 00000030012 12654066370 011304 0 ustar jan jan
Horde_Routespear.horde.orgRoutesHorde Routes URL mapping systemClasses for mapping URLs into the controllers and actions of an MVC system. It is a port of a Python library, Routes, by Ben Bangert (http://routes.groovie.org).Mike Nabereznymnaberezmike@maintainable.comyesChuck Hagenbuchchuckchuck@horde.orgyes2016-02-022.0.51.1.0stablestableBSD-2-Clause
* [jan] Mark PHP 7 as supported.
5.3.08.0.0alpha18.0.0alpha11.7.0Horde_Exceptionpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Utilpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Testpear.horde.org2.1.03.0.0alpha13.0.0alpha10.4.00.4.0betabeta2009-03-04BSD-2-Clause
* Added ability to pretty-print routes with Horde_Routes_Printer.
1.0.0beta11.0.0betabeta2011-03-16BSD-2-Clause
* First beta release for Horde 4.
1.0.0RC11.0.0betabeta2011-03-22BSD-2-Clause
* First release candidate for Horde 4.
1.0.0RC21.0.0betabeta2011-03-29BSD-2-Clause
* Second release candidate for Horde 4.
1.0.01.0.0stablestable2011-04-06BSD-2-Clause
* First stable release for Horde 4.
1.1.01.1.0stablestable2011-08-30BSD-2-Clause
* [mjr] Added Horde_Routes_Matcher helper class.
1.1.11.1.0stablestable2011-11-08BSD-2-Clause
* [gwr] Only remove the "_controller" suffix if it exists.
1.1.21.1.0stablestable2011-11-22BSD-2-Clause
* [jan] Make Horde_Routes_Utils::controllerScan() Windows compatible.
2.0.0alpha11.1.0alphastable2012-07-05BSD-2-Clause
* First alpha release for Horde 5.
2.0.0beta11.1.0betastable2012-07-19BSD-2-Clause
* First beta release for Horde 5.
2.0.01.1.0stablestable2012-10-30BSD-2-Clause
* First stable release for Horde 5.
2.0.11.1.0stablestable2012-11-19BSD-2-Clause
* [mms] Use new Horde_Test layout.
2.0.21.1.0stablestable2013-01-09BSD-2-Clause
* [jan] Fix generating cache key for generated URLs (remi@famillecollet.com, Bug #11894).
2.0.31.1.0stablestable2015-01-09BSD-2-Clause
* [jan] Add Composer definition.
2.0.41.1.0stablestable2015-04-28BSD-2-Clause
* [jan] Fix issues with certain locales like Turkish.
2.0.51.1.0stablestable2016-02-02BSD-2-Clause
* [jan] Mark PHP 7 as supported.
Horde_Routes-2.0.5/doc/Horde/Routes/COPYING 0000664 0001750 0001750 00000002430 12654066370 016356 0 ustar jan jan Copyright 1999-2016 Horde LLC. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HORDE PROJECT
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Horde_Routes-2.0.5/doc/Horde/Routes/integration.txt 0000664 0001750 0001750 00000010412 12654066370 020406 0 ustar jan jan Horde_Routes Integration Guide
This document is based on the manual for the Python version available at:
http://routes.groovie.org/integration.html
Integrating Horde_Routes
Horde_Routes is built to function with any PHP 5 web framework that utilizes a
MVC style approach to design. However, it can be used completely outside of a
MVC context as well.
For full integration with a web framework, several steps should be done during
different phases of the request cycle. The web framework developer should also
have a way to add routes to the mapper, and accessing utility functions.
Terminology:
Framework Integrator
Typically the person who is working to integrate routes into a web framework
Web/Framework Developer
The web application developer using the web framework
Route Setup
Horde_Routes requires PHP 5.1 or above. It does not require() its own files, so
an autoloader must be registered that will load the Horde_Routes files from its
PEAR directory. Alternatively, the files can be loaded explicitly:
require_once 'Horde/Routes/Mapper.php';
require_once 'Horde/Routes/Exception.php';
require_once 'Horde/Routes/Route.php';
require_once 'Horde/Routes/Utils.php';
The web framework developer will need a place to add routes that will be used
during the URL resolution phase. Commonly, the mapper object will be directly
exposed in a configuration file:
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:id');
The developer can then add additional routes as they see fit. The Framework
Integrator should make sure that their code takes care of using the Mapper
instance and preserving it somewhere for use by the framework.
Pre-Loading the Controllers
Due to the way Horde_Routes makes use of regular expressions for URL
recognition, Horde_Routes_Mapper requires a valid list of Controllers before
it can match URLs. Controller names can contain any character including /.
Once the controller list is created, the Mapper method createRegs() should be
called:
$m->createRegs(array('content', 'admin/comments', 'blog'))
After this step, the Mapper object is now ready to match URLs.
Instead of calling Horde_Routes_Mapper->createRegs() directly, a PHP callback
can also be passed to the Horde_Routes_Mapper constructor. See the inline
source documentation.
URL Resolution
When the URL is looked up, it should be matched against the Mapper. When
matching an incoming URL, it is assumed that the URL path is the only string
being matched. All query args should be stripped before matching:
$m->connect('articles/:year/:month',
array('controller'=>'blog', 'action'=>'view', 'year'=>null));
$m->match('/articles/2003/10');
// Returns:
// array('controller'=>'blog', 'action'=>'view',
'year'=>'2003', 'month'=>'10')
Matching a URL will return an associative array of the match results. If
you'd like to differentiate between where the argument came from you can use
routematch() which will return the Route object that has all these details:
$m->connect('articles/:year/:month',
array('controller'=>'blog', 'action'=>'view', 'year'=>null));
$result = $m->routematch('/articles/2003/10');
// result is array(matchdata, Horde_Routes_Route)
// result[0] - array('controller'=>'blog', 'action'=>'view',
// 'year'=>'2003', 'month'=>'10')
//
// result[1] - Horde_Routes_Route instance
// result[1]->defaults - array('controller'=>'blog', 'action'=>'view',
// 'year'=>null);
// result[1]->hardcoded - array('controller', 'action')
Your integration code is then expected to dispatch to a controller and action
in the associative array. How it does this is entirely up to the framework
integrator. Your integration should also typically provide the web developer a
mechanism to access the additional associative array values.
Providing Utilities
In addition to allowing the web developer to define routes on the Mapper instance,
access to a Horde_Routes_Utils instance should be provided:
$utils = $m->utils;
The $utils instance provides the web developer with the utility functions urlFor() and
redirectTo(), which will be used to generate URLs from the route mapping.
$url = $utils->urlFor(array('controller' => 'articles', 'action' => 'view',
'id' => $article->id));
Horde_Routes-2.0.5/doc/Horde/Routes/manual.txt 0000664 0001750 0001750 00000065407 12654066370 017356 0 ustar jan jan Horde_Routes Manual
This document is based on the manual for the Python version available at:
http://routes.groovie.org/manual.html
1 Introduction
Horde_Routes tackles an interesting problem that comes up frequently in web
development, how do you map a URL to your code? While there are many solutions
to this problem, that range from using the URL paths as an object publishing
hierarchy, to regular expression matching; Horde_Routes goes a slightly different
way.
Using Horde_Routes, you specify parts of the URL path and how to match them to your
Controllers and Actions. The specific web framework you're using may actually
call them by slightly different names, but for the sake of consistency we will
use these names.
Horde_Routes lets you have multiple ways to get to the same Controller and Action,
and uses an intelligent lookup mechanism to try and guarantee you the URL with
the least cruft when generating the URL.
URL Cruft
Shorthand reference to what will occur if a Route can't handle all the
arguments we want to send it. Those arguments become HTTP query args
(/something ?query=arg&another=arg ), which we try to avoid when
generating a URL.
2 Setting Up Routes
To setup Horde_Routes, it is assumed that you are using a web framework that has the
Horde_Routes mechanism integrated for you. The web framework should have somewhere
setup for you to add a Route to your Mapper.
Route (Horde_Routes_Route)
A Route is a mapping of a URL to a controller, action, and/or additional
variables. Matching a Route will always result in a controller and action.
Route objects are typically created and managed by the Mapper.
Mapper (Horde_Routes_Mapper)
The Mapper is the main class used to hold, organize, and match Routes.
While you can create a Route object independently of the Mapper, its not
nearly as useful. The Mapper is what you will use to add Routes and what
the web framework uses to match incoming URLs.
We will also assume for this introduction that your Mapper instance is exposed
to you as $m, for example:
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:id');
The above example covers one of the most common routes that is typically
considered the default route. This very flexible route allows virtually all of
your controllers and actions to be called. Adding more routes is done in a
similar manner, by calling $m->connect(...) and giving the Mapper instance a set
of arguments.
The following are all valid examples of adding routes:
$m->connect('archives/:year/:month/:day',
array('controller'=>'archives', 'action'=>'view', 'year'=>2004,
'requirements'=> array('year'=>'\d{2,4}', 'month'=>'\d{1,2}')));
$m->connect('feeds/:category/atom.xml',
array('controller'=>'feeds', 'action'=>'atom'));
$m->connect('history', 'archives/by_eon/:century',
array('controller'=>'archives', 'action'=>'aggregate', 'century'=>1800));
$m->connect('article', 'article/:section/:slug/:page.html',
array('controller'=>'article', 'action'=>'view'));
$m->connect(':controller/:action/:id');
$m->connect('home', '',
array('controller'=>'blog', 'action'=>'index'));
In the following sections, we'll highlight the section of the Route we're
referring to in the first example.
2.1 Route Name
Optional
$m->connect('history', 'archives/by_eon/:century',
array('controller'=>'archives...
A Route can have a name, this is also referred to as Named Routes and lets you
quickly reference the Defaults that the route was configured with. This is the
first non-keyword argument, and if not present the first non-keyword argument
is assumed to be the route path.
Route Names are mainly used when generating routes, and have no other effect
on matching a URL.
2.1.1 Static Named Routes
Horde_Routes also supports static named routes. These are routes that do not
involve actual URL generation, but instead allow you to quickly alias common
URLs. For example:
$m->connect('google_search', 'http://www.google.com/search',
array('_static'=>True));
Static Named Routes are ignored entirely when matching a URL.
2.1.2 Filter Functions
Named routes can have functions associated with them that will operate on the
arguments used during generation. If you have a route that requires multiple
arguments to generate, like:
$m->connect('archives/:year/:month/:day', array('controller'=>'archives',
'action'=>'view', 'year'=>2004,
'requirements'=>array('year'=>'\d{2,4}', 'month'=>'\d{1,2}')));
To generate a URL for this will require a month and day argument, and a year
argument if you don't want to use 2004. When using Routes with a database or
other objects that might have all this information, it's useful to let Routes
expand that information so you don't have to.
Consider the case where you have a story object which has a year, month, and
day attribute. You could generate the URL with:
$utils = $m->utils;
$utils->urlFor(array('year' => $story->year,
'month' => $story->month,
'day' => $story->day));
This isn't terribly convenient, and can be brittle if for some reason you need
to change the story object's interface. Here's an example of setting up a
filter function:
function story_expand($kargs) {
// only alter $kargs if a story keyword arg is present
if (! in_array('story', $kargs)) {
return $kargs;
}
$story = $kargs['story'];
unset ($kargs['story']);
$kargs['year'] = $story->year;
$kargs['month'] = $story->month;
$kargs['day'] = $story->day;
return $kargs;
}
$m->connect('archives', 'archives/:year/:month/:day',
array('controller' => 'archives', 'action' => 'view', 'year' => 2004,
'requirements' => array('year'=>'\d{2,4}', 'month'=>'\d{1,2}'),
'filter'=> 'story_expand'));
This filter function will be used when using the named route archives. If a
story keyword argument is present, it will use that and alter the keyword
arguments used to generate the actual route.
If you have a story object with those attributes, making the route would now
be done with the following arguments:
$utils = $m->utils;
$utils->urlFor('archives', array('story' => $myStory));
If the story interface changes, you can change how the arguments are pulled
out in a single location. This also makes it substantially easier to generate
the URL.
*Warning* Using the filter function requires the route to be a named route.
This is due to how the filter function can affect the route that
actually gets chosen. The only way to reliably ensure the proper
filter function gets used is by naming the route, and using its
route name with Horde_Routes_Utils->urlFor().
2.2 Route Path
Required
$m->connect('feeds/:category/atom.xml',
array('controller'=>'feeds', 'action'=>'atom'));
The Route Path determines the URL mapping for the Route. In the above example
a URL like /feeds/electronics/atom.xml will match this route.
A Route Path is separated into parts that you define, the naming used when
referencing the different types of route parts are:
Static Part
$m->connect('feeds/:category/atom.xml',
array('controller'=>'feeds', 'action'=>'atom'));
A plain-text part of the URL, this doesn't result in any Route variables.
Dynamic Part
$m->connect('feeds/:category/atom.xml',
array('controller'=>'feeds', 'action'=>'atom'))
A dynamic part matches text in that part of the URL, and assigns what it
finds to the name after the : mark.
Wildcard Part
$m->connect('file/*url',
array('controller'=>'file', 'action'=>'serve'));
A wildcard part will match everything except the other parts around it.
Groupings
$m->connect('article', 'article/:section/:slug/:(page).html', ...
$m->connect('file/*(url).html',
array('controller'=>'file', 'action'=>'serve'));
Groupings let you define boundaries for the match with the () characters.
This allows you to match wildcards and dynamics next to other static and
dynamic parts. Care should be taken when using Groupings next to each
other.
2.3 Defaults
Optional
$m->connect('history', 'archives/by_eon/:century',
array('controller'=>'archives', 'action'=>'aggregate', 'century'=>1800));
The keyword options in a route (not including the requirements keyword arg)
that can determine the default for a route. If a default is specified for a
variable that is not a dynamic part, then its not only a default but is also a
hardcoded variable. The controller and action are hardcoded variables in the
example above because despite the URL, they will always be 'archives' and
'aggregate' respectively.
Hardcoded Variable
Default keyword that does not exist in the route path. This keyword
variable cannot be changed by the URL coming in.
2.4 Requirements
Optional
$m->connect('archives/:year/:month/:day',
array('controller'=>'archives', 'action'=>'view', 'year'=>2004,
'requirements' => array('year'=>'\d{2,4}', 'month'=>'\d{1,2}')));
Requirements is a special keyword used by Routes to enforce a regular
expression restriction on the dynamic part or wildcard part of a route path.
Note in the example above that the regular expressions do not have boundaries
such as they would with a PHP function like preg_match(). The expression is
simply "\d{2,4}" and not "/\d{2,4}/".
2.5 Conditions
Optional
$m->connect('user/new;preview',
array('controller' => 'user', 'action' => 'preview',
'conditions' => array('method' => array('POST'))));
Conditions specifies a set of special conditions that must be met for the
route to be accepted as a valid match for the URL. The conditions argument
must always be a dictionary and can accept 3 different keys.
method
Request must be one of the HTTP methods defined here. This argument must
be a list of HTTP methods, and should be upper-case.
subDomain
Can either be True or an array of sub-domains, one of which must be
present.
function
A function that will be used to evaluate if the Route is a match. Must
return True or False, and will be called with the environ and match_dict.
The match_dict is a dict with all the Route variables for the request.
Modifications to match_dict will appear identical to Route variables from
the original match.
Examples:
// The method to be either GET or HEAD
m->connect('user/list',
array('controller' => 'user', 'action' => 'list',
'conditions' => array('method' => array('GET', 'HEAD'))));
// A sub-domain should be present
$m->connect('',
array('controller' => 'user', 'action' => 'home',
'conditions' => array('subDomain' => true)));
// Sub-domain should be either 'fred' or 'george'
$m->connect('',
array('controller' => 'user', 'action' => 'home',
'conditions' => array('subDomain' => array('fred', 'george')));
/**
* Put the referrer into the resulting match dictionary,
* this won't stop the match since it always returns True
*/
function referals($environ, $result) {
$referer = isset($environ['HTTP_REFERER']) ? $environ['HTTP_REFERER'] : null;
$result['referer'] = $referer;
return true;
}
$m->connect(':controller/:action/:id',
array('conditions' => array('function'=>'referals')));
3 The Nitty Gritty of Route Setup
3.1 Minimum URLs
Routes will use your defaults to try and minimize the required length of your
URL whenever possible. For example:
$m->connect(':controller/:action/:id',
array('action'=>'view', 'id'=>4));
# Will match all of the following
# /content/view/4
# /content/view
# /content
Trailing dynamic parts of a route path that have defaults setup are not
required to exist in the URL being matched. This means that each of the URL
examples shown above will result in the same set of keyword arguments being
sent to the same controller and action.
If a dynamic part with a default is followed by either static parts or dynamic
parts without defaults, that dynamic part will be required despite having a
default:
// Remember that :action has an implicit default
$m->connect('archives/:action/:article',
array('controller'=>'blog'));
# Matches:
# /archives/view/introduction
# /archives/edit/recipes
# Does Not Match:
# /archives/introduction
# /archives/recipes
This way, the URL coming in maps up to the route path you created, part for part.
When using Groupings, parts will still be left off, but only if the remainder
of the URL has no static after it. This can lead to some odd looking URLs
being generated if you aren't careful about your requirements and defaults.
For example:
# Groupings without requirements
$m->connect(':controller/:(action)-:(id)')
# Matches:
# /archives/view-3
# /archives/view-
# Generation:
$utils = $m->utils;
$utils->urlFor(array('controller'=>'archives', 'action'=>'view');
# /archives/view-
It's unlikely you want such a URL, and would prefer to ensure that there's
always an id supplied. To enforce this behavior we will use Requirements:
# Groupings without requirements
$m->connect(':controller/:(action)-:(id)',
array('requirements'=> array('id'=>'\d+')));
# Matches:
# /archives/view-3
# /archives/view-2
# Does Not Match:
# /archives/view-
# Generation:
$utils = $m->utils;
$utils->urlFor(array('controller'=>'archives', 'action'=>'view', 'id'=>2));
# /archives/view-2
If you end up with URLs missing parts you'd like left on when using Groupings,
add a requirement to that part.
3.2 Implicit Defaults
The above rule regarding minimum URLs has two built-in implicit defaults. If
you use either action or id in your route path and don't specify defaults for
them, Routes will automatically assign the following defaults to them for you:
array('action' => 'index', 'id' => null)
This is why using the following setup doesn't require an action or id in the URL:
$m->connect(':controller/:action/:id');
# '/blog' -> controller='blog', action='index', id=None
3.3 Search Order
When setting up your routes, remember that when using routes the order in
which you set them up can affect the URL that's generated. Routes will try and
use all the keyword args during route generation and if multiple routes can be
generated given the set of keyword args, the first and shortest route that was
connected to the mapper will be used. Hardcoded variables are also used first
if available as they typically result in shorter URLs.
For example:
# Route Setup
$m->connect('archives/:year',
array('controller'=>'blog', 'action'=>'view', 'year'=null));
$m->connect(':controller/:action/:id');
# Route Usage
$utils = $m->utils;
$utils->urlFor(array('controller'=>'blog', 'action'=>'view'));
# -> '/archives'
You will typically want your specific and detailed routes at the top of your
Route setup and the more generic routes at the bottom.
3.4 Wildcard Limitations and Gotchas
Due to the nature of wildcard parts, using wildcards in your route path can
result in URL matches that you didn't expect. Wildcard parts are extremely
powerful and when combined with dynamic parts that have defaults can confuse
the new Routes user.
When you have dynamic parts with defaults, you should never place them
directly next to a wildcard part. This can result in the wildcard part eating
the part in the URL that was intended as the dynamic part.
For example:
$m->connect('*url/:username',
array('controller'=>'blog', 'action'=>'view', 'username'=>'george'));
# When matching url variable username variable
# /some/long/url/george /some/long/url/george george
# /some/other/stuff/fred /some/other/stuff/fred george
This occurs because Routes sees the default as being optional, and the
wildcard part attempts to gobble as much of the URL as possible before a
required section of the route path is found. By having a trailing dynamic part
with a default, that section gets dropped.
Notice how removing the dynamic part default results in the variables we expect:
$m->connect('*url/:username',
array('controller'=>'blog', 'action'=>'view'));
# When matching url variable username variable
# /some/long/url/george /some/long/url george
# /some/other/stuff/fred /some/other/stuff fred
Let's try one more time, but put in a static part between the dynamic part
with a default and the wildcard:
$m->connect('*url/user/:username',
array('controller'=>'blog', 'action'=>'view', 'username'=>'george'));
# When matching url variable username variable
# /some/long/url/user/george /some/long/url george
# /some/other/stuff/user/fred /some/other/stuff fred
3.5 Unicode
Not currently supported in the PHP version.
4 Using Routes
Once you have setup the Routes to map URLs to your controllers and actions,
you will likely want to generate URLs from within your web application.
Horde_Routes_Utils includes two functions for use in your web application that
are commonly desired.
* redirectTo()
* urlFor()
Both of these functions take a similar set of arguments. The most important
being an associative array of keyword arguments that describes the controller,
action, and additional variables you'd like present for the URL that's created.
To save you from repeating things, Routes has two mechanisms to reduce the
amount of information you need to supply the urlFor() or redirectTo() function.
4.1 Named Routes
We saw earlier how the route name ties a set of defaults to a name. We can use
this name with our Route functions and its as if we used that set of keyword
args:
$m->connect('category_home', 'category/:section',
array('controller'=>'blog', 'action'=>'view', 'section'=>'home'));
$utils = $m->utils;
$utils->urlFor('category_home');
// is equivalent to
$utils->urlFor(array('controller'=>'blog', 'action'=>'view', 'section'=>'home'));
You can also specify keyword arguments and it will override defaults
associated with the route name:
$utils->urlFor('category_home', array('action'=>'index'));
// is equivalent to
$utils->urlFor(array('controller'=>'blog', 'action'=>'index', 'section'=>'home'));
As you can see, the amount of typing you save yourself by using the route name
feature is quite handy.
Using the recently introduced static named routes feature allows you to
quickly use common URLs and easily add query arguments:
$m->connect('google_search', 'http://www.google.com/search',
array('_static' => true));
$utils = $m->utils;
$utils->urlFor('google_search', array('q'=>'routes'));
// will result in
// http://www.google.com/search?q=routes
4.1.1 Non-Existent Route Names
If you supply a route name that does not exist, urlFor() will assume that you
intend to use the name as the actual URL. It will also prepend it with the
proper SCRIPT_NAME if applicable:
$utils->urlFor('/css/source.css');
# if running underneath a 'mount' point of /myapp will become
# /myapp/css/source.css
For portable web applications, it's highly encouraged that you use urlFor() for
all your URLs, even those that are static resources and images. This will
ensure that the URLs are properly handled in various deployment cases.
4.2 Route Memory
When your controller and action is matched up from the URL, the variables it
set to get there are preserved. This lets you update small bits of the
keywords that got you there without specifying the entire thing:
$m->connect('archives/:year/:month/:day',
array('controller'=>'archives', 'action'=>'view', 'year'=>2004,
'requirements'=>array('year'=>'\d{2,4}', 'month'=>'\d{1,2}')));
# URL used: /archives/2005/10/4
# Route dict: {'controller': 'archives', 'action': 'view', 'year': '2005',
# 'month': '10', 'day': '4'}
$utils->urlFor(array('day'=>6)) # => /archives/2005/10/6
$utils->urlFor(array('month'=>4)) # => /archives/2005/4/4
$utils->urlFor() # => /archives/2005/10/4
$utils->urlFor(array('controller'=>'/archives')) # => /archives
The route memory is always used for values with the following conditions:
* If the controller name begins with a /, no values from the Route dict are used
* If the controller name changes and no action is specified, action will be set to 'index'
* If you use named routes, no values from the Route dict are used
4.3 Overriding Route Memory
Sometimes one doesn't want to have Route Memory present, as well as removing
the Implicit Defaults. Routes can disable route memory and implicit defaults
either globally, or on a per-route basis. Setting explicit routes:
$m = new Horde_Routes_Mapper(array('explicit'=>true));
When toggling explicit behavior for individual routes, only the implicit route
defaults will be de-activated. urlFor() behavior can only be set globally with
the mapper explicit keyword. Setting explicit behavior for a route:
$m = new Horde_Routes_Mapper();
# Note no 'id' value will be assumed for a default
$m->connect('archives/:year',
array('controller'=>'archives', 'action'=>'view', '_explicit'=>true));
# This will now require an action and id present
$m->connect(':controller/:action/:id',
array('_explicit'=>true));
5 Sub-domain Support
Routes comes with sub-domain support to make it easy to handle sub-domains in
an integrated fashion. When sub-domain support is turned on, Routes will
always have a subDomain argument present with the sub-domain if present, or
None.
To avoid matching common aliases to your main domain like www, the sub-domain
support can be set to ignore some sub-domains.
Example:
$m = new Horde_Routes_Mapper();
// Turn on sub-domain support
$m->subDomains = true;
// Ignore the www sub-domain
$m->subDomainsIgnore = array('www');
5.1 Generating URLs with sub-domains
When sub-domain support is on, the urlFor() function will accept a subDomain
keyword argument. Routes will then ensure that the generated URL has the
sub-domain indicated. This feature works with Route memory to ensure that the
sub-domain is only added when necessary.
Some examples:
// Assuming that the current URL from the request is http://george.example.com/users/edit
// Also assuming that you're using the map options above with the default routing of
// ':controller/:action/:id'
$utils->urlFor(array('action'=>'update', 'subDomain'=>'fred'));
# -> http://fred.example.com/users/update
$utils->urlFor(array('controller'=>'/content', 'action'=>'view', 'subDomain'=>'www'));
# will become -> http://example.com/content/view
$utils->urlFor(array('action'=>'new', 'subDomain'=>null));
# -> http://example.com/users/new
6 RESTful Services
To make it easier to setup RESTful web services with Routes, there's a
shortcut Mapper method that will setup a batch of routes for you along with
conditions that will restrict them to specific HTTP methods. This is directly
styled on the Rails version of $map->resource(), which was based heavily on the
Atom Publishing Protocol.
The Horde_Routes_Mapper->resource() command creates a set of Routes for common
operations on a collection of resources, individually referred to as
'members'. Consider the common case where you have a system that deals with
users. In that case operations dealing with the entire group of users (or
perhaps a subset) would be considered collection methods. Operations (or
actions) that act on an individual member of that collection are considered
member methods. These terms are important to remember as the options to
$map->resource() rely on a clear understanding of collection actions vs.
member actions.
The default mapping that $map->resource() sets up looks like this:
$map->resource('message', 'messages')
// Will setup all the routes as if you had typed the following map commands:
$map->connect('messages',
array('controller'=>'messages', 'action'=>'create',
'conditions'=>array('method'=>array('POST'))));
$map->connect('messages', 'messages',
array('controller'=>'messages', 'action'=>'index',
'conditions'=>array('method'=>array('GET'))));
$map->connect('formatted_messages', 'messages.:(format)',
array('controller'=>'messages', action=>'index',
'conditions'=>array('method'=>array('GET'))));
$map->connect('new_message', 'messages/new',
array('controller'=>'messages', 'action'=>'new',
'conditions'=>array('method'=>array('GET'))));
$map->connect('formatted_new_message', 'messages/new.:(format)',
array('controller'=>'messages', 'action'=>'new',
'conditions'=>array('method'=>array('GET'))));
$map->connect('messages/:id',
array('controller'=>'messages', 'action'=>'update',
'conditions'=>array('method'=>array('PUT'))));
$map->connect('messages/:id',
array('controller'=>'messages', 'action'=>'delete',
'conditions'=>array('method'=>array('DELETE'))));
$map->connect('edit_message', 'messages/:(id);edit',
array('controller'=>'messages', 'action'=>'edit',
'conditions'=>array('method'=>array('GET'))));
$map->connect('formatted_edit_message', 'messages/:(id).:(format);edit',
array('controller'=>'messages', 'action'=>'edit',
'conditions'=>array('method'=>array('GET'))));
$map->connect('message', 'messages/:id',
array('controller'=>'messages', 'action'=>'show',
'conditions'=>array('method'=>array('GET'))));
$map->connect('formatted_message', 'messages/:(id).:(format)',
array('controller'=>'messages', 'action'=>'show',
'conditions'=>array('method'=>array('GET'))));
The most important aspects of this is the following mapping that is established:
GET /messages -> messages.index() -> $utils->urlFor('messages')
POST /messages -> messages.create() -> $utils->urlFor('messages')
GET /messages/new -> messages.new() -> $utils->urlFor('new_message')
PUT /messages/1 -> messages.update(id) -> $utils->urlFor('message', array('id'=>1))
DELETE /messages/1 -> messages.delete(id) -> $utils->urlFor('message', array('id'=>1))
GET /messages/1 -> messages.show(id) -> $utils->urlFor('message', array('id'=>1))
GET /messages/1;edit -> messages.edit(id) -> $utils->urlFor('edit_message', array('id'=>1))
*Note* Several of these methods map to functions intended to display forms. The new
message method should be used to return a form allowing someone to create a
new message, while it should POST to /messages. The edit message function
should work similarly returning a form to edit a message, which then performs a
PUT to the /messages/1 resource.
Additional methods that respond to either a new member, or different ways of
viewing collections can be added via keyword arguments to $map->resource() as
shown in the complete list with examples of the $map->resource() options.
Horde_Routes-2.0.5/lib/Horde/Routes/Exception.php 0000664 0001750 0001750 00000001206 12654066370 017773 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* Exception class for the Horde_Routes package. All exceptions thrown
* from the package will be of this type.
*
* @package Routes
*/
class Horde_Routes_Exception extends Horde_Exception_Wrapped
{
}
Horde_Routes-2.0.5/lib/Horde/Routes/Mapper.php 0000664 0001750 0001750 00000121312 12654066370 017262 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* The mapper class handles URL generation and recognition for web applications
*
* The mapper class is built by handling associated arrays of information and passing
* associated arrays back to the application for it to handle and dispatch the
* appropriate scripts.
*
* @package Routes
*/
class Horde_Routes_Mapper
{
/**
* Filtered request environment with keys like SCRIPT_NAME
* @var array
*/
public $environ = array();
/**
* Callback function used to get array of controller names
* @var callback
*/
public $controllerScan;
/**
* Path to controller directory passed to controllerScan function
* @var string
*/
public $directory;
/**
* Call controllerScan callback before every route match?
* @var boolean
*/
public $alwaysScan;
/**
* Disable route memory and implicit defaults?
* @var boolean
*/
public $explicit;
/**
* Collect debug information during route match?
* @var boolean
*/
public $debug = false;
/**
* Use sub-domain support?
* @var boolean
*/
public $subDomains = false;
/**
* Array of sub-domains to ignore if using sub-domain support
* @var array
*/
public $subDomainsIgnore = array();
/**
* Append trailing slash ('/') to generated routes?
* @var boolean
*/
public $appendSlash = false;
/**
* Prefix to strip during matching and to append during generation
* @var null|string
*/
public $prefix = null;
/**
* Array of connected routes
* @var array
*/
public $matchList = array();
/**
* Array of connected named routes, indexed by name
* @var array
*/
public $routeNames = array();
/**
* Cache of URLs used in generate()
* @var array
*/
public $urlCache = array();
/**
* Encoding of routes URLs (not yet supported)
* @var string
*/
public $encoding = 'utf-8';
/**
* What to do on decoding errors? 'ignore' or 'replace'
* @var string
*/
public $decodeErrors = 'ignore';
/**
* Partial regexp used to match domain part of the end of URLs to match
* @var string
*/
public $domainMatch = '[^\.\/]+?\.[^\.\/]+';
/**
* Array of all connected routes, indexed by the serialized array of all
* keys that each route could utilize.
* @var array
*/
public $maxKeys = array();
/**
* Array of all connected routes, indexed by the serialized array of the
* minimum keys that each route needs.
* @var array
*/
public $minKeys = array();
/**
* Utility functions like urlFor() and redirectTo() for this Mapper
* @var Horde_Routes_Utils
*/
public $utils;
/**
* Cache
* @var Horde_Cache
*/
public $cache;
/**
* Cache lifetime for the same value of $this->matchList
* @var integer
*/
public $cacheLifetime = 86400;
/**
* Have regular expressions been created for all connected routes?
* @var boolean
*/
protected $_createdRegs = false;
/**
* Have generation hashes been created for all connected routes?
* @var boolean
*/
protected $_createdGens = false;
/**
* Generation hashes created for all connected routes
* @var array
*/
protected $_gendict;
/**
* Temporary variable used to pass array of keys into _keysort() callback
* @var array
*/
protected $_keysortTmp;
/**
* Regular expression generated to match after the prefix
* @var string
*/
protected $_regPrefix = null;
/**
* Constructor.
*
* Keyword arguments ($kargs):
* ``controllerScan`` (callback)
* Function to return an array of valid controllers
*
* ``redirect`` (callback)
* Function to perform a redirect for Horde_Routes_Utils->redirectTo()
*
* ``directory`` (string)
* Path to the directory that will be passed to the
* controllerScan callback
*
* ``alwaysScan`` (boolean)
* Should the controllerScan callback be called
* before every URL match?
*
* ``explicit`` (boolean)
* Should routes be connected with the implicit defaults of
* array('controller'=>'content', 'action'=>'index', 'id'=>null)?
* When set to True, these will not be added to route connections.
*/
public function __construct($kargs = array())
{
$callback = array('Horde_Routes_Utils', 'controllerScan');
$defaultKargs = array('controllerScan' => $callback,
'directory' => null,
'alwaysScan' => false,
'explicit' => false);
$kargs = array_merge($defaultKargs, $kargs);
// Most default assignments that were in the construct in the Python
// version have been moved to outside the constructor unless they were variable
$this->directory = $kargs['directory'];
$this->alwaysScan = $kargs['alwaysScan'];
$this->controllerScan = $kargs['controllerScan'];
$this->explicit = $kargs['explicit'];
$this->utils = new Horde_Routes_Utils($this);
}
/**
* Create and connect a new Route to the Mapper.
*
* Usage:
* $m = new Horde_Routes_Mapper();
* $m->connect(':controller/:action/:id');
* $m->connect('date/:year/:month/:day', array('controller' => "blog", 'action' => 'view');
* $m->connect('archives/:page', array('controller' => 'blog', 'action' => 'by_page',
* ' requirements' => array('page' => '\d{1,2}')));
* $m->connect('category_list',
* 'archives/category/:section', array('controller' => 'blog', 'action' => 'category',
* 'section' => 'home', 'type' => 'list'));
* $m->connect('home',
* '',
* array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
*
* @param mixed $first First argument in vargs, see usage above.
* @param mixed $second Second argument in varags
* @param mixed $third Third argument in varargs
* @return void
*/
public function connect($first, $second = null, $third = null)
{
if ($third !== null) {
// 3 args given
// connect('route_name', ':/controller/:action/:id', array('kargs'=>'here'))
$routeName = $first;
$routePath = $second;
$kargs = $third;
} else if ($second !== null) {
// 2 args given
if (is_array($second)) {
// connect(':/controller/:action/:id', array('kargs'=>'here'))
$routeName = null;
$routePath = $first;
$kargs = $second;
} else {
// connect('route_name', ':/controller/:action/:id')
$routeName = $first;
$routePath = $second;
$kargs = array();
}
} else {
// 1 arg given
// connect('/:controller/:action/:id')
$routeName = null;
$routePath = $first;
$kargs = array();
}
if (!in_array('_explicit', $kargs)) {
$kargs['_explicit'] = $this->explicit;
}
$route = new Horde_Routes_Route($routePath, $kargs);
if ($this->encoding != 'utf-8' || $this->decodeErrors != 'ignore') {
$route->encoding = $this->encoding;
$route->decodeErrors = $this->decodeErrors;
}
$this->matchList[] = $route;
if (isset($routeName)) {
$this->routeNames[$routeName] = $route;
}
if ($route->static) {
return;
}
$exists = false;
foreach ($this->maxKeys as $key => $value) {
if (unserialize($key) == $route->maxKeys) {
$this->maxKeys[$key][] = $route;
$exists = true;
break;
}
}
if (!$exists) {
$this->maxKeys[serialize($route->maxKeys)] = array($route);
}
$this->_createdGens = false;
}
/**
* Set an optional Horde_Cache object for the created rules.
*
* @param Horde_Cache $cache Cache object
*/
public function setCache(Horde_Cache $cache)
{
$this->cache = $cache;
}
/**
* Create the generation hashes (arrays) for route lookups
*
* @return void
*/
protected function _createGens()
{
// Checked for a cached generator dictionary for $this->matchList
if ($this->cache) {
$cacheKey = 'horde.routes.' . sha1(serialize($this->matchList));
$cachedDict = $cache->get($cacheKey, $this->cacheLifetime);
if ($gendict = @unserialize($cachedDict)) {
$this->_gendict = $gendict;
$this->_createdGens = true;
return;
}
}
// Use keys temporarily to assemble the list to avoid excessive
// list iteration testing with foreach. We include the '*' in the
// case that a generate contains a controller/action that has no
// hardcodes.
$actionList = $controllerList = array('*' => true);
// Assemble all the hardcoded/defaulted actions/controllers used
foreach ($this->matchList as $route) {
if ($route->static) {
continue;
}
if (isset($route->defaults['controller'])) {
$controllerList[$route->defaults['controller']] = true;
}
if (isset($route->defaults['action'])) {
$actionList[$route->defaults['action']] = true;
}
}
$actionList = array_keys($actionList);
$controllerList = array_keys($controllerList);
// Go through our list again, assemble the controllers/actions we'll
// add each route to. If its hardcoded, we only add it to that dict key.
// Otherwise we add it to every hardcode since it can be changed.
$gendict = array(); // Our generated two-deep hash
foreach ($this->matchList as $route) {
if ($route->static) {
continue;
}
$clist = $controllerList;
$alist = $actionList;
if (in_array('controller', $route->hardCoded)) {
$clist = array($route->defaults['controller']);
}
if (in_array('action', $route->hardCoded)) {
$alist = array($route->defaults['action']);
}
foreach ($clist as $controller) {
foreach ($alist as $action) {
if (in_array($controller, array_keys($gendict))) {
$actiondict = &$gendict[$controller];
} else {
$gendict[$controller] = array();
$actiondict = &$gendict[$controller];
}
if (in_array($action, array_keys($actiondict))) {
$tmp = $actiondict[$action];
} else {
$tmp = array(array(), array());
}
$tmp[0][] = $route;
$actiondict[$action] = $tmp;
}
}
}
if (!isset($gendict['*'])) {
$gendict['*'] = array();
}
// Write to the cache
if ($this->cache) {
$this->cache->set($cacheKey, serialize($gendict), $this->cacheLifetime);
}
$this->_gendict = $gendict;
$this->_createdGens = true;
}
/**
* Creates the regexes for all connected routes
*
* @param array $clist controller list, controller_scan will be used otherwise
* @return void
*/
public function createRegs($clist = null)
{
if ($clist === null) {
if ($this->directory === null) {
$clist = call_user_func($this->controllerScan);
} else {
$clist = call_user_func($this->controllerScan, $this->directory);
}
}
foreach ($this->maxKeys as $key => $val) {
foreach ($val as $route) {
$route->makeRegexp($clist);
}
}
// Create our regexp to strip the prefix
if (!empty($this->prefix)) {
$this->_regPrefix = $this->prefix . '(.*)';
}
$this->_createdRegs = true;
}
/**
* Internal Route matcher
*
* Matches a URL against a route, and returns a tuple (array) of the
* match dict (array) and the route object if a match is successful,
* otherwise it returns null.
*
* @param string $url URL to match
* @return null|array Match data if matched, otherwise null
*/
protected function _match($url)
{
if (!$this->_createdRegs && !empty($this->controllerScan)) {
$this->createRegs();
} elseif (!$this->_createdRegs) {
$msg = 'You must generate the regular expressions before matching.';
throw new Horde_Routes_Exception($msg);
}
if ($this->alwaysScan) {
$this->createRegs();
}
$matchLog = array();
if (!empty($this->prefix)) {
if (preg_match('@' . $this->_regPrefix . '@', $url)) {
$url = preg_replace('@' . $this->_regPrefix . '@', '$1', $url);
if (empty($url)) {
$url = '/';
}
} else {
return array(null, null, $matchLog);
}
}
foreach ($this->matchList as $route) {
if ($route->static) {
if ($this->debug) {
$matchLog[] = array('route' => $route, 'static' => true);
}
continue;
}
$match = $route->match($url, array('environ' => $this->environ,
'subDomains' => $this->subDomains,
'subDomainsIgnore' => $this->subDomainsIgnore,
'domainMatch' => $this->domainMatch));
if ($this->debug) {
$matchLog[] = array('route' => $route, 'regexp' => (bool)$match);
}
if ($match) {
return array($match, $route, $matchLog);
}
}
return array(null, null, $matchLog);
}
/**
* Match a URL against one of the routes contained.
* It will return null if no valid match is found.
*
* Usage:
* $resultdict = $m->match('/joe/sixpack');
*
* @param string $url URL to match
* @param array|null Array if matched, otherwise null
*/
public function match($url)
{
if (!strlen($url)) {
$msg = 'No URL provided, the minimum URL necessary to match is "/"';
throw new Horde_Routes_Exception($msg);
}
$result = $this->_match($url);
if ($this->debug) {
return array($result[0], $result[1], $result[2]);
}
return ($result[0]) ? $result[0] : null;
}
/**
* Match a URL against one of the routes contained.
* It will return null if no valid match is found, otherwise
* a result dict (array) and a route object is returned.
*
* Usage:
* list($resultdict, $resultobj) = $m->match('/joe/sixpack');
*
* @param string $url URL to match
* @param array|null Array if matched, otherwise null
*/
public function routematch($url)
{
$result = $this->_match($url);
if ($this->debug) {
return array($result[0], $result[1], $result[2]);
}
return ($result[0]) ? array($result[0], $result[1]) : null;
}
/**
* Generates the URL from a given set of keywords
* Returns the URL text, or null if no URL could be generated.
*
* Usage:
* $m->generate(array('controller' => 'content', 'action' => 'view', 'id' => 10));
*
* @param array $routeArgs Optional explicit route list
* @param array $kargs Keyword arguments (key/value pairs)
* @return null|string URL text or null
*/
public function generate($first = null, $second = null)
{
if ($second) {
$routeArgs = $first;
$kargs = is_null($second) ? array() : $second;
} else {
$routeArgs = array();
$kargs = is_null($first) ? array() : $first;
}
// Generate ourself if we haven't already
if (!$this->_createdGens) {
$this->_createGens();
}
if ($this->appendSlash) {
$kargs['_appendSlash'] = true;
}
if (!$this->explicit) {
if (!in_array('controller', array_keys($kargs))) {
$kargs['controller'] = 'content';
}
if (!in_array('action', array_keys($kargs))) {
$kargs['action'] = 'index';
}
}
$environ = $this->environ;
$controller = isset($kargs['controller']) ? $kargs['controller'] : null;
$action = isset($kargs['action']) ? $kargs['action'] : null;
// If the URL didn't depend on the SCRIPT_NAME, we'll cache it
// keyed by just the $kargs; otherwise we need to cache it with
// both SCRIPT_NAME and $kargs:
$cacheKey = serialize($kargs);
if (!empty($environ['SCRIPT_NAME'])) {
$cacheKeyScriptName = sprintf('%s:%s', $environ['SCRIPT_NAME'], $cacheKey);
} else {
$cacheKeyScriptName = $cacheKey;
}
// Check the URL cache to see if it exists, use it if it does.
foreach (array($cacheKey, $cacheKeyScriptName) as $key) {
if (in_array($key, array_keys($this->urlCache))) {
return $this->urlCache[$key];
}
}
if ($routeArgs) {
$keyList = $routeArgs;
} else {
$actionList = isset($this->_gendict[$controller]) ? $this->_gendict[$controller] : $this->_gendict['*'];
list($keyList, $sortCache) =
(isset($actionList[$action])) ? $actionList[$action] : ((isset($actionList['*'])) ? $actionList['*'] : array(null, null));
if ($keyList === null) {
return null;
}
}
$keys = array_keys($kargs);
// necessary to pass $keys to _keysort() callback used by PHP's usort()
$this->_keysortTmp = $keys;
$newList = array();
foreach ($keyList as $route) {
$tmp = Horde_Routes_Utils::arraySubtract($route->minKeys, $keys);
if (count($tmp) == 0) {
$newList[] = $route;
}
}
$keyList = $newList;
// inline python function keysort() moved below as _keycmp()
$this->_keysort($keyList);
foreach ($keyList as $route) {
$fail = false;
foreach ($route->hardCoded as $key) {
$kval = isset($kargs[$key]) ? $kargs[$key] : null;
if ($kval == null) {
continue;
}
if ($kval != $route->defaults[$key]) {
$fail = true;
break;
}
}
if ($fail) {
continue;
}
$path = $route->generate($kargs);
if ($path) {
if ($this->prefix) {
$path = $this->prefix . $path;
}
if (!empty($environ['SCRIPT_NAME']) && !$route->absolute) {
$path = $environ['SCRIPT_NAME'] . $path;
$key = $cacheKeyScriptName;
} else {
$key = $cacheKey;
}
if ($this->urlCache != null) {
$this->urlCache[$key] = $path;
}
return $path;
} else {
continue;
}
}
return null;
}
/**
* Generate routes for a controller resource
*
* The $memberName name should be the appropriate singular version of the
* resource given your locale and used with members of the collection.
*
* The $collectionName name will be used to refer to the resource
* collection methods and should be a plural version of the $memberName
* argument. By default, the $memberName name will also be assumed to map
* to a controller you create.
*
* The concept of a web resource maps somewhat directly to 'CRUD'
* operations. The overlying things to keep in mind is that mapping a
* resource is about handling creating, viewing, and editing that
* resource.
*
* All keyword arguments ($kargs) are optional.
*
* ``controller``
* If specified in the keyword args, the controller will be the actual
* controller used, but the rest of the naming conventions used for
* the route names and URL paths are unchanged.
*
* ``collection``
* Additional action mappings used to manipulate/view the entire set of
* resources provided by the controller.
*
* Example::
*
* $map->resource('message', 'messages',
* array('collection' => array('rss' => 'GET)));
* # GET /message;rss (maps to the rss action)
* # also adds named route "rss_message"
*
* ``member``
* Additional action mappings used to access an individual 'member'
* of this controllers resources.
*
* Example::
*
* $map->resource('message', 'messages',
* array('member' => array('mark' => 'POST')));
* # POST /message/1;mark (maps to the mark action)
* # also adds named route "mark_message"
*
* ``new``
* Action mappings that involve dealing with a new member in the
* controller resources.
*
* Example::
*
* $map->resource('message', 'messages',
* array('new' => array('preview' => 'POST')));
* # POST /message/new;preview (maps to the preview action)
* # also adds a url named "preview_new_message"
*
* ``pathPrefix``
* Prepends the URL path for the Route with the pathPrefix given.
* This is most useful for cases where you want to mix resources
* or relations between resources.
*
* ``namePrefix``
* Perpends the route names that are generated with the namePrefix
* given. Combined with the pathPrefix option, it's easy to
* generate route names and paths that represent resources that are
* in relations.
*
* Example::
*
* map.resource('message', 'messages',
* array('controller' => 'categories',
* 'pathPrefix' => '/category/:category_id',
* 'namePrefix' => 'category_')));
* # GET /category/7/message/1
* # has named route "category_message"
*
* ``parentResource``
* An assoc. array containing information about the parent resource,
* for creating a nested resource. It should contain the ``$memberName``
* and ``collectionName`` of the parent resource. This assoc. array will
* be available via the associated ``Route`` object which can be
* accessed during a request via ``request.environ['routes.route']``
*
* If ``parentResource`` is supplied and ``pathPrefix`` isn't,
* ``pathPrefix`` will be generated from ``parentResource`` as
* "/:_id".
*
* If ``parentResource`` is supplied and ``namePrefix`` isn't,
* ``namePrefix`` will be generated from ``parentResource`` as
* "_".
*
* Example::
*
* $m = new Horde_Routes_Mapper();
* $utils = $m->utils;
*
* $m->resource('location', 'locations',
* array('parentResource' =>
* array('memberName' => 'region',
* 'collectionName' => 'regions'))));
* # pathPrefix is "regions/:region_id"
* # namePrefix is "region_"
*
* $utils->urlFor('region_locations', array('region_id'=>13));
* # '/regions/13/locations'
*
* $utils->urlFor('region_new_location', array('region_id'=>13));
* # '/regions/13/locations/new'
*
* $utils->urlFor('region_location',
* array('region_id'=>13, 'id'=>60));
* # '/regions/13/locations/60'
*
* $utils->urlFor('region_edit_location',
* array('region_id'=>13, 'id'=>60));
* # '/regions/13/locations/60/edit'
*
* Overriding generated ``pathPrefix``::
*
* $m = new Horde_Routes_Mapper();
* $utils = new Horde_Routes_Utils();
*
* $m->resource('location', 'locations',
* array('parentResource' =>
* array('memberName' => 'region',
* 'collectionName' => 'regions'),
* 'pathPrefix' => 'areas/:area_id')));
* # name prefix is "region_"
*
* $utils->urlFor('region_locations', array('area_id'=>51));
* # '/areas/51/locations'
*
* Overriding generated ``namePrefix``::
*
* $m = new Horde_Routes_Mapper
* $m->resource('location', 'locations',
* array('parentResource' =>
* array('memberName' => 'region',
* 'collectionName' => 'regions'),
* 'namePrefix' => '')));
* # pathPrefix is "regions/:region_id"
*
* $utils->urlFor('locations', array('region_id'=>51));
* # '/regions/51/locations'
*
* Note: Since Horde Routes 0.2.0 and Python Routes 1.8, this method is
* not compatible with earlier versions inasmuch as the semicolon is no
* longer used to delimit custom actions. This was a change in Rails
* itself (http://dev.rubyonrails.org/changeset/6485) and adopting it
* here allows us to keep parity with Rails and ActiveResource.
*
* @param string $memberName Singular version of the resource name
* @param string $collectionName Collection name (plural of $memberName)
* @param array $kargs Keyword arguments (see above)
* @return void
*/
public function resource($memberName, $collectionName, $kargs = array())
{
$defaultKargs = array('collection' => array(),
'member' => array(),
'new' => array(),
'pathPrefix' => null,
'namePrefix' => null,
'parentResource' => null);
$kargs = array_merge($defaultKargs, $kargs);
// Generate ``pathPrefix`` if ``pathPrefix`` wasn't specified and
// ``parentResource`` was. Likewise for ``namePrefix``. Make sure
// that ``pathPrefix`` and ``namePrefix`` *always* take precedence if
// they are specified--in particular, we need to be careful when they
// are explicitly set to "".
if ($kargs['parentResource'] !== null) {
if ($kargs['pathPrefix'] === null) {
$kargs['pathPrefix'] = $kargs['parentResource']['collectionName'] . '/:'
. $kargs['parentResource']['memberName'] . '_id';
}
if ($kargs['namePrefix'] === null) {
$kargs['namePrefix'] = $kargs['parentResource']['memberName'] . '_';
}
} else {
if ($kargs['pathPrefix'] === null) {
$kargs['pathPrefix'] = '';
}
if ($kargs['namePrefix'] === null) {
$kargs['namePrefix'] = '';
}
}
// Ensure the edit and new actions are in and GET
$kargs['member']['edit'] = 'GET';
$kargs['new']['new'] = 'GET';
// inline python method swap() moved below as _swap()
$collectionMethods = $this->_swap($kargs['collection'], array());
$memberMethods = $this->_swap($kargs['member'], array());
$newMethods = $this->_swap($kargs['new'], array());
// Insert create, update, and destroy methods
if (!isset($collectionMethods['POST'])) {
$collectionMethods['POST'] = array();
}
array_unshift($collectionMethods['POST'], 'create');
if (!isset($memberMethods['PUT'])) {
$memberMethods['PUT'] = array();
}
array_unshift($memberMethods['PUT'], 'update');
if (!isset($memberMethods['DELETE'])) {
$memberMethods['DELETE'] = array();
}
array_unshift($memberMethods['DELETE'], 'delete');
// If there's a path prefix option, use it with the controller
$controller = $this->_stripSlashes($collectionName);
$kargs['pathPrefix'] = $this->_stripSlashes($kargs['pathPrefix']);
if ($kargs['pathPrefix']) {
$path = $kargs['pathPrefix'] . '/' . $controller;
} else {
$path = $controller;
}
$collectionPath = $path;
$newPath = $path . '/new';
$memberPath = $path . '/:(id)';
$options = array(
'controller' => (isset($kargs['controller']) ? $kargs['controller'] : $controller),
'_memberName' => $memberName,
'_collectionName' => $collectionName,
'_parentResource' => $kargs['parentResource']
);
// inline python method requirements_for() moved below as _requirementsFor()
// Add the routes for handling collection methods
foreach ($collectionMethods as $method => $lst) {
$primary = ($method != 'GET' && isset($lst[0])) ? array_shift($lst) : null;
$routeOptions = $this->_requirementsFor($method, $options);
foreach ($lst as $action) {
$routeOptions['action'] = $action;
$routeName = sprintf('%s%s_%s', $kargs['namePrefix'], $action, $collectionName);
$this->connect($routeName,
sprintf("%s/%s", $collectionPath, $action),
$routeOptions);
$this->connect('formatted_' . $routeName,
sprintf("%s/%s.:(format)", $collectionPath, $action),
$routeOptions);
}
if ($primary) {
$routeOptions['action'] = $primary;
$this->connect($collectionPath, $routeOptions);
$this->connect($collectionPath . '.:(format)', $routeOptions);
}
}
// Specifically add in the built-in 'index' collection method and its
// formatted version
$connectkargs = array('action' => 'index',
'conditions' => array('method' => array('GET')));
$this->connect($kargs['namePrefix'] . $collectionName,
$collectionPath,
array_merge($connectkargs, $options));
$this->connect('formatted_' . $kargs['namePrefix'] . $collectionName,
$collectionPath . '.:(format)',
array_merge($connectkargs, $options));
// Add the routes that deal with new resource methods
foreach ($newMethods as $method => $lst) {
$routeOptions = $this->_requirementsFor($method, $options);
foreach ($lst as $action) {
if ($action == 'new' && $newPath) {
$path = $newPath;
} else {
$path = sprintf('%s/%s', $newPath, $action);
}
$name = 'new_' . $memberName;
if ($action != 'new') {
$name = $action . '_' . $name;
}
$routeOptions['action'] = $action;
$this->connect($kargs['namePrefix'] . $name, $path, $routeOptions);
if ($action == 'new' && $newPath) {
$path = $newPath . '.:(format)';
} else {
$path = sprintf('%s/%s.:(format)', $newPath, $action);
}
$this->connect('formatted_' . $kargs['namePrefix'] . $name,
$path, $routeOptions);
}
}
$requirementsRegexp = '[\w\-_]+';
// Add the routes that deal with member methods of a resource
foreach ($memberMethods as $method => $lst) {
$routeOptions = $this->_requirementsFor($method, $options);
$routeOptions['requirements'] = array('id' => $requirementsRegexp);
if (!in_array($method, array('POST', 'GET', 'any'))) {
$primary = array_shift($lst);
} else {
$primary = null;
}
foreach ($lst as $action) {
$routeOptions['action'] = $action;
$this->connect(sprintf('%s%s_%s', $kargs['namePrefix'], $action, $memberName),
sprintf('%s/%s', $memberPath, $action),
$routeOptions);
$this->connect(sprintf('formatted_%s%s_%s', $kargs['namePrefix'], $action, $memberName),
sprintf('%s/%s.:(format)', $memberPath, $action),
$routeOptions);
}
if ($primary) {
$routeOptions['action'] = $primary;
$this->connect($memberPath, $routeOptions);
$this->connect($memberPath . '.:(format)', $routeOptions);
}
}
// Specifically add the member 'show' method
$routeOptions = $this->_requirementsFor('GET', $options);
$routeOptions['action'] = 'show';
$routeOptions['requirements'] = array('id' => $requirementsRegexp);
$this->connect($kargs['namePrefix'] . $memberName, $memberPath, $routeOptions);
$this->connect('formatted_' . $kargs['namePrefix'] . $memberName,
$memberPath . '.:(format)', $routeOptions);
}
/**
* Returns a new dict to be used for all route creation as
* the route options.
* @see resource()
*
* @param string $method Request method ('get', 'post', etc.) or 'any'
* @param array $options Assoc. array to populate with 'conditions' key
* @return $options populated
*/
protected function _requirementsFor($meth, $options)
{
if ($meth != 'any') {
$options['conditions'] = array('method' => array(Horde_String::upper($meth)));
}
return $options;
}
/**
* Swap the keys and values in the dict, and uppercase the values
* from the dict during the swap.
* @see resource()
*
* @param array $dct Input dict (assoc. array)
* @param array $newdct Output dict to populate
* @return array $newdct populated
*/
protected function _swap($dct, $newdct)
{
foreach ($dct as $key => $val) {
$newkey = Horde_String::upper($val);
if (!isset($newdct[$newkey])) {
$newdct[$newkey] = array();
}
$newdct[$newkey][] = $key;
}
return $newdct;
}
/**
* Sort an array of Horde_Routes_Routes to using _keycmp() for the comparision
* to order them ideally for matching.
*
* An unfortunate property of PHP's usort() is that if two members compare
* equal, their order in the sorted array is undefined (see PHP manual).
* This is unsuitable for us because the order that the routes were
* connected to the mapper is significant.
*
* Uses this method uses merge sort algorithm based on the
* comments in http://www.php.net/usort
*
* @param array $array Array Horde_Routes_Route objects to sort (by reference)
* @return void
*/
protected function _keysort(&$array)
{
// arrays of size < 2 require no action.
if (count($array) < 2) { return; }
// split the array in half
$halfway = count($array) / 2;
$array1 = array_slice($array, 0, $halfway);
$array2 = array_slice($array, $halfway);
// recurse to sort the two halves
$this->_keysort($array1);
$this->_keysort($array2);
// if all of $array1 is <= all of $array2, just append them.
if ($this->_keycmp(end($array1), $array2[0]) < 1) {
$array = array_merge($array1, $array2);
return;
}
// merge the two sorted arrays into a single sorted array
$array = array();
$ptr1 = 0;
$ptr2 = 0;
while ($ptr1 < count($array1) && $ptr2 < count($array2)) {
if ($this->_keycmp($array1[$ptr1], $array2[$ptr2]) < 1) {
$array[] = $array1[$ptr1++];
}
else {
$array[] = $array2[$ptr2++];
}
}
// merge the remainder
while ($ptr1 < count($array1)) { $array[] = $array1[$ptr1++]; }
while ($ptr2 < count($array2)) { $array[] = $array2[$ptr2++]; }
return;
}
/**
* Compare two Horde_Route_Routes objects by their keys against
* the instance variable $keysortTmp. Used by _keysort().
*
* @param array $a First dict (assoc. array)
* @param array $b Second dict
* @return integer
*/
protected function _keycmp($a, $b)
{
$keys = $this->_keysortTmp;
$am = $a->minKeys;
$a = $a->maxKeys;
$b = $b->maxKeys;
$lendiffa = count(array_diff($keys, $a));
$lendiffb = count(array_diff($keys, $b));
// If they both match, don't switch them
if ($lendiffa == 0 && $lendiffb == 0) {
return 0;
}
// First, if $a matches exactly, use it
if ($lendiffa == 0) {
return -1;
}
// Or $b matches exactly, use it
if ($lendiffb == 0) {
return 1;
}
// Neither matches exactly, return the one with the most in common
if ($this->_cmp($lendiffa, $lendiffb) != 0) {
return $this->_cmp($lendiffa, $lendiffb);
}
// Neither matches exactly, but if they both have just as much in common
if (count($this->_arrayUnion($keys, $b)) == count($this->_arrayUnion($keys, $a))) {
return $this->_cmp(count($a), count($b));
// Otherwise, we return the one that has the most in common
} else {
return $this->_cmp(count($this->_arrayUnion($keys, $b)), count($this->_arrayUnion($keys, $a)));
}
}
/**
* Create a union of two arrays.
*
* @param array $a First array
* @param array $b Second array
* @return array Union of $a and $b
*/
protected function _arrayUnion($a, $b)
{
return array_merge(array_diff($a, $b), array_diff($b, $a), array_intersect($a, $b));
}
/**
* Equivalent of Python's cmp() function.
*
* @param integer|float $a First item to compare
* @param integer|flot $b Second item to compare
* @param integer Result of comparison
*/
protected function _cmp($a, $b)
{
if ($a < $b) {
return -1;
}
if ($a == $b) {
return 0;
}
return 1;
}
/**
* Trims slashes from the beginning or end of a part/URL.
*
* @param string $name Part or URL with slash at begin/end
* @return string Part or URL with begin/end slashes removed
*/
protected function _stripSlashes($name)
{
if (substr($name, 0, 1) == '/') {
$name = substr($name, 1);
}
if (substr($name, -1, 1) == '/') {
$name = substr($name, 0, -1);
}
return $name;
}
}
Horde_Routes-2.0.5/lib/Horde/Routes/Matcher.php 0000664 0001750 0001750 00000004217 12654066370 017425 0 ustar jan jan
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @link http://pear.horde.org/index.php?package=Horde_Routes
*/
/**
* Generates the match dictionary for the incoming request.
*
* Copyright 2011-2016 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you did not
* receive this file, see
* http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package Horde_Routes
* @author Gunnar Wrobel
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @link http://pear.horde.org/index.php?package=Horde_Routes
*/
class Horde_Routes_Matcher
{
/**
* The routes mapper.
*
* @var Horde_Routes_Mapper
*/
protected $_mapper;
/**
* The incoming request.
*
* @var Horde_Controller_Request
*/
protected $_request;
/**
* The match dictionary.
*
* @var array
*/
protected $_match_dict;
/**
* Constructor
*
* @param Horde_Routes_Mapper $mapper The mapper
* @param Object $request A request object that implements a ::getPath()
* method similar to Horde_Controller_Request::
*/
public function __construct(
Horde_Routes_Mapper $mapper,
$request)
{
$this->_mapper = $mapper;
$this->_request = $request;
}
/**
* Return the match dictionary for the incoming request.
*
* @return array The match dictionary.
*/
public function getMatchDict()
{
if ($this->_match_dict === null) {
$path = $this->_request->getPath();
if (($pos = strpos($path, '?')) !== false) {
$path = substr($path, 0, $pos);
}
if (!$path) {
$path = '/';
}
$this->_match_dict = new Horde_Support_Array($this->_mapper->match($path));
}
return $this->_match_dict;
}
}
Horde_Routes-2.0.5/lib/Horde/Routes/Printer.php 0000664 0001750 0001750 00000007547 12654066370 017476 0 ustar jan jan _mapper = $mapper;
}
/**
* Pretty-print a listing of the routes connected to the mapper.
*
* @param stream|null $stream Output stream for printing (optional)
* @param string|null $eol Line ending (optional)
* @return void
*/
public function printRoutes($stream = null, $eol = PHP_EOL)
{
$routes = $this->getRoutes();
if (empty($routes)) { return; }
if ($stream === null) {
$stream = fopen('php://output', 'a');
}
// find the max $widths to size the output columns {'name'=>40, 'method'=>6, ...}
$widths = array();
foreach (array_keys($routes[0]) as $key) {
$width = 0;
foreach($routes as $r) {
$l = strlen($r[$key]);
if ($l > $width) { $width = $l; }
}
$widths[$key] = $width;
}
// print the output
foreach ($routes as $r) {
fwrite($stream, str_pad($r['name'], $widths['name'], ' ', STR_PAD_LEFT) . ' ');
fwrite($stream, str_pad($r['method'], $widths['method'], ' ', STR_PAD_RIGHT) . ' ');
fwrite($stream, str_pad($r['path'], $widths['path'], ' ', STR_PAD_RIGHT) . ' ');
fwrite($stream, $r['hardcodes'] . $eol);
}
}
/**
* Analyze the mapper and return an array of data about the
* routes connected to the mapper.
*
* @return array
*/
public function getRoutes()
{
/**
* Traverse all routes connected to the mapper in match order,
* and assemble an array of $routes used to build the output
*/
$routes = array();
foreach ($this->_mapper->matchList as $route) {
// name of this route, or empty string if anonymous
$routeName = '';
foreach ($this->_mapper->routeNames as $name => $namedRoute) {
if ($route === $namedRoute) { $routeName = $name; break; }
}
// request_method types recognized by this route, or empty string for any
$methods = array('');
if (isset($route->conditions['method']) && is_array($route->conditions['method']) ) {
$methods = $route->conditions['method'];
}
// hardcoded defaults that can't be overriden by the request path as {:key=>"value"}
$hardcodes = array();
foreach ($route->hardCoded as $key) {
$value = isset($route->defaults[$key]) ? $route->defaults[$key] : 'NULL';
$dump = ":{$key}=>\"{$value}\"";
($key == 'controller') ? array_unshift($hardcodes, $dump) : $hardcodes[] = $dump;
}
$hardcodes = empty($hardcodes) ? '' : '{'. implode(', ', $hardcodes) .'}';
// route data for output
foreach ($methods as $method) {
$routes[] = array('name' => $routeName,
'method' => $method,
'path' => '/' . $route->routePath,
'hardcodes' => $hardcodes);
}
}
return $routes;
}
}
Horde_Routes-2.0.5/lib/Horde/Routes/Route.php 0000664 0001750 0001750 00000067651 12654066370 017153 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* The Route object holds a route recognition and generation routine.
* See __construct() docs for usage.
*
* @package Routes
*/
class Horde_Routes_Route
{
/**
* The path for this route, such as ':controller/:action/:id'
* @var string
*/
public $routePath;
/**
* Encoding of this route (not yet supported)
* @var string
*/
public $encoding = 'utf-8';
/**
* What to do on decoding errors? 'ignore' or 'replace'
* @var string
*/
public $decodeErrors = 'replace';
/**
* Is this a static route?
* @var string
*/
public $static;
/**
* Filter function to operate on arguments before generation
* @var callback
*/
public $filter;
/**
* Is this an absolute path? (Mapper will not prepend SCRIPT_NAME)
* @var boolean
*/
public $absolute;
/**
* Does this route use explicit mode (no implicit defaults)?
* @var boolean
*/
public $explicit;
/**
* Default keyword arguments for this route
* @var array
*/
public $defaults = array();
/**
* Array of keyword args for special conditions (method, subDomain, function)
* @var array
*/
public $conditions;
/**
* Maximum keys that this route could utilize.
* @var array
*/
public $maxKeys;
/**
* Minimum keys required to generate this route
* @var array
*/
public $minKeys;
/**
* Default keywords that don't exist in the path; can't be changed by an incomng URL.
* @var array
*/
public $hardCoded;
/**
* Requirements for this route
* @var array
*/
public $reqs;
/**
* Regular expression for matching this route
* @var string
*/
public $regexp;
/**
* Route path split by '/'
* @var array
*/
protected $_routeList;
/**
* Reverse of $routeList
* @var array
*/
protected $_routeBackwards;
/**
* Characters that split the parts of a URL
* @var array
*/
protected $_splitChars;
/**
* Last path part used by buildNextReg()
* @var string
*/
protected $_prior;
/**
* Requirements formatted as regexps suitable for preg_match()
* @var array
*/
protected $_reqRegs;
/**
* Member name if this is a RESTful route
* @see resource()
* @var null|string
*/
protected $_memberName;
/**
* Collection name if this is a RESTful route
* @see resource()
* @var null|string
*/
protected $_collectionName;
/**
* Name of the parent resource, if this is a RESTful route & has a parent
* @see resource
* @var string
*/
protected $_parentResource;
/**
* Initialize a route, with a given routepath for matching/generation
*
* The set of keyword args will be used as defaults.
*
* Usage:
* $route = new Horde_Routes_Route(':controller/:action/:id');
*
* $route = new Horde_Routes_Route('date/:year/:month/:day',
* array('controller'=>'blog', 'action'=>'view'));
*
* $route = new Horde_Routes_Route('archives/:page',
* array('controller'=>'blog', 'action'=>'by_page',
* 'requirements' => array('page'=>'\d{1,2}'));
*
* Note:
* Route is generally not called directly, a Mapper instance connect()
* method should be used to add routes.
*/
public function __construct($routePath, $kargs = array())
{
$this->routePath = $routePath;
// Don't bother forming stuff we don't need if its a static route
$this->static = isset($kargs['_static']) ? $kargs['_static'] : false;
$this->filter = isset($kargs['_filter']) ? $kargs['_filter'] : null;
unset($kargs['_filter']);
$this->absolute = isset($kargs['_absolute']) ? $kargs['_absolute'] : false;
unset($kargs['_absolute']);
// Pull out the member/collection name if present, this applies only to
// map.resource
$this->_memberName = isset($kargs['_memberName']) ? $kargs['_memberName'] : null;
unset($kargs['_memberName']);
$this->_collectionName = isset($kargs['_collectionName']) ? $kargs['_collectionName'] : null;
unset($kargs['_collectionName']);
$this->_parentResource = isset($kargs['_parentResource']) ? $kargs['_parentResource'] : null;
unset($kargs['_parentResource']);
// Pull out route conditions
$this->conditions = isset($kargs['conditions']) ? $kargs['conditions'] : null;
unset($kargs['conditions']);
// Determine if explicit behavior should be used
$this->explicit = isset($kargs['_explicit']) ? $kargs['_explicit'] : false;
unset($kargs['_explicit']);
// Reserved keys that don't count
$reservedKeys = array('requirements');
// Name has been changed from the Python version
// This is a list of characters natural splitters in a URL
$this->_splitChars = array('/', ',', ';', '.', '#');
// trim preceding '/' if present
if (substr($this->routePath, 0, 1) == '/') {
$routePath = substr($this->routePath, 1);
}
// Build our routelist, and the keys used in the route
$this->_routeList = $this->_pathKeys($routePath);
$routeKeys = array();
foreach ($this->_routeList as $key) {
if (is_array($key)) { $routeKeys[] = $key['name']; }
}
// Build a req list with all the regexp requirements for our args
$this->reqs = isset($kargs['requirements']) ? $kargs['requirements'] : array();
$this->_reqRegs = array();
foreach ($this->reqs as $key => $value) {
$this->_reqRegs[$key] = '@^' . str_replace('@', '\@', $value) . '$@';
}
// Update our defaults and set new default keys if needed. defaults
// needs to be saved
list($this->defaults, $defaultKeys) = $this->_defaults($routeKeys, $reservedKeys, $kargs);
// Save the maximum keys we could utilize
$this->maxKeys = array_keys(array_flip(array_merge($defaultKeys, $routeKeys)));
list($this->minKeys, $this->_routeBackwards) = $this->_minKeys($this->_routeList);
// Populate our hardcoded keys, these are ones that are set and don't
// exist in the route
$this->hardCoded = array();
foreach ($this->maxKeys as $key) {
if (!in_array($key, $routeKeys) && $this->defaults[$key] != null) {
$this->hardCoded[] = $key;
}
}
}
/**
* Utility method to walk the route, and pull out the valid
* dynamic/wildcard keys
*
* @param string $routePath Route path
* @return array Route list
*/
protected function _pathKeys($routePath)
{
$collecting = false;
$current = '';
$doneOn = array();
$varType = '';
$justStarted = false;
$routeList = array();
foreach (preg_split('//', $routePath, -1, PREG_SPLIT_NO_EMPTY) as $char) {
if (!$collecting && in_array($char, array(':', '*'))) {
$justStarted = true;
$collecting = true;
$varType = $char;
if (strlen($current) > 0) {
$routeList[] = $current;
$current = '';
}
} elseif ($collecting && $justStarted) {
$justStarted = false;
if ($char == '(') {
$doneOn = array(')');
} else {
$current = $char;
// Basically appends '-' to _splitChars
// Helps it fall in line with the Python idioms.
$doneOn = $this->_splitChars + array('-');
}
} elseif ($collecting && !in_array($char, $doneOn)) {
$current .= $char;
} elseif ($collecting) {
$collecting = false;
$routeList[] = array('type' => $varType, 'name' => $current);
if (in_array($char, $this->_splitChars)) {
$routeList[] = $char;
}
$doneOn = $varType = $current = '';
} else {
$current .= $char;
}
}
if ($collecting) {
$routeList[] = array('type' => $varType, 'name' => $current);
} elseif (!empty($current)) {
$routeList[] = $current;
}
return $routeList;
}
/**
* Utility function to walk the route backwards
*
* Will determine the minimum keys we must have to generate a
* working route.
*
* @param array $routeList Route path split by '/'
* @return array [minimum keys for route, route list reversed]
*/
protected function _minKeys($routeList)
{
$minKeys = array();
$backCheck = array_reverse($routeList);
$gaps = false;
foreach ($backCheck as $part) {
if (!is_array($part) && !in_array($part, $this->_splitChars)) {
$gaps = true;
continue;
} elseif (!is_array($part)) {
continue;
}
$key = $part['name'];
if (array_key_exists($key, $this->defaults) && !$gaps)
continue;
$minKeys[] = $key;
$gaps = true;
}
return array($minKeys, $backCheck);
}
/**
* Creates a default array of strings
*
* Puts together the array of defaults, turns non-null values to strings,
* and add in our action/id default if they use and do not specify it
*
* Precondition: $this->_defaultKeys is an array of the currently assumed default keys
*
* @param array $routekeys All the keys found in the route path
* @param array $reservedKeys Array of keys not in the route path
* @param array $kargs Keyword args passed to the Route constructor
* @return array [defaults, new default keys]
*/
protected function _defaults($routeKeys, $reservedKeys, $kargs)
{
$defaults = array();
// Add in a controller/action default if they don't exist
if ((!in_array('controller', $routeKeys)) &&
(!in_array('controller', array_keys($kargs))) &&
(!$this->explicit)) {
$kargs['controller'] = 'content';
}
if (!in_array('action', $routeKeys) &&
(!in_array('action', array_keys($kargs))) &&
(!$this->explicit)) {
$kargs['action'] = 'index';
}
$defaultKeys = array();
foreach (array_keys($kargs) as $key) {
if (!in_array($key, $reservedKeys)) {
$defaultKeys[] = $key;
}
}
foreach ($defaultKeys as $key) {
if ($kargs[$key] !== null) {
$defaults[$key] = (string)$kargs[$key];
} else {
$defaults[$key] = null;
}
}
if (in_array('action', $routeKeys) &&
(!array_key_exists('action', $defaults)) &&
(!$this->explicit)) {
$defaults['action'] = 'index';
}
if (in_array('id', $routeKeys) &&
(!array_key_exists('id', $defaults)) &&
(!$this->explicit)) {
$defaults['id'] = null;
}
$newDefaultKeys = array();
foreach (array_keys($defaults) as $key) {
if (!in_array($key, $reservedKeys)) {
$newDefaultKeys[] = $key;
}
}
return array($defaults, $newDefaultKeys);
}
/**
* Create the regular expression for matching.
*
* Note: This MUST be called before match can function properly.
*
* clist should be a list of valid controller strings that can be
* matched, for this reason makeregexp should be called by the web
* framework after it knows all available controllers that can be
* utilized.
*
* @param array $clist List of all possible controllers
* @return void
*/
public function makeRegexp($clist)
{
list($reg, $noreqs, $allblank) = $this->buildNextReg($this->_routeList, $clist);
if (empty($reg)) {
$reg = '/';
}
$reg = $reg . '(/)?$';
if (substr($reg, 0, 1) != '/') {
$reg = '/' . $reg;
}
$reg = '^' . $reg;
$this->regexp = $reg;
}
/**
* Recursively build a regexp given a path, and a controller list.
*
* Returns the regular expression string, and two booleans that can be
* ignored as they're only used internally by buildnextreg.
*
* @param array $path The RouteList for the path
* @param array $clist List of all possible controllers
* @return array [array, boolean, boolean]
*/
public function buildNextReg($path, $clist)
{
if (!empty($path)) {
$part = $path[0];
} else {
$part = '';
}
// noreqs will remember whether the remainder has either a string
// match, or a non-defaulted regexp match on a key, allblank remembers
// if the rest could possible be completely empty
list($rest, $noreqs, $allblank) = array('', true, true);
if (count($path) > 1) {
$this->_prior = $part;
list($rest, $noreqs, $allblank) = $this->buildNextReg(array_slice($path, 1), $clist);
}
if (is_array($part) && $part['type'] == ':') {
$var = $part['name'];
$partreg = '';
// First we plug in the proper part matcher
if (array_key_exists($var, $this->reqs)) {
$partreg = '(?P<' . $var . '>' . $this->reqs[$var] . ')';
} elseif ($var == 'controller') {
$partreg = '(?P<' . $var . '>' . implode('|', array_map('preg_quote', $clist)) . ')';
} elseif (in_array($this->_prior, array('/', '#'))) {
$partreg = '(?P<' . $var . '>[^' . $this->_prior . ']+?)';
} else {
if (empty($rest)) {
$partreg = '(?P<' . $var . '>[^/]+?)';
} else {
$partreg = '(?P<' . $var . '>[^' . implode('', $this->_splitChars) . ']+?)';
}
}
if (array_key_exists($var, $this->reqs)) {
$noreqs = false;
}
if (!array_key_exists($var, $this->defaults)) {
$allblank = false;
$noreqs = false;
}
// Now we determine if its optional, or required. This changes
// depending on what is in the rest of the match. If noreqs is
// true, then its possible the entire thing is optional as there's
// no reqs or string matches.
if ($noreqs) {
// The rest is optional, but now we have an optional with a
// regexp. Wrap to ensure that if we match anything, we match
// our regexp first. It's still possible we could be completely
// blank as we have a default
if (array_key_exists($var, $this->reqs) && array_key_exists($var, $this->defaults)) {
$reg = '(' . $partreg . $rest . ')?';
// Or we have a regexp match with no default, so now being
// completely blank form here on out isn't possible
} elseif (array_key_exists($var, $this->reqs)) {
$allblank = false;
$reg = $partreg . $rest;
// If the character before this is a special char, it has to be
// followed by this
} elseif (array_key_exists($var, $this->defaults) && in_array($this->_prior, array(',', ';', '.'))) {
$reg = $partreg . $rest;
// Or we have a default with no regexp, don't touch the allblank
} elseif (array_key_exists($var, $this->defaults)) {
$reg = $partreg . '?' . $rest;
// Or we have a key with no default, and no reqs. Not possible
// to be all blank from here
} else {
$allblank = false;
$reg = $partreg . $rest;
}
// In this case, we have something dangling that might need to be
// matched
} else {
// If they can all be blank, and we have a default here, we know
// its safe to make everything from here optional. Since
// something else in the chain does have req's though, we have
// to make the partreg here required to continue matching
if ($allblank && array_key_exists($var, $this->defaults)) {
$reg = '(' . $partreg . $rest . ')?';
// Same as before, but they can't all be blank, so we have to
// require it all to ensure our matches line up right
} else {
$reg = $partreg . $rest;
}
}
} elseif (is_array($part) && $part['type'] == '*') {
$var = $part['name'];
if ($noreqs) {
$reg = '(?P<' . $var . '>.*)' . $rest;
if (!array_key_exists($var, $this->defaults)) {
$allblank = false;
$noreqs = false;
}
} else {
if ($allblank && array_key_exists($var, $this->defaults)) {
$reg = '(?P<' . $var . '>.*)' . $rest;
} elseif (array_key_exists($var, $this->defaults)) {
$reg = '(?P<' . $var . '>.*)' . $rest;
} else {
$allblank = false;
$noreqs = false;
$reg = '(?P<' . $var . '>.*)' . $rest;
}
}
} elseif ($part && in_array(substr($part, -1), $this->_splitChars)) {
if ($allblank) {
$reg = preg_quote(substr($part, 0, -1)) . '(' . preg_quote(substr($part, -1)) . $rest . ')?';
} else {
$allblank = false;
$reg = preg_quote($part) . $rest;
}
// We have a normal string here, this is a req, and it prevents us from
// being all blank
} else {
$noreqs = false;
$allblank = false;
$reg = preg_quote($part) . $rest;
}
return array($reg, $noreqs, $allblank);
}
/**
* Match a url to our regexp.
*
* While the regexp might match, this operation isn't
* guaranteed as there's other factors that can cause a match to fail
* even though the regexp succeeds (Default that was relied on wasn't
* given, requirement regexp doesn't pass, etc.).
*
* Therefore the calling function shouldn't assume this will return a
* valid dict, the other possible return is False if a match doesn't work
* out.
*
* @param string $url URL to match
* @param array Keyword arguments
* @return null|array Array of match data if matched, Null otherwise
*/
public function match($url, $kargs = array())
{
$defaultKargs = array('environ' => array(),
'subDomains' => false,
'subDomainsIgnore' => array(),
'domainMatch' => '');
$kargs = array_merge($defaultKargs, $kargs);
// Static routes don't match, they generate only
if ($this->static) {
return false;
}
if (substr($url, -1) == '/' && strlen($url) > 1) {
$url = substr($url, 0, -1);
}
// Match the regexps we generated
$match = preg_match('@' . str_replace('@', '\@', $this->regexp) . '@', $url, $matches);
if ($match == 0) {
return false;
}
$host = isset($kargs['environ']['HTTP_HOST']) ? $kargs['environ']['HTTP_HOST'] : null;
if ($host !== null && !empty($kargs['subDomains'])) {
$host = substr($host, 0, strpos(':', $host));
$subMatch = '@^(.+?)\.' . $kargs['domainMatch'] . '$';
$subdomain = preg_replace($subMatch, '$1', $host);
if (!in_array($subdomain, $kargs['subDomainsIgnore']) && $host != $subdomain) {
$subDomain = $subdomain;
}
}
if (!empty($this->conditions)) {
if (isset($this->conditions['method'])) {
if (empty($kargs['environ']['REQUEST_METHOD'])) { return false; }
if (!in_array($kargs['environ']['REQUEST_METHOD'], $this->conditions['method'])) {
return false;
}
}
// Check sub-domains?
$use_sd = isset($this->conditions['subDomain']) ? $this->conditions['subDomain'] : null;
if (!empty($use_sd) && empty($subDomain)) {
return false;
}
if (is_array($use_sd) && !in_array($subDomain, $use_sd)) {
return false;
}
}
$matchDict = $matches;
// Clear out int keys as PHP gives us both the named subgroups and numbered subgroups
foreach ($matchDict as $key => $val) {
if (is_int($key)) {
unset($matchDict[$key]);
}
}
$result = array();
$extras = Horde_Routes_Utils::arraySubtract(array_keys($this->defaults), array_keys($matchDict));
foreach ($matchDict as $key => $val) {
// TODO: character set decoding
if ($key != 'path_info' && $this->encoding) {
$val = urldecode($val);
}
if (empty($val) && array_key_exists($key, $this->defaults) && !empty($this->defaults[$key])) {
$result[$key] = $this->defaults[$key];
} else {
$result[$key] = $val;
}
}
foreach ($extras as $key) {
$result[$key] = $this->defaults[$key];
}
// Add the sub-domain if there is one
if (!empty($kargs['subDomains'])) {
$result['subDomain'] = $subDomain;
}
// If there's a function, call it with environ and expire if it
// returns False
if (!empty($this->conditions) && array_key_exists('function', $this->conditions) &&
!call_user_func_array($this->conditions['function'], array($kargs['environ'], $result))) {
return false;
}
return $result;
}
/**
* Generate a URL from ourself given a set of keyword arguments
*
* @param array $kargs Keyword arguments
* @param null|string Null if generation failed, URL otherwise
*/
public function generate($kargs)
{
$defaultKargs = array('_ignoreReqList' => false,
'_appendSlash' => false);
$kargs = array_merge($defaultKargs, $kargs);
$_appendSlash = $kargs['_appendSlash'];
unset($kargs['_appendSlash']);
$_ignoreReqList = $kargs['_ignoreReqList'];
unset($kargs['_ignoreReqList']);
// Verify that our args pass any regexp requirements
if (!$_ignoreReqList) {
foreach ($this->reqs as $key => $v) {
$value = (isset($kargs[$key])) ? $kargs[$key] : null;
if (!empty($value) && !preg_match($this->_reqRegs[$key], $value)) {
return null;
}
}
}
// Verify that if we have a method arg, it's in the method accept list.
// Also, method will be changed to _method for route generation.
$meth = (isset($kargs['method'])) ? $kargs['method'] : null;
if ($meth) {
if ($this->conditions && isset($this->conditions['method']) &&
(!in_array(Horde_String::upper($meth), $this->conditions['method']))) {
return null;
}
unset($kargs['method']);
}
$routeList = $this->_routeBackwards;
$urlList = array();
$gaps = false;
foreach ($routeList as $part) {
if (is_array($part) && $part['type'] == ':') {
$arg = $part['name'];
// For efficiency, check these just once
$hasArg = array_key_exists($arg, $kargs);
$hasDefault = array_key_exists($arg, $this->defaults);
// Determine if we can leave this part off
// First check if the default exists and wasn't provided in the
// call (also no gaps)
if ($hasDefault && !$hasArg && !$gaps) {
continue;
}
// Now check to see if there's a default and it matches the
// incoming call arg
if (($hasDefault && $hasArg) && $kargs[$arg] == $this->defaults[$arg] && !$gaps) {
continue;
}
// We need to pull the value to append, if the arg is NULL and
// we have a default, use that
if ($hasArg && $kargs[$arg] === null && $hasDefault && !$gaps) {
continue;
// Otherwise if we do have an arg, use that
} elseif ($hasArg) {
$val = ($kargs[$arg] === null) ? 'null' : $kargs[$arg];
} elseif ($hasDefault && $this->defaults[$arg] != null) {
$val = $this->defaults[$arg];
// No arg at all? This won't work
} else {
return null;
}
$urlList[] = Horde_Routes_Utils::urlQuote($val, $this->encoding);
if ($hasArg) {
unset($kargs[$arg]);
}
$gaps = true;
} elseif (is_array($part) && $part['type'] == '*') {
$arg = $part['name'];
$kar = (isset($kargs[$arg])) ? $kargs[$arg] : null;
if ($kar != null) {
$urlList[] = Horde_Routes_Utils::urlQuote($kar, $this->encoding);
$gaps = true;
}
} elseif (!empty($part) && in_array(substr($part, -1), $this->_splitChars)) {
if (!$gaps && in_array($part, $this->_splitChars)) {
continue;
} elseif (!$gaps) {
$gaps = true;
$urlList[] = substr($part, 0, -1);
} else {
$gaps = true;
$urlList[] = $part;
}
} else {
$gaps = true;
$urlList[] = $part;
}
}
$urlList = array_reverse($urlList);
$url = implode('', $urlList);
if (substr($url, 0, 1) != '/') {
$url = '/' . $url;
}
$extras = $kargs;
foreach ($this->maxKeys as $key) {
unset($extras[$key]);
}
$extras = array_keys($extras);
if (!empty($extras)) {
if ($_appendSlash && substr($url, -1) != '/') {
$url .= '/';
}
$url .= '?';
$newExtras = array();
foreach ($kargs as $key => $value) {
if (in_array($key, $extras) && ($key != 'action' || $key != 'controller')) {
$newExtras[$key] = $value;
}
}
$url .= http_build_query($newExtras);
} elseif ($_appendSlash && substr($url, -1) != '/') {
$url .= '/';
}
return $url;
}
}
Horde_Routes-2.0.5/lib/Horde/Routes/Utils.php 0000664 0001750 0001750 00000037271 12654066370 017150 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* Utility functions for use in templates and controllers
*
* @package Routes
*/
class Horde_Routes_Utils
{
/**
* @var Horde_Routes_Mapper
*/
public $mapper;
/**
* Match data from last match; implements for urlFor() route memory
* @var array
*/
public $mapperDict = array();
/**
* Callback function used for redirectTo()
* @var callback
*/
public $redirect;
/**
* Constructor
*
* @param Horde_Routes_Mapper $mapper Mapper for these utilities
* @param callback $redirect Redirect callback for redirectTo()
*/
public function __construct(Horde_Routes_Mapper $mapper, $redirect = null)
{
$this->mapper = $mapper;
$this->redirect = $redirect;
}
/**
* Generates a URL.
*
* All keys given to urlFor are sent to the Routes Mapper instance for
* generation except for::
*
* anchor specified the anchor name to be appened to the path
* host overrides the default (current) host if provided
* protocol overrides the default (current) protocol if provided
* qualified creates the URL with the host/port information as
* needed
*
* The URL is generated based on the rest of the keys. When generating a new
* URL, values will be used from the current request's parameters (if
* present). The following rules are used to determine when and how to keep
* the current requests parameters:
*
* * If the controller is present and begins with '/', no defaults are used
* * If the controller is changed, action is set to 'index' unless otherwise
* specified
*
* For example, if the current request yielded a dict (associative array) of
* array('controller'=>'blog', 'action'=>'view', 'id'=>2), with the standard
* ':controller/:action/:id' route, you'd get the following results::
*
* urlFor(array('id'=>4)) => '/blog/view/4',
* urlFor(array('controller'=>'/admin')) => '/admin',
* urlFor(array('controller'=>'admin')) => '/admin/view/2'
* urlFor(array('action'=>'edit')) => '/blog/edit/2',
* urlFor(array('action'=>'list', id=NULL)) => '/blog/list'
*
* **Static and Named Routes**
*
* If there is a string present as the first argument, a lookup is done
* against the named routes table to see if there's any matching routes. The
* keyword defaults used with static routes will be sent in as GET query
* arg's if a route matches.
*
* If no route by that name is found, the string is assumed to be a raw URL.
* Should the raw URL begin with ``/`` then appropriate SCRIPT_NAME data will
* be added if present, otherwise the string will be used as the url with
* keyword args becoming GET query args.
*/
public function urlFor($first = array(), $second = array())
{
if (is_array($first)) {
// urlFor(array('controller' => 'foo', ...))
$routeName = null;
$kargs = $first;
} else {
// urlFor('named_route')
// urlFor('named_route', array('id' => 3, ...))
// urlFor('static_path')
$routeName = (string)$first;
$kargs = $second;
}
$anchor = isset($kargs['anchor']) ? $kargs['anchor'] : null;
$host = isset($kargs['host']) ? $kargs['host'] : null;
$protocol = isset($kargs['protocol']) ? $kargs['protocol'] : null;
$qualified = isset($kargs['qualified']) ? $kargs['qualified'] : null;
unset($kargs['qualified']);
// Remove special words from kargs, convert placeholders
foreach (array('anchor', 'host', 'protocol') as $key) {
if (array_key_exists($key, $kargs)) {
unset($kargs[$key]);
}
if (array_key_exists($key . '_', $kargs)) {
$kargs[$key] = $kargs[$key . '_'];
unset($kargs[$key . '_']);
}
}
$route = null;
$routeArgs = array();
$static = false;
$encoding = $this->mapper->encoding;
$environ = $this->mapper->environ;
$url = '';
if (isset($routeName)) {
if (isset($kargs['format']) && isset($this->mapper->routeNames['formatted_' . $routeName])) {
$route = $this->mapper->routeNames['formatted_' . $routeName];
} elseif (isset($this->mapper->routeNames[$routeName])) {
$route = $this->mapper->routeNames[$routeName];
}
if ($route && array_key_exists('_static', $route->defaults)) {
$static = true;
$url = $route->routePath;
}
// No named route found, assume the argument is a relative path
if ($route === null) {
$static = true;
$url = $routeName;
}
if ((substr($url, 0, 1) == '/') &&
isset($environ['SCRIPT_NAME'])) {
$url = $environ['SCRIPT_NAME'] . $url;
}
if ($static) {
if (!empty($kargs)) {
$url .= '?';
$query_args = array();
foreach ($kargs as $key => $val) {
$query_args[] = urlencode(utf8_decode($key)) . '=' .
urlencode(utf8_decode($val));
}
$url .= implode('&', $query_args);
}
}
}
if (! $static) {
if ($route) {
$routeArgs = array($route);
$newargs = $route->defaults;
foreach ($kargs as $key => $value) {
$newargs[$key] = $value;
}
// If this route has a filter, apply it
if (!empty($route->filter)) {
$newargs = call_user_func($route->filter, $newargs);
}
$newargs = $this->_subdomainCheck($newargs);
} else {
$newargs = $this->_screenArgs($kargs);
}
$anchor = (isset($newargs['_anchor'])) ? $newargs['_anchor'] : $anchor;
unset($newargs['_anchor']);
$host = (isset($newargs['_host'])) ? $newargs['_host'] : $host;
unset($newargs['_host']);
$protocol = (isset($newargs['_protocol'])) ? $newargs['_protocol'] : $protocol;
unset($newargs['_protocol']);
$url = $this->mapper->generate($routeArgs, $newargs);
}
if (!empty($anchor)) {
$url .= '#' . self::urlQuote($anchor, $encoding);
}
if (!empty($host) || !empty($qualified) || !empty($protocol)) {
$http_host = isset($environ['HTTP_HOST']) ? $environ['HTTP_HOST'] : null;
$server_name = isset($environ['SERVER_NAME']) ? $environ['SERVER_NAME'] : null;
$fullhost = !is_null($http_host) ? $http_host : $server_name;
if (empty($host) && empty($qualified)) {
$host = explode(':', $fullhost);
$host = $host[0];
} else if (empty($host)) {
$host = $fullhost;
}
if (empty($protocol)) {
if (!empty($environ['HTTPS']) && $environ['HTTPS'] != 'off') {
$protocol = 'https';
} else {
$protocol = 'http';
}
}
if ($url !== null) {
$url = $protocol . '://' . $host . $url;
}
}
return $url;
}
/**
* Issues a redirect based on the arguments.
*
* Redirects *should* occur as a "302 Moved" header, however the web
* framework may utilize a different method.
*
* All arguments are passed to urlFor() to retrieve the appropriate URL, then
* the resulting URL it sent to the redirect function as the URL.
*
* @param mixed $first First argument in varargs, same as urlFor()
* @param mixed $second Second argument in varargs
* @return mixed Result of redirect callback
*/
public function redirectTo($first = array(), $second = array())
{
$target = $this->urlFor($first, $second);
return call_user_func($this->redirect, $target);
}
/**
* Pretty-print a listing of the routes connected to the mapper.
*
* @param stream|null $stream Output stream for printing (optional)
* @param string|null $eol Line ending (optional)
* @return void
*/
public function printRoutes($stream = null, $eol = PHP_EOL)
{
$printer = new Horde_Routes_Printer($this->mapper);
$printer->printRoutes($stream, $eol);
}
/**
* Scan a directory for PHP files and use them as controllers. Used
* as the default scanner callback for Horde_Routes_Mapper. See the
* constructor of that class for more information.
*
* Given a directory with:
* foo.php, bar.php, baz.php
* Returns an array:
* foo, bar, baz
*
* @param string $dirname Directory to scan for controller files
* @param string $prefix Prefix controller names (optional)
* @return array Array of controller names
*/
public static function controllerScan($dirname = null, $prefix = '')
{
$controllers = array();
if ($dirname === null) {
return $controllers;
}
$baseregexp = preg_quote($dirname . DIRECTORY_SEPARATOR, '/');
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dirname)) as $entry) {
if (!$entry->isFile()) {
continue;
}
// Match .php files that don't start with an underscore
if (preg_match('/^[^_]{1,1}.*\.php$/', basename($entry->getFilename())) == 0) {
continue;
}
// Strip off base path: dirname/admin/users.php -> admin/users.php
$controller = preg_replace("/^$baseregexp(.*)\.php/", '\\1', $entry->getPathname());
// PrepareController -> prepare_controller -> prepare
$controller = Horde_String::lower(
preg_replace('/([a-z])([A-Z])/',
"\${1}_\${2}", $controller));
if (preg_match('/_controller$/', $controller)) {
$controller = substr($controller, 0, -(strlen('_controller')));
}
// Normalize directory separators.
$controller = str_replace(DIRECTORY_SEPARATOR, '/', $controller);
// Add to controller list.
$controllers[] = $prefix . $controller;
}
usort($controllers, array('Horde_Routes_Utils', 'longestFirst'));
return $controllers;
}
/**
* Private function that takes a dict, and screens it against the current
* request dict to determine what the dict should look like that is used.
* This is responsible for the requests "memory" of the current.
*/
private function _screenArgs($kargs)
{
if ($this->mapper->explicit && $this->mapper->subDomains) {
return $this->_subdomainCheck($kargs);
} else if ($this->mapper->explicit) {
return $kargs;
}
$controllerName = (isset($kargs['controller'])) ? $kargs['controller'] : null;
if (!empty($controllerName) && substr($controllerName, 0, 1) == '/') {
// If the controller name starts with '/', ignore route memory
$kargs['controller'] = substr($kargs['controller'], 1);
return $kargs;
} else if (!empty($controllerName) && !array_key_exists('action', $kargs)) {
// Fill in an action if we don't have one, but have a controller
$kargs['action'] = 'index';
}
$memoryKargs = $this->mapperDict;
// Remove keys from memory and kargs if kargs has them as null
foreach ($kargs as $key => $value) {
if ($value === null) {
unset($kargs[$key]);
if (array_key_exists($key, $memoryKargs)) {
unset($memoryKargs[$key]);
}
}
}
// Merge the new args on top of the memory args
foreach ($kargs as $key => $value) {
$memoryKargs[$key] = $value;
}
// Setup a sub-domain if applicable
if (!empty($this->mapper->subDomains)) {
$memoryKargs = $this->_subdomainCheck($memoryKargs);
}
return $memoryKargs;
}
/**
* Screen the kargs for a subdomain and alter it appropriately depending
* on the current subdomain or lack therof.
*/
private function _subdomainCheck($kargs)
{
if ($this->mapper->subDomains) {
$subdomain = (isset($kargs['subDomain'])) ? $kargs['subDomain'] : null;
unset($kargs['subDomain']);
$environ = $this->mapper->environ;
$http_host = isset($environ['HTTP_HOST']) ? $environ['HTTP_HOST'] : null;
$server_name = isset($environ['SERVER_NAME']) ? $environ['SERVER_NAME'] : null;
$fullhost = !is_null($http_host) ? $http_host : $server_name;
$hostmatch = explode(':', $fullhost);
$host = $hostmatch[0];
$port = '';
if (count($hostmatch) > 1) {
$port .= ':' . $hostmatch[1];
}
$subMatch = '^.+?\.(' . $this->mapper->domainMatch . ')$';
$domain = preg_replace("@$subMatch@", '$1', $host);
if ($subdomain && (substr($host, 0, strlen($subdomain)) != $subdomain)
&& (! in_array($subdomain, $this->mapper->subDomainsIgnore))) {
$kargs['_host'] = $subdomain . '.' . $domain . $port;
} else if (($subdomain === null || in_array($subdomain, $this->mapper->subDomainsIgnore))
&& $domain != $host) {
$kargs['_host'] = $domain . $port;
}
return $kargs;
} else {
return $kargs;
}
}
/**
* Quote a string containing a URL in a given encoding.
*
* @todo This is a placeholder. Multiple encodings aren't yet supported.
*
* @param string $url URL to encode
* @param string $encoding Encoding to use
*/
public static function urlQuote($url, $encoding = null)
{
if ($encoding === null) {
return str_replace('%2F', '/', urlencode($url));
} else {
return str_replace('%2F', '/', urlencode(utf8_decode($url)));
}
}
/**
* Callback used by usort() in controllerScan() to sort controller
* names by the longest first.
*
* @param string $fst First string to compare
* @param string $lst Last string to compare
* @return integer Difference of string length (first - last)
*/
public static function longestFirst($fst, $lst)
{
return strlen($lst) - strlen($fst);
}
/**
*/
public static function arraySubtract($a1, $a2)
{
foreach ($a2 as $key) {
if (in_array($key, $a1)) {
unset($a1[array_search($key, $a1)]);
}
}
return $a1;
}
}
Horde_Routes-2.0.5/test/Horde/Routes/fixtures/controllers/admin/users.php 0000664 0001750 0001750 00000000041 12654066370 024712 0 ustar jan jan run();
Horde_Routes-2.0.5/test/Horde/Routes/bootstrap.php 0000664 0001750 0001750 00000000143 12654066370 020262 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* @package Routes
*/
class Horde_Routes_GenerationTest extends PHPUnit_Framework_TestCase
{
public function testAllStaticNoReqs()
{
$m = new Horde_Routes_Mapper();
$m->connect('hello/world');
$this->assertEquals('/hello/world', $m->generate());
}
public function testBasicDynamic()
{
foreach (array('hi/:fred', 'hi/:(fred)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/hi/index', $m->generate(array('fred' => 'index')));
$this->assertEquals('/hi/show', $m->generate(array('fred' => 'show')));
$this->assertEquals('/hi/list+people', $m->generate(array('fred' => 'list people')));
$this->assertNull($m->generate());
}
}
public function testDynamicWithDefault()
{
foreach (array('hi/:action', 'hi/:(action)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/hi', $m->generate(array('action' => 'index')));
$this->assertEquals('/hi/show', $m->generate(array('action' => 'show')));
$this->assertEquals('/hi/list+people', $m->generate(array('action' => 'list people')));
$this->assertEquals('/hi', $m->generate());
}
}
/**
* Some of these assertions are invalidated in PHP, it passes in Python because
* unicode(None) == unicode('None'). In PHP, we don't have a function similar
* to unicode(). These have the comment "unicode false equiv"
*/
public function testDynamicWithFalseEquivs()
{
$m = new Horde_Routes_Mapper();
$m->connect('article/:page', array('page' => false));
$m->connect(':controller/:action/:id');
$this->assertEquals('/blog/view/0',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => '0')));
// unicode false equiv
// $this->assertEquals('/blog/view/0',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 0)));
//$this->assertEquals('/blog/view/False',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => false)));
$this->assertEquals('/blog/view/False',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 'False')));
$this->assertEquals('/blog/view',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => null)));
// unicode false equiv
// $this->assertEquals('/blog/view',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 'null')));
$this->assertEquals('/article',
$m->generate(array('page' => null)));
}
public function testDynamicWithUnderscoreParts()
{
$m = new Horde_Routes_Mapper();
$m->connect('article/:small_page', array('small_page' => false));
$m->connect(':(controller)/:(action)/:(id)');
$this->assertEquals('/blog/view/0',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => '0')));
// unicode false equiv
// $this->assertEquals('/blog/view/False',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => false)));
// unicode False Equiv
//$this->assertEquals('/blog/view',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 'null'))); */
$this->assertEquals('/article',
$m->generate(array('small_page' => null)));
$this->assertEquals('/article/hobbes',
$m->generate(array('small_page' => 'hobbes')));
}
public function testDynamicWithFalseEquivsAndSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('article/:(page)', array('page' => false));
$m->connect(':(controller)/:(action)/:(id)');
$this->assertEquals('/blog/view/0',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => '0')));
// unicode false equiv
// $this->assertEquals('/blog/view/0',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 0)));
// $this->assertEquals('/blog/view/False',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => false));
$this->assertEquals('/blog/view/False',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 'False')));
$this->assertEquals('/blog/view',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => null)));
// unicode false equiv
//$this->assertEquals('/blog/view',
// $m->generate(array('controller' => 'blog', 'action' => 'view', 'id' => 'null')));
$this->assertEquals('/article',
$m->generate(array('page' => null)));
$m = new Horde_Routes_Mapper();
$m->connect('view/:(home)/:(area)', array('home' => 'austere', 'area' => null));
$this->assertEquals('/view/sumatra',
$m->generate(array('home' => 'sumatra')));
$this->assertEquals('/view/austere/chicago',
$m->generate(array('area' => 'chicago')));
$m = new Horde_Routes_Mapper();
$m->connect('view/:(home)/:(area)', array('home' => null, 'area' => null));
$this->assertEquals('/view/null/chicago',
$m->generate(array('home' => null, 'area' => 'chicago')));
}
public function testDynamicWithRegExpCondition()
{
foreach (array('hi/:name', 'hi/:(name)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('requirements' => array('name' => '[a-z]+')));
$this->assertEquals('/hi/index', $m->generate(array('name' => 'index')));
$this->assertNull($m->generate(array('name' => 'fox5')));
$this->assertNull($m->generate(array('name' => 'something_is_up')));
$this->assertEquals('/hi/abunchofcharacter',
$m->generate(array('name' => 'abunchofcharacter')));
$this->assertNull($m->generate());
}
}
public function testDynamicWithDefaultAndRegexpCondition()
{
foreach (array('hi/:action', 'hi/:(action)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('requirements' => array('action' => '[a-z]+')));
$this->assertEquals('/hi', $m->generate(array('action' => 'index')));
$this->assertNull($m->generate(array('action' => 'fox5')));
$this->assertNull($m->generate(array('action' => 'something_is_up')));
$this->assertNull($m->generate(array('action' => 'list people')));
$this->assertEquals('/hi/abunchofcharacter',
$m->generate(array('action' => 'abunchofcharacter')));
$this->assertEquals('/hi', $m->generate());
}
}
public function testPath()
{
foreach (array('hi/*file', 'hi/*(file)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/hi',
$m->generate(array('file' => null)));
$this->assertEquals('/hi/books/learning_python.pdf',
$m->generate(array('file' => 'books/learning_python.pdf')));
$this->assertEquals('/hi/books/development%26whatever/learning_python.pdf',
$m->generate(array('file' => 'books/development&whatever/learning_python.pdf')));
}
}
public function testPathBackwards()
{
foreach (array('*file/hi', '*(file)/hi') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/hi',
$m->generate(array('file' => null)));
$this->assertEquals('/books/learning_python.pdf/hi',
$m->generate(array('file' => 'books/learning_python.pdf')));
$this->assertEquals('/books/development%26whatever/learning_python.pdf/hi',
$m->generate(array('file' => 'books/development&whatever/learning_python.pdf')));
}
}
public function testController()
{
foreach (array('hi/:controller', 'hi/:(controller)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/hi/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/hi/admin/user',
$m->generate(array('controller' => 'admin/user')));
}
}
public function testControllerWithStatic()
{
foreach (array('hi/:controller', 'hi/:(controller)') as $path) {
$m = new Horde_Routes_Mapper();
$utils = $m->utils;
$m->connect($path);
$m->connect('google', 'http://www.google.com', array('_static' => true));
$this->assertEquals('/hi/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/hi/admin/user',
$m->generate(array('controller' => 'admin/user')));
$this->assertEquals('http://www.google.com', $utils->urlFor('google'));
}
}
public function testStandardRoute()
{
foreach (array(':controller/:action/:id', ':(controller)/:(action)/:(id)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/content',
$m->generate(array('controller' => 'content', 'action' => 'index')));
$this->assertEquals('/content/list',
$m->generate(array('controller' => 'content', 'action' => 'list')));
$this->assertEquals('/content/show/10',
$m->generate(array('controller' => 'content', 'action' => 'show', 'id' => '10')));
$this->assertEquals('/admin/user',
$m->generate(array('controller' => 'admin/user', 'action' => 'index')));
$this->assertEquals('/admin/user/list',
$m->generate(array('controller' => 'admin/user', 'action' => 'list')));
$this->assertEquals('/admin/user/show/10',
$m->generate(array('controller' => 'admin/user', 'action' => 'show', 'id' => '10')));
}
}
public function testMultiroute()
{
$m = new Horde_Routes_Mapper();
$m->connect('archive/:year/:month/:day', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null,
'requirements' => array('month' => '\d{1,2}',
'day' => '\d{1,2}')));
$m->connect('viewpost/:id', array('controller' => 'post', 'action' => 'view'));
$m->connect(':controller/:action/:id');
$this->assertEquals('/blog/view?year=2004&month=blah',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004, 'month' => 'blah')));
$this->assertEquals('/archive/2004/11',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004, 'month' => 11)));
$this->assertEquals('/archive/2004/11',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004, 'month' => '11')));
$this->assertEquals('/archive/2004/11',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'year' => 2004, 'month' => 11)));
$this->assertEquals('/archive/2004', $m->generate(array('controller' => 'blog', 'action' => 'view', 'year' => 2004)));
$this->assertEquals('/viewpost/3',
$m->generate(array('controller' => 'post', 'action' => 'view', 'id' => 3)));
}
public function testMultirouteWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('archive/:(year)/:(month)/:(day)', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null,
'requirements' => array('month' => '\d{1,2}',
'day' => '\d{1,2}')));
$m->connect('viewpost/:(id)', array('controller' => 'post', 'action' => 'view'));
$m->connect(':(controller)/:(action)/:(id)');
$this->assertEquals('/blog/view?year=2004&month=blah',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004, 'month' => 'blah')));
$this->assertEquals('/archive/2004/11',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004, 'month' => 11)));
$this->assertEquals('/archive/2004/11',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004, 'month' => '11')));
$this->assertEquals('/archive/2004',
$m->generate(array('controller' => 'blog', 'action' => 'view', 'year' => 2004)));
$this->assertEquals('/viewpost/3',
$m->generate(array('controller' => 'post', 'action' => 'view', 'id' => 3)));
}
public function testBigMultiroute()
{
$m = new Horde_Routes_Mapper();
$m->connect('', array('controller' => 'articles', 'action' => 'index'));
$m->connect('admin', array('controller' => 'admin/general', 'action' => 'index'));
$m->connect('admin/comments/article/:article_id/:action/:id',
array('controller' => 'admin/comments', 'action' => null, 'id' => null));
$m->connect('admin/trackback/article/:article_id/:action/:id',
array('controller' => 'admin/trackback', 'action' => null, 'id' => null));
$m->connect('admin/content/:action/:id', array('controller' => 'admin/content'));
$m->connect('xml/:action/feed.xml', array('controller' => 'xml'));
$m->connect('xml/articlerss/:id/feed.xml', array('controller' => 'xml', 'action' => 'articlerss'));
$m->connect('index.rdf', array('controller' => 'xml', 'action' => 'rss'));
$m->connect('articles', array('controller' => 'articles', 'action' => 'index'));
$m->connect('articles/page/:page',
array('controller' => 'articles', 'action' => 'index',
'requirements' => array('page' => '\d+')));
$m->connect('articles/:year/:month/:day/page/:page',
array('controller' => 'articles', 'action' => 'find_by_date',
'month' => null, 'day' => null,
'requirements' => array('year' => '\d{4}', 'month' => '\d{1,2}',
'day' => '\d{1,2}')));
$m->connect('articles/category/:id', array('controller' => 'articles', 'action' => 'category'));
$m->connect('pages/*name', array('controller' => 'articles', 'action' => 'view_page'));
$this->assertEquals('/pages/the/idiot/has/spoken',
$m->generate(array('controller' => 'articles', 'action' => 'view_page',
'name' => 'the/idiot/has/spoken')));
$this->assertEquals('/',
$m->generate(array('controller' => 'articles', 'action' => 'index')));
$this->assertEquals('/xml/articlerss/4/feed.xml',
$m->generate(array('controller' => 'xml', 'action' => 'articlerss', 'id' => 4)));
$this->assertEquals('/xml/rss/feed.xml',
$m->generate(array('controller' => 'xml', 'action' => 'rss')));
$this->assertEquals('/admin/comments/article/4/view/2',
$m->generate(array('controller' => 'admin/comments', 'action' => 'view',
'article_id' => 4, 'id' => 2)));
$this->assertEquals('/admin',
$m->generate(array('controller' => 'admin/general')));
$this->assertEquals('/admin/comments/article/4/index',
$m->generate(array('controller' => 'admin/comments', 'article_id' => 4)));
$this->assertEquals('/admin/comments/article/4',
$m->generate(array('controller' => 'admin/comments', 'action' => null,
'article_id' => 4)));
$this->assertEquals('/articles/2004/2/20/page/1',
$m->generate(array('controller' => 'articles', 'action' => 'find_by_date',
'year' => 2004, 'month' => 2, 'day' => 20, 'page' => 1)));
$this->assertEquals('/articles/category',
$m->generate(array('controller' => 'articles', 'action' => 'category')));
$this->assertEquals('/xml/index/feed.xml',
$m->generate(array('controller' => 'xml')));
$this->assertEquals('/xml/articlerss/feed.xml',
$m->generate(array('controller' => 'xml', 'action' => 'articlerss')));
$this->assertNull($m->generate(array('controller' => 'admin/comments', 'id' => 2)));
$this->assertNull($m->generate(array('controller' => 'articles', 'action' => 'find_by_date',
'year' => 2004)));
}
public function testBigMultirouteWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('', array('controller' => 'articles', 'action' => 'index'));
$m->connect('admin', array('controller' => 'admin/general', 'action' => 'index'));
$m->connect('admin/comments/article/:(article_id)/:(action)/:(id)',
array('controller' => 'admin/comments', 'action' => null, 'id' => null));
$m->connect('admin/trackback/article/:(article_id)/:(action)/:(id)',
array('controller' => 'admin/trackback', 'action' => null, 'id' => null));
$m->connect('admin/content/:(action)/:(id)', array('controller' => 'admin/content'));
$m->connect('xml/:(action)/feed.xml', array('controller' => 'xml'));
$m->connect('xml/articlerss/:(id)/feed.xml', array('controller' => 'xml', 'action' => 'articlerss'));
$m->connect('index.rdf', array('controller' => 'xml', 'action' => 'rss'));
$m->connect('articles', array('controller' => 'articles', 'action' => 'index'));
$m->connect('articles/page/:(page)',
array('controller' => 'articles', 'action' => 'index',
'requirements' => array('page' => '\d+')));
$m->connect('articles/:(year)/:(month)/:(day)/page/:(page)',
array('controller' => 'articles', 'action' => 'find_by_date',
'month' => null, 'day' => null,
'requirements' => array('year' => '\d{4}', 'month' => '\d{1,2}',
'day' => '\d{1,2}')));
$m->connect('articles/category/:(id)', array('controller' => 'articles', 'action' => 'category'));
$m->connect('pages/*name', array('controller' => 'articles', 'action' => 'view_page'));
$this->assertEquals('/pages/the/idiot/has/spoken',
$m->generate(array('controller' => 'articles', 'action' => 'view_page',
'name' => 'the/idiot/has/spoken')));
$this->assertEquals('/',
$m->generate(array('controller' => 'articles', 'action' => 'index')));
$this->assertEquals('/xml/articlerss/4/feed.xml',
$m->generate(array('controller' => 'xml', 'action' => 'articlerss', 'id' => 4)));
$this->assertEquals('/xml/rss/feed.xml',
$m->generate(array('controller' => 'xml', 'action' => 'rss')));
$this->assertEquals('/admin/comments/article/4/view/2',
$m->generate(array('controller' => 'admin/comments', 'action' => 'view',
'article_id' => 4, 'id' => 2)));
$this->assertEquals('/admin',
$m->generate(array('controller' => 'admin/general')));
$this->assertEquals('/admin/comments/article/4/index',
$m->generate(array('controller' => 'admin/comments', 'article_id' => 4)));
$this->assertEquals('/admin/comments/article/4',
$m->generate(array('controller' => 'admin/comments', 'action' => null,
'article_id' => 4)));
$this->assertEquals('/articles/2004/2/20/page/1',
$m->generate(array('controller' => 'articles', 'action' => 'find_by_date',
'year' => 2004, 'month' => 2, 'day' => 20, 'page' => 1)));
$this->assertEquals('/articles/category',
$m->generate(array('controller' => 'articles', 'action' => 'category')));
$this->assertEquals('/xml/index/feed.xml',
$m->generate(array('controller' => 'xml')));
$this->assertEquals('/xml/articlerss/feed.xml',
$m->generate(array('controller' => 'xml', 'action' => 'articlerss')));
$this->assertNull($m->generate(array('controller' => 'admin/comments', 'id' => 2)));
$this->assertNull($m->generate(array('controller' => 'articles', 'action' => 'find_by_date',
'year' => 2004)));
}
public function testNoExtras()
{
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:id');
$m->connect('archive/:year/:month/:day', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null));
$this->assertEquals('/archive/2004',
$m->generate(array('controller' => 'blog', 'action' => 'view',
'year' => 2004)));
}
public function testNoExtrasWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect(':(controller)/:(action)/:(id)');
$m->connect('archive/:(year)/:(month)/:(day)', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null));
}
public function testTheSmallestRoute()
{
foreach (array('pages/:title', 'pages/:(title)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect('', array('controller' => 'page', 'action' => 'view', 'title' => 'HomePage'));
$m->connect($path, array('controller' => 'page', 'action' => 'view'));
$this->assertEquals('/pages/joe', $m->generate(array('controller' => 'page', 'action' => 'view', 'title' => 'joe')));
$this->assertEquals('/',
$m->generate(array('controller' => 'page', 'action' => 'view',
'title' => 'HomePage')));
}
}
public function testExtras()
{
$m = new Horde_Routes_Mapper();
$m->connect('viewpost/:id', array('controller' => 'post', 'action' => 'view'));
$m->connect(':controller/:action/:id');
$this->assertEquals('/viewpost/2?extra=x%2Fy',
$m->generate(array('controller' => 'post', 'action' => 'view',
'id' => 2, 'extra' => 'x/y')));
$this->assertEquals('/blog?extra=3',
$m->generate(array('controller' => 'blog', 'action' => 'index', 'extra' => 3)));
$this->assertEquals('/viewpost/2?extra=3',
$m->generate(array('controller' => 'post', 'action' => 'view',
'id' => 2, 'extra' => 3)));
}
public function testExtrasWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('viewpost/:(id)', array('controller' => 'post', 'action' => 'view'));
$m->connect(':(controller)/:(action)/:(id)');
$this->assertEquals('/viewpost/2?extra=x%2Fy',
$m->generate(array('controller' => 'post', 'action' => 'view',
'id' => 2, 'extra' => 'x/y')));
$this->assertEquals('/blog?extra=3',
$m->generate(array('controller' => 'blog', 'action' => 'index', 'extra' => 3)));
$this->assertEquals('/viewpost/2?extra=3',
$m->generate(array('controller' => 'post', 'action' => 'view',
'id' => 2, 'extra' => 3)));
}
public function testStatic()
{
$m = new Horde_Routes_Mapper();
$m->connect('hello/world', array('controller' => 'content', 'action' => 'index',
'known' => 'known_value'));
$this->assertEquals('/hello/world',
$m->generate(array('controller' => 'content', 'action' => 'index',
'known' => 'known_value')));
$this->assertEquals('/hello/world?extra=hi',
$m->generate(array('controller' => 'content', 'action' => 'index',
'known' => 'known_value', 'extra' => 'hi')));
$this->assertNull($m->generate(array('known' => 'foo')));
}
public function testTypical()
{
foreach (array(':controller/:action/:id', ':(controller)/:(action)/:(id)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('action' => 'index', 'id' => null));
$this->assertEquals('/content',
$m->generate(array('controller' => 'content', 'action' => 'index')));
$this->assertEquals('/content/list',
$m->generate(array('controller' => 'content', 'action' => 'list')));
$this->assertEquals('/content/show/10',
$m->generate(array('controller' => 'content', 'action' => 'show', 'id' => 10)));
$this->assertEquals('/admin/user',
$m->generate(array('controller' => 'admin/user', 'action' => 'index')));
$this->assertEquals('/admin/user',
$m->generate(array('controller' => 'admin/user')));
$this->assertEquals('/admin/user/show/10',
$m->generate(array('controller' => 'admin/user', 'action' => 'show', 'id' => 10)));
$this->assertEquals('/content', $m->generate(array('controller' => 'content')));
}
}
public function testRouteWithFixnumDefault()
{
$m = new Horde_Routes_Mapper();
$m->connect('page/:id', array('controller' => 'content', 'action' => 'show_page', 'id' => 1));
$m->connect(':controller/:action/:id');
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page')));
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => 1)));
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => '1')));
$this->assertEquals('/page/10',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => 10)));
$this->assertEquals('/blog/show/4',
$m->generate(array('controller' => 'blog', 'action' => 'show', 'id' => 4)));
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page')));
$this->assertEquals('/page/4',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => 4)));
$this->assertEquals('/content/show',
$m->generate(array('controller' => 'content', 'action' => 'show')));
}
public function testRouteWithFixnumDefaultWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('page/:(id)', array('controller' => 'content', 'action' => 'show_page', 'id' => 1));
$m->connect(':(controller)/:(action)/:(id)');
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page')));
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => 1)));
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => '1')));
$this->assertEquals('/page/10',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => 10)));
$this->assertEquals('/blog/show/4',
$m->generate(array('controller' => 'blog', 'action' => 'show', 'id' => 4)));
$this->assertEquals('/page',
$m->generate(array('controller' => 'content', 'action' => 'show_page')));
$this->assertEquals('/page/4',
$m->generate(array('controller' => 'content', 'action' => 'show_page', 'id' => 4)));
$this->assertEquals('/content/show',
$m->generate(array('controller' => 'content', 'action' => 'show')));
}
public function testUppercaseRecognition()
{
foreach (array(':controller/:action/:id', ':(controller)/:(action)/:(id)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$this->assertEquals('/Content',
$m->generate(array('controller' => 'Content', 'action' => 'index')));
$this->assertEquals('/Content/list',
$m->generate(array('controller' => 'Content', 'action' => 'list')));
$this->assertEquals('/Content/show/10',
$m->generate(array('controller' => 'Content', 'action' => 'show', 'id' => '10')));
$this->assertEquals('/Admin/NewsFeed',
$m->generate(array('controller' => 'Admin/NewsFeed', 'action' => 'index')));
}
}
public function testBackwards()
{
$m = new Horde_Routes_Mapper();
$m->connect('page/:id/:action', array('controller' => 'pages', 'action' => 'show'));
$m->connect(':controller/:action/:id');
$this->assertEquals('/page/20',
$m->generate(array('controller' => 'pages', 'action' => 'show', 'id' => 20)));
$this->assertEquals('/pages/boo',
$m->generate(array('controller' => 'pages', 'action' => 'boo')));
}
public function testBackwardsWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('page/:(id)/:(action)', array('controller' => 'pages', 'action' => 'show'));
$m->connect(':(controller)/:(action)/:(id)');
$this->assertEquals('/page/20',
$m->generate(array('controller' => 'pages', 'action' => 'show', 'id' => 20)));
$this->assertEquals('/pages/boo',
$m->generate(array('controller' => 'pages', 'action' => 'boo')));
}
public function testBothRequirementAndOptional()
{
$m = new Horde_Routes_Mapper();
$m->connect('test/:year', array('controller' => 'post', 'action' => 'show',
'year' => null, 'requirements' => array('year' => '\d{4}')));
$this->assertEquals('/test',
$m->generate(array('controller' => 'post', 'action' => 'show')));
$this->assertEquals('/test',
$m->generate(array('controller' => 'post', 'action' => 'show', 'year' => null)));
}
public function testSetToNilForgets()
{
$m = new Horde_Routes_Mapper();
$m->connect('pages/:year/:month/:day',
array('controller' => 'content', 'action' => 'list_pages',
'month' => null, 'day' => null));
$m->connect(':controller/:action/:id');
$this->assertEquals('/pages/2005',
$m->generate(array('controller' => 'content', 'action' => 'list_pages',
'year' => 2005)));
$this->assertEquals('/pages/2005/6',
$m->generate(array('controller' => 'content', 'action' => 'list_pages',
'year' => 2005, 'month' => 6)));
$this->assertEquals('/pages/2005/6/12',
$m->generate(array('controller' => 'content', 'action' => 'list_pages',
'year' => 2005, 'month' => 6, 'day' => 12)));
}
public function testUrlWithNoActionSpecified()
{
$m = new Horde_Routes_Mapper();
$m->connect('', array('controller' => 'content'));
$m->connect(':controller/:action/:id');
$this->assertEquals('/',
$m->generate(array('controller' => 'content', 'action' => 'index')));
$this->assertEquals('/',
$m->generate(array('controller' => 'content')));
}
public function testUrlWithPrefix()
{
$m = new Horde_Routes_Mapper();
$m->prefix = '/blog';
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/blog/content/view',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/blog/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/blog/admin/comments',
$m->generate(array('controller' => 'admin/comments')));
}
public function testUrlWithPrefixDeeper()
{
$m = new Horde_Routes_Mapper();
$m->prefix = '/blog/phil';
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/blog/phil/content/view',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/blog/phil/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/blog/phil/admin/comments',
$m->generate(array('controller' => 'admin/comments')));
}
public function testUrlWithEnvironEmpty()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '');
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/content/view',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/admin/comments',
$m->generate(array('controller' => 'admin/comments')));
}
public function testUrlWithEnviron()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '/blog');
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/blog/content/view',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/blog/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/blog/admin/comments',
$m->generate(array('controller' => 'admin/comments')));
$m->environ['SCRIPT_NAME'] = '/notblog';
$this->assertEquals('/notblog/content/view',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/notblog/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/notblog/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/notblog/admin/comments',
$m->generate(array('controller' => 'admin/comments')));
}
public function testUrlWithEnvironAndAbsolute()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '/blog');
$utils = $m->utils;
$m->connect('image', 'image/:name', array('_absolute' => true));
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/blog/content/view',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/blog/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/blog/content',
$m->generate(array('controller' => 'content')));
$this->assertEquals('/blog/admin/comments',
$m->generate(array('controller' => 'admin/comments')));
$this->assertEquals('/image/topnav.jpg',
$utils->urlFor('image', array('name' => 'topnav.jpg')));
}
public function testRouteWithOddLeftovers()
{
$m = new Horde_Routes_Mapper();
$m->environ = array();
$m->connect(':controller/:(action)-:(id)');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/content/view-',
$m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content/index-',
$m->generate(array('controller' => 'content')));
}
public function testRouteWithEndExtension()
{
$m = new Horde_Routes_Mapper();
$m->environ = array();
$m->connect(':controller/:(action)-:(id).html');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertNull($m->generate(array('controller' => 'content', 'action' => 'view')));
$this->assertNull($m->generate(array('controller' => 'content')));
$this->assertEquals('/content/view-3.html',
$m->generate(array('controller' => 'content', 'action' => 'view', 'id' => 3)));
$this->assertEquals('/content/index-2.html',
$m->generate(array('controller' => 'content', 'id' => 2)));
}
public function testResources()
{
$m = new Horde_Routes_Mapper();
$m->environ = array();
$utils = $m->utils;
$m->resource('message', 'messages');
$m->createRegs(array('messages'));
$options = array('controller' => 'messages');
$this->assertEquals('/messages',
$utils->urlFor('messages'));
$this->assertEquals('/messages.xml',
$utils->urlFor('messages', array('format' => 'xml')));
$this->assertEquals('/messages/1',
$utils->urlFor('message', array('id' => 1)));
$this->assertEquals('/messages/1.xml',
$utils->urlFor('message', array('id' => 1, 'format' => 'xml')));
$this->assertEquals('/messages/new',
$utils->urlFor('new_message'));
$this->assertEquals('/messages/1.xml',
$utils->urlFor('message', array('id' => 1, 'format' => 'xml')));
$this->assertEquals('/messages/1/edit',
$utils->urlFor('edit_message', array('id' => 1)));
$this->assertEquals('/messages/1/edit.xml',
$utils->urlFor('edit_message', array('id' => 1, 'format' => 'xml')));
$this->assertRestfulRoutes($m, $options);
}
public function testResourcesWithPathPrefix()
{
$m = new Horde_Routes_Mapper();
$m->resource('message', 'messages', array('pathPrefix' => '/thread/:threadid'));
$m->createRegs(array('messages'));
$options = array('controller' => 'messages', 'threadid' => '5');
$this->assertRestfulRoutes($m, $options, 'thread/5/');
}
public function testResourcesWithCollectionAction()
{
$m = new Horde_Routes_Mapper();
$utils = $m->utils;
$m->resource('message', 'messages', array('collection' => array('rss' => 'GET')));
$m->createRegs(array('messages'));
$options = array('controller' => 'messages');
$this->assertRestfulRoutes($m, $options);
$this->assertEquals('/messages/rss',
$m->generate(array('controller' => 'messages', 'action' => 'rss')));
$this->assertEquals('/messages/rss',
$utils->urlFor('rss_messages'));
$this->assertEquals('/messages/rss.xml',
$m->generate(array('controller' => 'messages', 'action' => 'rss',
'format' => 'xml')));
$this->assertEquals('/messages/rss.xml',
$utils->urlFor('formatted_rss_messages', array('format' => 'xml')));
}
public function testResourcesWithMemberAction()
{
foreach (array('put', 'post') as $method) {
$m = new Horde_Routes_Mapper();
$m->resource('message', 'messages', array('member' => array('mark' => $method)));
$m->createRegs(array('messages'));
$options = array('controller' => 'messages');
$this->assertRestfulRoutes($m, $options);
$connectkargs = array('method' => $method, 'action' => 'mark', 'id' => '1');
$this->assertEquals('/messages/1/mark',
$m->generate(array_merge($connectkargs, $options)));
$connectkargs = array('method' => $method, 'action' => 'mark',
'id' => '1', 'format' => 'xml');
$this->assertEquals('/messages/1/mark.xml',
$m->generate(array_merge($connectkargs, $options)));
}
}
public function testResourcesWithNewAction()
{
$m = new Horde_Routes_Mapper();
$utils = $m->utils;
$m->resource('message', 'messages/', array('new' => array('preview' => 'POST')));
$m->createRegs(array('messages'));
$this->assertRestfulRoutes($m, array('controller' => 'messages'));
$this->assertEquals('/messages/new/preview',
$m->generate(array('controller' => 'messages', 'action' => 'preview',
'method' => 'post')));
$this->assertEquals('/messages/new/preview',
$utils->urlFor('preview_new_message'));
$this->assertEquals('/messages/new/preview.xml',
$m->generate(array('controller' => 'messages', 'action' => 'preview',
'method' => 'post', 'format' => 'xml')));
$this->assertEquals('/messages/new/preview.xml',
$utils->urlFor('preview_new_message', array('format' => 'xml')));
}
public function testResourcesWithNamePrefix()
{
$m = new Horde_Routes_Mapper();
$utils = $m->utils;
$m->resource('message', 'messages', array('namePrefix' => 'category_',
'new' => array('preview' => 'POST')));
$m->createRegs(array('messages'));
$options = array('controller' => 'messages');
$this->assertRestfulRoutes($m, $options);
$this->assertEquals('/messages/new/preview',
$utils->urlFor('category_preview_new_message'));
$this->assertNull($utils->urlFor('category_preview_new_message', array('method' => 'get')));
}
public function testUnicode()
{
// php version does not handing decoding
}
public function testUnicodeStatic()
{
// php version does not handing decoding
}
public function testOtherSpecialChars()
{
$m = new Horde_Routes_Mapper();
$m->connect('/:year/:(slug).:(format),:(locale)', array('locale' => 'en', 'format' => 'html'));
$m->createRegs(array('content'));
$this->assertEquals('/2007/test',
$m->generate(array('year' => 2007, 'slug' => 'test')));
$this->assertEquals('/2007/test.xml',
$m->generate(array('year' => 2007, 'slug' => 'test', 'format' => 'xml')));
$this->assertEquals('/2007/test.xml,ja',
$m->generate(array('year' => 2007, 'slug' => 'test', 'format' => 'xml',
'locale' => 'ja')));
$this->assertNull($m->generate(array('year' => 2007, 'format' => 'html')));
}
// Test Helpers
public function assertRestfulRoutes($m, $options, $pathPrefix = '')
{
$baseroute = '/' . $pathPrefix . $options['controller'];
$this->assertEquals($baseroute,
$m->generate(array_merge($options, array('action' => 'index'))));
$this->assertEquals($baseroute . '.xml',
$m->generate(array_merge($options, array('action' => 'index',
'format' => 'xml'))));
$this->assertEquals($baseroute . '/new',
$m->generate(array_merge($options, array('action' => 'new'))));
$this->assertEquals($baseroute . '/1',
$m->generate(array_merge($options, array('action' => 'show',
'id' => '1'))));
$this->assertEquals($baseroute . '/1/edit',
$m->generate(array_merge($options, array('action' => 'edit',
'id' => '1'))));
$this->assertEquals($baseroute . '/1.xml',
$m->generate(array_merge($options, array('action' => 'show',
'id' => '1',
'format' => 'xml'))));
$this->assertEquals($baseroute,
$m->generate(array_merge($options, array('action' => 'create',
'method' => 'post'))));
$this->assertEquals($baseroute . '/1',
$m->generate(array_merge($options, array('action' => 'update',
'method' => 'put',
'id' => '1'))));
$this->assertEquals($baseroute . '/1',
$m->generate(array_merge($options, array('action' => 'delete',
'method' => 'delete',
'id' => '1'))));
}
}
Horde_Routes-2.0.5/test/Horde/Routes/phpunit.xml 0000664 0001750 0001750 00000000056 12654066370 017750 0 ustar jan jan
Horde_Routes-2.0.5/test/Horde/Routes/RecognitionTest.php 0000664 0001750 0001750 00000135620 12654066370 021376 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* @package Routes
*/
class Horde_Routes_RecognitionTest extends PHPUnit_Framework_TestCase
{
public function testRegexpCharEscaping()
{
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:(action).:(id)');
$m->createRegs(array('content'));
$this->assertNull($m->match('/content/view#2'));
$matchdata = array('action' => 'view', 'controller' => 'content', 'id' => '2');
$this->assertEquals($matchdata, $m->match('/content/view.2'));
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'find.all'));
$matchdata = array('action' => 'view#2', 'controller' => 'content', 'id' => null);
$this->assertEquals($matchdata, $m->match('/content/view#2'));
$matchdata = array('action' => 'view', 'controller' => 'find.all', 'id'=> null);
$this->assertEquals($matchdata, $m->match('/find.all/view'));
$this->assertNull($m->match('/findzall/view'));
}
public function testAllStatic()
{
$m = new Horde_Routes_Mapper();
$m->connect('hello/world/how/are/you', array('controller' => 'content', 'action' => 'index'));
$m->createRegs(array());
$this->assertNull($m->match('/x'));
$this->assertNull($m->match('/hello/world/how'));
$this->assertNull($m->match('/hello/world/how/are'));
$this->assertNull($m->match('/hello/world/how/are/you/today'));
$matchdata = array('controller' => 'content', 'action' =>'index');
$this->assertEquals($matchdata, $m->match('/hello/world/how/are/you'));
}
public function testUnicode()
{
// php version does not handing decoding
}
public function testDisablingUnicode()
{
// php version does not handing decoding
}
public function testBasicDynamic()
{
foreach(array('hi/:name', 'hi/:(name)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content'));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$this->assertNull($m->match('/hi/dude/what'));
$matchdata = array('controller' => 'content', 'name' => 'dude', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi/dude'));
$this->assertEquals($matchdata, $m->match('/hi/dude/'));
}
}
public function testBasicDynamicBackwards()
{
foreach (array(':name/hi', ':(name)/hi') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$m->createRegs();
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/hi'));
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/shop/walmart/hi'));
$matchdata = array('name' => 'fred', 'action' => 'index', 'controller' => 'content');
$this->assertEquals($matchdata, $m->match('/fred/hi'));
$matchdata = array('name' => 'index', 'action' => 'index', 'controller' => 'content');
$this->assertEquals($matchdata, $m->match('/index/hi'));
}
}
public function testDynamicWithUnderscores()
{
$m = new Horde_Routes_Mapper();
$m->connect('article/:small_page', array('small_page' => false));
$m->connect(':(controller)/:(action)/:(id)');
$m->createRegs(array('article', 'blog'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '0');
$this->assertEquals($matchdata, $m->match('/blog/view/0'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/view'));
}
public function testDynamicWithDefault()
{
foreach (array('hi/:action', 'hi/:(action)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content'));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi/dude/what'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi/index'));
$matchdata = array('controller' => 'content', 'action' => 'dude');
$this->assertEquals($matchdata, $m->match('/hi/dude'));
}
}
public function testDynamicWithDefaultBackwards()
{
foreach (array(':action/hi', ':(action)/hi') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content'));
$m->createRegs();
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/index/hi'));
$this->assertEquals($matchdata, $m->match('/index/hi/'));
$matchdata = array('controller' => 'content', 'action' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/hi'));
}
}
public function testDynamicWithStringCondition()
{
foreach (array(':name/hi', ':(name)/hi') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content',
'requirements' => array('name' => 'index')));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$this->assertNull($m->match('/dude/what/hi'));
$matchdata = array('controller' => 'content', 'name' => 'index', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/index/hi'));
$this->assertNull($m->match('/dude/hi'));
}
}
public function testDynamicWithStringConditionBackwards()
{
foreach (array('hi/:name', 'hi/:(name)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content',
'requirements' => array('name' => 'index')));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$this->assertNull($m->match('/hi/dude/what'));
$matchdata = array('controller' => 'content', 'name' => 'index', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi/index'));
$this->assertEquals($matchdata, $m->match('/hi/index'));
$this->assertNull($m->match('/dude/hi'));
}
}
public function testDynamicWithRegexpCondition()
{
foreach (array('hi/:name', 'hi/:(name)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content',
'requirements' => array('name' => '[a-z]+')));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$this->assertNull($m->match('/hi/FOXY'));
$this->assertNull($m->match('/hi/138708jkhdf'));
$this->assertNull($m->match('/hi/dkjfl8792343dfsf'));
$this->assertNull($m->match('/hi/dude/what'));
$this->assertNull($m->match('/hi/dude/what/'));
$matchdata = array('controller' => 'content', 'name' => 'index', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi/index'));
$matchdata = array('controller' => 'content', 'name' => 'dude', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi/dude'));
}
}
public function testDynamicWithRegexpAndDefault()
{
foreach (array('hi/:action', 'hi/:(action)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content',
'requirements' => array('action' => '[a-z]+')));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi/FOXY'));
$this->assertNull($m->match('/hi/138708jkhdf'));
$this->assertNull($m->match('/hi/dkjfl8792343dfsf'));
$this->assertNull($m->match('/hi/dude/what/'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi'));
$this->assertEquals($matchdata, $m->match('/hi/index'));
$matchdata = array('controller' => 'content', 'action' => 'dude');
$this->assertEquals($matchdata, $m->match('/hi/dude'));
}
}
public function testDynamicWithDefaultAndStringConditionBackwards()
{
foreach (array(':action/hi', ':(action)/hi') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$m->createRegs();
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$matchdata = array('action' => 'index', 'controller' => 'content');
$this->assertEquals($matchdata, $m->match('/index/hi'));
}
}
public function testDynamicAndControllerWithStringAndDefaultBackwards()
{
foreach (array(':controller/:action/hi', ':(controller)/:(action)/hi') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content'));
$m->createRegs(array('content', 'admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/fred'));
}
}
public function testMultiroute()
{
$m = new Horde_Routes_Mapper();
$m->connect('archive/:year/:month/:day', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null,
'requirements' => array('month' => '\d{1,2}',
'day' => '\d{1,2}')));
$m->connect('viewpost/:id', array('controller' => 'post', 'action' => 'view'));
$m->connect(':controller/:action/:id');
$m->createRegs(array('post','blog','admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/archive'));
$this->assertNull($m->match('/archive/2004/ab'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/view'));
$matchdata = array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null, 'year' => '2004');
$this->assertEquals($matchdata, $m->match('/archive/2004'));
$matchdata = array('controller' => 'blog', 'action' => 'view',
'month' => '4', 'day' => null, 'year' =>'2004');
$this->assertEquals($matchdata, $m->match('/archive/2004/4'));
}
public function testMultirouteWithSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('archive/:(year)/:(month)/:(day)', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null,
'requirements' => array('month' => '\d{1,2}',
'day' => '\d{1,2}')));
$m->connect('viewpost/:(id)', array('controller' => 'post', 'action' => 'view'));
$m->connect(':(controller)/:(action)/:(id)');
$m->createRegs(array('post','blog','admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/archive'));
$this->assertNull($m->match('/archive/2004/ab'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/view'));
$matchdata = array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null, 'year' => '2004');
$this->assertEquals($matchdata, $m->match('/archive/2004'));
$matchdata = array('controller' => 'blog', 'action' => 'view',
'month' => '4', 'day' => null, 'year' => '2004');
$this->assertEquals($matchdata, $m->match('/archive/2004/4'));
}
public function testDynamicWithRegexpDefaultsAndGaps()
{
$m = new Horde_Routes_Mapper();
$m->connect('archive/:year/:month/:day', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null,
'requirements' => array('month' => '\d{1,2}')));
$m->connect('view/:id/:controller', array('controller' => 'blog', 'action' => 'view',
'id' => 2, 'requirements' => array('id' => '\d{1,2}')));
$m->createRegs(array('post','blog','admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/archive'));
$this->assertNull($m->match('/archive/2004/haha'));
$this->assertNull($m->match('/view/blog'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
$this->assertEquals($matchdata, $m->match('/view'));
$matchdata = array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null, 'year' => '2004');
$this->assertEquals($matchdata, $m->match('/archive/2004'));
}
public function testDynamicWithRegexpDefaultsAndGapsAndSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('archive/:(year)/:(month)/:(day)', array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null,
'requirements' => array('month' => '\d{1,2}')));
$m->connect('view/:(id)/:(controller)', array('controller' => 'blog', 'action' => 'view',
'id' => 2, 'requirements' => array('id' => '\d{1,2}')));
$m->createRegs(array('post','blog','admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/archive'));
$this->assertNull($m->match('/archive/2004/haha'));
$this->assertNull($m->match('/view/blog'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
$this->assertEquals($matchdata, $m->match('/view'));
$matchdata = array('controller' => 'blog', 'action' => 'view',
'month' => null, 'day' => null, 'year' => '2004');
$this->assertEquals($matchdata, $m->match('/archive/2004'));
}
public function testDynamicWithRegexpGapsControllers()
{
foreach(array('view/:id/:controller', 'view/:(id)/:(controller)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('id' => 2, 'action' => 'view', 'requirements' => array('id' => '\d{1,2}')));
$m->createRegs(array('post', 'blog', 'admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/view'));
$this->assertNull($m->match('/view/blog'));
$this->assertNull($m->match('/view/3'));
$this->assertNull($m->match('/view/4/honker'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
$this->assertEquals($matchdata, $m->match('/view/2/blog'));
}
}
public function testDynamicWithTrailingStrings()
{
foreach (array('view/:id/:controller/super', 'view/:(id)/:(controller)/super') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'blog', 'action' => 'view',
'id' => 2, 'requirements' => array('id' => '\d{1,2}')));
$m->createRegs(array('post', 'blog', 'admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/view'));
$this->assertNull($m->match('/view/blah/blog/super'));
$this->assertNull($m->match('/view/ha/super'));
$this->assertNull($m->match('/view/super'));
$this->assertNull($m->match('/view/4/super'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
$this->assertEquals($matchdata, $m->match('/view/2/blog/super'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view', 'id' => '4');
$this->assertEquals($matchdata, $m->match('/view/4/admin/user/super'));
}
}
public function testDynamicWithTrailingNonKeywordStrings()
{
$m = new Horde_Routes_Mapper();
$m->connect('somewhere/:over/rainbow', array('controller' => 'blog'));
$m->connect('somewhere/:over', array('controller' => 'post'));
$m->createRegs(array('post', 'blog', 'admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/somewhere'));
$matchdata = array('controller' => 'blog', 'action' => 'index', 'over' => 'near');
$this->assertEquals($matchdata, $m->match('/somewhere/near/rainbow'));
$matchdata = array('controller' => 'post', 'action' => 'index', 'over' => 'tomorrow');
$this->assertEquals($matchdata, $m->match('/somewhere/tomorrow'));
}
public function testDynamicWithTrailingDynamicDefaults()
{
foreach (array('archives/:action/:article', 'archives/:(action)/:(article)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'blog'));
$m->createRegs(array('blog'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/archives'));
$this->assertNull($m->match('/archives/introduction'));
$this->assertNull($m->match('/archives/sample'));
$this->assertNull($m->match('/view/super'));
$this->assertNull($m->match('/view/4/super'));
$matchdata = array('controller' => 'blog', 'action' => 'view', 'article' => 'introduction');
$this->assertEquals($matchdata, $m->match('/archives/view/introduction'));
$matchdata = array('controller' => 'blog', 'action' => 'edit', 'article' => 'recipes');
$this->assertEquals($matchdata, $m->match('/archives/edit/recipes'));
}
}
public function testPath()
{
foreach (array('hi/*file', 'hi/*(file)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content', 'action' => 'download'));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi'));
$matchdata = array('controller' => 'content', 'action' => 'download',
'file' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/hi/books/learning_python.pdf'));
$matchdata = array('controller' => 'content', 'action' => 'download',
'file' => 'dude');
$this->assertEquals($matchdata, $m->match('/hi/dude'));
$matchdata = array('controller' => 'content', 'action' => 'download',
'file' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/hi/dude/what'));
}
}
public function testDynamicWithPath()
{
foreach (array(':controller/:action/*url', ':(controller)/:(action)/*(url)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path);
$m->createRegs(array('content', 'admin/user'));
$this->assertNull($m->match('/'));
$this->assertNull($m->match('/blog'));
$this->assertNull($m->match('/content'));
$this->assertNull($m->match('/content/view'));
$matchdata = array('controller' => 'content', 'action' => 'view', 'url' => 'blob');
$this->assertEquals($matchdata, $m->match('/content/view/blob'));
$this->assertNull($m->match('/admin/user'));
$this->assertNull($m->match('/admin/user/view'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view',
'url' => 'blob/check');
$this->assertEquals($matchdata, $m->match('/admin/user/view/blob/check'));
}
}
public function testPathWithDynamicAndDefault()
{
foreach (array(':controller/:action/*url', ':(controller)/:(action)/*(url)') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content', 'action' => 'view', 'url' => null));
$m->createRegs(array('content', 'admin/user'));
$this->assertNull($m->match('/goober/view/here'));
$matchdata = array('controller' => 'content', 'action' => 'view', 'url' => null);
$this->assertEquals($matchdata, $m->match('/content'));
$this->assertEquals($matchdata, $m->match('/content/'));
$this->assertEquals($matchdata, $m->match('/content/view'));
$matchdata = array('controller' => 'content', 'action' => 'view', 'url' => 'fred');
$this->assertEquals($matchdata, $m->match('/content/view/fred'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => null);
$this->assertEquals($matchdata, $m->match('/admin/user'));
$this->assertEquals($matchdata, $m->match('/admin/user/view'));
}
}
public function testPathWithDynamicAndDefaultBackwards()
{
foreach (array('*file/login', '*(file)/login') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content', 'action' => 'download', 'file' => null));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$matchdata = array('controller' => 'content', 'action' => 'download', 'file' => '');
$this->assertEquals($matchdata, $m->match('//login'));
$matchdata = array('controller' => 'content', 'action' => 'download',
'file' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
$matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/login'));
$matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/dude/what/login'));
}
}
public function testPathBackwards()
{
foreach (array('*file/login', '*(file)/login') as $path) {
$m = new Horde_Routes_Mapper();
$m->connect($path, array('controller' => 'content', 'action' => 'download'));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/login'));
$matchdata = array('controller' => 'content', 'action' => 'download',
'file' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
$matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/login'));
$matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/dude/what/login'));
}
}
public function testPathBackwardsWithController()
{
$m = new Horde_Routes_Mapper();
$m->connect('*url/login', array('controller' => 'content', 'action' => 'check_access'));
$m->connect('*url/:controller', array('action' => 'view'));
$m->createRegs(array('content', 'admin/user'));
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/login'));
$matchdata = array('controller' => 'content', 'action' => 'check_access',
'url' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
$matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/login'));
$matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/dude/what/login'));
$this->assertNull($m->match('/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view',
'url' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/dude/what/admin/user'));
}
public function testPathBackwardsWithControllerAndSplits()
{
$m = new Horde_Routes_Mapper();
$m->connect('*(url)/login', array('controller' => 'content', 'action' => 'check_access'));
$m->connect('*(url)/:(controller)', array('action' => 'view'));
$m->createRegs(array('content', 'admin/user'));
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/login'));
$matchdata = array('controller' => 'content', 'action' => 'check_access',
'url' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
$matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/login'));
$matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/dude/what/login'));
$this->assertNull($m->match('/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view',
'url' => 'books/learning_python.pdf');
$this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude');
$this->assertEquals($matchdata, $m->match('/dude/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude/what');
$this->assertEquals($matchdata, $m->match('/dude/what/admin/user'));
}
public function testController()
{
$m = new Horde_Routes_Mapper();
$m->connect('hi/:controller', array('action' => 'hi'));
$m->createRegs(array('content', 'admin/user'));
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi/13870948'));
$this->assertNull($m->match('/hi/content/dog'));
$this->assertNull($m->match('/hi/admin/user/foo'));
$this->assertNull($m->match('/hi/admin/user/foo/'));
$matchdata = array('controller' => 'content', 'action' => 'hi');
$this->assertEquals($matchdata, $m->match('/hi/content'));
$matchdata = array('controller' => 'admin/user', 'action' => 'hi');
$this->assertEquals($matchdata, $m->match('/hi/admin/user'));
}
public function testStandardRoute()
{
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'admin/user'));
$matchdata = array('controller' => 'content', 'action' => 'index', 'id' => null);
$this->assertEquals($matchdata, $m->match('/content'));
$matchdata = array('controller' => 'content', 'action' => 'list', 'id' => null);
$this->assertEquals($matchdata, $m->match('/content/list'));
$matchdata = array('controller' => 'content', 'action' => 'show', 'id' => '10');
$this->assertEquals($matchdata, $m->match('/content/show/10'));
$matchdata = array('controller' => 'admin/user', 'action' => 'index', 'id' => null);
$this->assertEquals($matchdata, $m->match('/admin/user'));
$matchdata = array('controller' => 'admin/user', 'action' => 'list', 'id' => null);
$this->assertEquals($matchdata, $m->match('/admin/user/list'));
$matchdata = array('controller' => 'admin/user', 'action' => 'show', 'id' => 'bbangert');
$this->assertEquals($matchdata, $m->match('/admin/user/show/bbangert'));
$this->assertNull($m->match('/content/show/10/20'));
$this->assertNull($m->match('/food'));
}
public function testStandardRouteWithGaps()
{
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:(id).py');
$m->createRegs(array('content', 'admin/user'));
$matchdata = array('controller' => 'content', 'action' => 'index', 'id' => 'None');
$this->assertEquals($matchdata, $m->match('/content/index/None.py'));
$matchdata = array('controller' =>'content', 'action' => 'list', 'id' => 'None');
$this->assertEquals($matchdata, $m->match('/content/list/None.py'));
$matchdata = array('controller' => 'content', 'action' => 'show', 'id' => '10');
$this->assertEquals($matchdata, $m->match('/content/show/10.py'));
}
public function testStandardRouteWithGapsAndDomains()
{
$m = new Horde_Routes_Mapper();
$m->connect('manage/:domain.:ext', array('controller' => 'admin/user', 'action' => 'view',
'ext' => 'html'));
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'admin/user'));
$matchdata = array('controller' => 'content', 'action' => 'index', 'id' => 'None.py');
$this->assertEquals($matchdata, $m->match('/content/index/None.py'));
$matchdata = array('controller' => 'content', 'action' => 'list', 'id' => 'None.py');
$this->assertEquals($matchdata, $m->match('/content/list/None.py'));
$matchdata = array('controller' => 'content', 'action' => 'show', 'id' => '10.py');
$this->assertEquals($matchdata, $m->match('/content/show/10.py'));
$matchdata = array('controller' => 'content', 'action' => 'show.all', 'id' => '10.py');
$this->assertEquals($matchdata, $m->match('/content/show.all/10.py'));
$matchdata = array('controller' => 'content', 'action' => 'show', 'id' => 'www.groovie.org');
$this->assertEquals($matchdata, $m->match('/content/show/www.groovie.org'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view',
'ext' => 'html', 'domain' => 'groovie');
$this->assertEquals($matchdata, $m->match('/manage/groovie'));
$matchdata = array('controller' => 'admin/user', 'action' => 'view',
'ext' => 'xml', 'domain' => 'groovie');
$this->assertEquals($matchdata, $m->match('/manage/groovie.xml'));
}
public function testStandardWithDomains()
{
$m = new Horde_Routes_Mapper();
$m->connect('manage/:domain', array('controller' => 'domains', 'action' => 'view'));
$m->createRegs(array('domains'));
$matchdata = array('controller' => 'domains', 'action' => 'view', 'domain' => 'www.groovie.org');
$this->assertEquals($matchdata, $m->match('/manage/www.groovie.org'));
}
public function testDefaultRoute()
{
$m = new Horde_Routes_Mapper();
$m->connect('', array('controller' => 'content', 'action' => 'index'));
$m->createRegs(array('content'));
$this->assertNull($m->match('/x'));
$this->assertNull($m->match('/hello/world'));
$this->assertNull($m->match('/hello/world/how/are'));
$this->assertNull($m->match('/hello/world/how/are/you/today'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/'));
}
public function testDynamicWithPrefix()
{
$m = new Horde_Routes_Mapper();
$m->prefix = '/blog';
$m->connect(':controller/:action/:id');
$m->connect('', array('controller' => 'content', 'action' => 'index'));
$m->createRegs(array('content', 'archive', 'admin/comments'));
$this->assertNull($m->match('/x'));
$this->assertNull($m->match('/admin/comments'));
$this->assertNull($m->match('/content/view'));
$this->assertNull($m->match('/archive/view/4'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/blog'));
$matchdata = array('controller' => 'content', 'action' => 'index', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/content'));
$matchdata = array('controller' => 'admin/comments', 'action' => 'view', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/admin/comments/view'));
$matchdata = array('controller' => 'archive', 'action' => 'index', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/archive'));
$matchdata = array('controller' => 'archive', 'action' => 'view', 'id' => '4');
$this->assertEquals($matchdata, $m->match('/blog/archive/view/4'));
}
public function testDynamicWithMultipleAndPrefix()
{
$m = new Horde_Routes_Mapper();
$m->prefix = '/blog';
$m->connect(':controller/:action/:id');
$m->connect('home/:action', array('controller' => 'archive'));
$m->connect('', array('controller' => 'content'));
$m->createRegs(array('content', 'archive', 'admin/comments'));
$this->assertNull($m->match('/x'));
$this->assertNull($m->match('/admin/comments'));
$this->assertNull($m->match('/content/view'));
$this->assertNull($m->match('/archive/view/4'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/blog/'));
$matchdata = array('controller' => 'archive', 'action' => 'view');
$this->assertEquals($matchdata, $m->match('/blog/home/view'));
$matchdata = array('controller' => 'content', 'action' => 'index', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/content'));
$matchdata = array('controller' => 'admin/comments', 'action' => 'view', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/admin/comments/view'));
$matchdata = array('controller' => 'archive', 'action' => 'index', 'id' => null);
$this->assertEquals($matchdata, $m->match('/blog/archive'));
$matchdata = array('controller' => 'archive', 'action' => 'view', 'id' => '4');
$this->assertEquals($matchdata, $m->match('/blog/archive/view/4'));
}
public function testSplitsWithExtension()
{
$m = new Horde_Routes_Mapper();
$m->connect('hi/:(action).html', array('controller' => 'content'));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/boo/blah'));
$this->assertNull($m->match('/hi/dude/what'));
$this->assertNull($m->match('/hi'));
$matchdata = array('controller' => 'content', 'action' => 'index');
$this->assertEquals($matchdata, $m->match('/hi/index.html'));
$matchdata = array('controller' => 'content', 'action' => 'dude');
$this->assertEquals($matchdata, $m->match('/hi/dude.html'));
}
public function testSplitsWithDashes()
{
$m = new Horde_Routes_Mapper();
$m->connect('archives/:(year)-:(month)-:(day).html',
array('controller' => 'archives', 'action' => 'view'));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/archives'));
$matchdata = array('controller' => 'archives', 'action' => 'view',
'year' => '2004', 'month' => '12', 'day' => '4');
$this->assertEquals($matchdata, $m->match('/archives/2004-12-4.html'));
$matchdata = array('controller' => 'archives', 'action' => 'view',
'year' => '04', 'month' => '10', 'day' => '4');
$this->assertEquals($matchdata, $m->match('/archives/04-10-4.html'));
$matchdata = array('controller' => 'archives', 'action' => 'view',
'year' => '04', 'month' => '1', 'day' => '1');
$this->assertEquals($matchdata, $m->match('/archives/04-1-1.html'));
}
public function testSplitsPackedWithRegexps()
{
$m = new Horde_Routes_Mapper();
$m->connect('archives/:(year):(month):(day).html',
array('controller' => 'archives', 'action' => 'view',
'requirements' => array('year' => '\d{4}', 'month' => '\d{2}',
'day' => '\d{2}')));
$m->createRegs();
$this->assertNull($m->match('/boo'));
$this->assertNull($m->match('/archives'));
$this->assertNull($m->match('/archives/2004020.html'));
$this->assertNull($m->match('/archives/200502.html'));
$matchdata = array('controller' => 'archives', 'action' => 'view',
'year' => '2004', 'month' => '12', 'day' => '04');
$this->assertEquals($matchdata, $m->match('/archives/20041204.html'));
$matchdata = array('controller' => 'archives', 'action' => 'view',
'year' => '2005', 'month' => '10', 'day' => '04');
$this->assertEquals($matchdata, $m->match('/archives/20051004.html'));
$matchdata = array('controller' => 'archives', 'action' => 'view',
'year' => '2006', 'month' => '01', 'day' => '01');
$this->assertEquals($matchdata, $m->match('/archives/20060101.html'));
}
public function testSplitsWithSlashes()
{
$m = new Horde_Routes_Mapper();
$m->connect(':name/:(action)-:(day)', array('controller' => 'content'));
$this->assertNull($m->match('/something'));
$this->assertNull($m->match('/something/is-'));
$matchdata = array('controller' => 'content', 'action' => 'view',
'day' => '3', 'name' => 'group');
$this->assertEquals($matchdata, $m->match('/group/view-3'));
$matchdata = array('controller' => 'content', 'action' => 'view',
'day' => '5', 'name' => 'group');
$this->assertEquals($matchdata, $m->match('/group/view-5'));
}
public function testSplitsWithSlashesAndDefault()
{
$m = new Horde_Routes_Mapper();
$m->connect(':name/:(action)-:(id)', array('controller' => 'content'));
$m->createRegs();
$this->assertNull($m->match('/something'));
$this->assertNull($m->match('/something/is'));
$matchdata = array('controller' => 'content', 'action' => 'view',
'id' => '3', 'name' => 'group');
$this->assertEquals($matchdata, $m->match('/group/view-3'));
$matchdata = array('controller' => 'content', 'action' => 'view',
'id' => null, 'name' => 'group');
$this->assertEquals($matchdata, $m->match('/group/view-'));
}
public function testNoRegMake()
{
$m = new Horde_Routes_Mapper();
$m->connect(':name/:(action)-:(id)', array('controller' => 'content'));
$m->controllerScan = false;
try {
$m->match('/group/view-3');
$this->fail();
} catch (Horde_Routes_Exception $e) {
$this->assertRegExp('/must generate the regular expressions/i', $e->getMessage());
}
}
public function testRoutematch()
{
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:id');
$m->createRegs(array('content'));
$route = $m->matchList[0];
list($resultdict, $resultObj) = $m->routematch('/content');
$this->assertEquals(array('controller' => 'content', 'action' => 'index', 'id' => null),
$resultdict);
$this->assertSame($route, $resultObj);
$this->assertNull($m->routematch('/nowhere'));
}
public function testRoutematchDebug()
{
$m = new Horde_Routes_Mapper();
$m->connect(':controller/:action/:id');
$m->debug = true;
$m->createRegs(array('content'));
$route = $m->matchList[0];
list($resultdict, $resultObj, $debug) = $m->routematch('/content');
$this->assertEquals(array('controller' => 'content', 'action' => 'index', 'id' => null),
$resultdict);
$this->assertSame($route, $resultObj);
list($resultdict, $resultObj, $debug) = $m->routematch('/nowhere');
$this->assertNull($resultdict);
$this->assertNull($resultObj);
$this->assertEquals(1, count($debug));
}
public function testMatchDebug()
{
$m = new Horde_Routes_Mapper();
$m->connect('nowhere', 'http://nowhere.com/', array('_static' => true));
$m->connect(':controller/:action/:id');
$m->debug = true;
$m->createRegs(array('content'));
$route = $m->matchList[1];
list($resultdict, $resultObj, $debug) = $m->match('/content');
$this->assertEquals(array('controller' => 'content', 'action' => 'index', 'id' => null),
$resultdict);
$this->assertSame($route, $resultObj);
list($resultdict, $resultObj, $debug) = $m->match('/nowhere');
$this->assertNull($resultdict);
$this->assertNull($resultObj);
$this->assertEquals(2, count($debug));
}
public function testResourceCollection()
{
$m = new Horde_Routes_Mapper();
$m->resource('message', 'messages');
$m->createRegs(array('messages'));
$path = '/messages';
$m->environ = array('REQUEST_METHOD' => 'GET');
$this->assertEquals(array('controller' => 'messages', 'action' => 'index'),
$m->match($path));
$m->environ = array('REQUEST_METHOD' => 'POST');
$this->assertEquals(array('controller' => 'messages', 'action' => 'create'),
$m->match($path));
}
public function testFormattedResourceCollection()
{
$m = new Horde_Routes_Mapper();
$m->resource('message', 'messages');
$m->createRegs(array('messages'));
$path = '/messages.xml';
$m->environ = array('REQUEST_METHOD' => 'GET');
$this->assertEquals(array('controller' => 'messages', 'action' => 'index',
'format' => 'xml'),
$m->match($path));
$m->environ = array('REQUEST_METHOD' => 'POST');
$this->assertEquals(array('controller' => 'messages', 'action' => 'create',
'format' => 'xml'),
$m->match($path));
}
public function testResourceMember()
{
$m = new Horde_Routes_Mapper();
$m->resource('message', 'messages');
$m->createRegs(array('messages'));
$path = '/messages/42';
$m->environ = array('REQUEST_METHOD' => 'GET');
$this->assertEquals(array('controller' => 'messages', 'action' => 'show',
'id' => 42),
$m->match($path));
$m->environ = array('REQUEST_METHOD' => 'POST');
$this->assertNull($m->match($path));
$m->environ = array('REQUEST_METHOD' => 'PUT');
$this->assertEquals(array('controller' => 'messages', 'action' => 'update',
'id' => 42),
$m->match($path));
$m->environ = array('REQUEST_METHOD' => 'DELETE');
$this->assertEquals(array('controller' => 'messages', 'action' => 'delete',
'id' => 42),
$m->match($path));
}
public function testFormattedResourceMember()
{
$m = new Horde_Routes_Mapper();
$m->resource('message', 'messages');
$m->createRegs(array('messages'));
$path = '/messages/42.xml';
$m->environ = array('REQUEST_METHOD' => 'GET');
$this->assertEquals(array('controller' => 'messages', 'action' => 'show',
'id' => 42, 'format' => 'xml'),
$m->match($path));
$m->environ = array('REQUEST_METHOD' => 'POST');
$this->assertNull($m->match($path));
$m->environ = array('REQUEST_METHOD' => 'PUT');
$this->assertEquals(array('controller' => 'messages', 'action' => 'update',
'id' => 42, 'format' => 'xml'),
$m->match($path));
$m->environ = array('REQUEST_METHOD' => 'DELETE');
$this->assertEquals(array('controller' => 'messages', 'action' => 'delete',
'id' => 42, 'format' => 'xml'),
$m->match($path));
}
}
Horde_Routes-2.0.5/test/Horde/Routes/TestHelper.php 0000664 0001750 0001750 00000002216 12654066370 020327 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
/**
* @package Routes
*/
class Horde_Routes_TestHelper
{
/**
* Update a Mapper instance with a new $environ. If PATH_INFO
* is present, try to match it and update mapperDict.
*
* @param Horde_Routes_Mapper $mapper Mapper instance to update
* @param array $environ Environ to set in Mapper
* @return void
*/
public static function updateMapper($mapper, $environ)
{
$mapper->environ = $environ;
$mapper->utils->mapperdict = null;
if (isset($environ['PATH_INFO'])) {
$result = $mapper->routeMatch($environ['PATH_INFO']);
$mapper->utils->mapperDict = isset($result) ? $result[0] : null;
}
}
}
Horde_Routes-2.0.5/test/Horde/Routes/UtilTest.php 0000664 0001750 0001750 00000065542 12654066370 020040 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
require_once __DIR__ . '/TestHelper.php';
/**
* @package Routes
*/
class Horde_Routes_UtilTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('HTTP_HOST' => 'www.test.com');
$m->connect('archive/:year/:month/:day',
array('controller' => 'blog',
'action' => 'view',
'month' => null,
'day' => null,
'requirements' => array('month' => '\d{1,2}', 'day' => '\d{1,2}')));
$m->connect('viewpost/:id', array('controller' => 'post', 'action' => 'view'));
$m->connect(':controller/:action/:id');
$this->mapper = $m;
$this->utils = $m->utils;
}
public function testUrlForSelf()
{
$utils = $this->utils;
$utils->mapperDict = array();
$this->assertEquals('/blog', $utils->urlFor(array('controller' => 'blog')));
$this->assertEquals('/content', $utils->urlFor());
$this->assertEquals('https://www.test.com/viewpost', $utils->urlFor(array('controller' => 'post', 'action' => 'view', 'protocol' => 'https')));
$this->assertEquals('http://www.test.org/content/view/2', $utils->urlFor(array('host' => 'www.test.org', 'controller' => 'content', 'action' => 'view', 'id' => 2)));
}
public function testUrlForWithDefaults()
{
$utils = $this->utils;
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'id' => 4);
$this->assertEquals('/blog/view/4', $utils->urlFor());
$this->assertEquals('/post/index/4', $utils->urlFor(array('controller' => 'post')));
$this->assertEquals('/blog/view/2', $utils->urlFor(array('id' => 2)));
$this->assertEquals('/viewpost/4', $utils->urlFor(array('controller' => 'post', 'action' => 'view', 'id' => 4)));
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'year' => 2004);
$this->assertEquals('/archive/2004/10', $utils->urlFor(array('month' => 10)));
$this->assertEquals('/archive/2004/9/2', $utils->urlFor(array('month' => 9, 'day' => 2)));
$this->assertEquals('/blog', $utils->urlFor(array('controller' => 'blog', 'year' => null)));
}
public function testUrlForWithMoreDefaults()
{
$utils = $this->utils;
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'id' => 4);
$this->assertEquals('/blog/view/4', $utils->urlFor());
$this->assertEquals('/post/index/4', $utils->urlFor(array('controller' => 'post')));
$this->assertEquals('/viewpost/4', $utils->urlfor(array('controller' => 'post', 'action' => 'view', 'id' => 4)));
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'year' => 2004);
$this->assertEquals('/archive/2004/10', $utils->urlFor(array('month' => 10)));
$this->assertEquals('/archive/2004/9/2', $utils->urlFor(array('month' => 9, 'day' => 2)));
$this->assertEquals('/blog', $utils->urlFor(array('controller' => 'blog', 'year' => null)));
$this->assertEquals('/archive/2004', $utils->urlFor());
}
public function testUrlForWithDefaultsAndQualified()
{
$m = $this->mapper;
$utils = $m->utils;
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section', array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'www.example.com',
'PATH_INFO' => '/blog/view/4');
Horde_Routes_TestHelper::updateMapper($m, $environ);
$this->assertEquals('/blog/view/4', $utils->urlFor());
$this->assertEquals('/post/index/4', $utils->urlFor(array('controller' => 'post')));
$this->assertEquals('http://www.example.com/blog/view/4', $utils->urlFor(array('qualified' => true)));
$this->assertEquals('/blog/view/2', $utils->urlFor(array('id' => 2)));
$this->assertEquals('/viewpost/4', $utils->urlFor(array('controller' => 'post', 'action' => 'view', 'id' => 4)));
$environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'www.example.com:8080', 'PATH_INFO' => '/blog/view/4');
Horde_Routes_TestHelper::updateMapper($m, $environ);
$this->assertEquals('/post/index/4',
$utils->urlFor(array('controller' => 'post')));
$this->assertEquals('http://www.example.com:8080/blog/view/4',
$utils->urlFor(array('qualified' => true)));
}
public function testWithRouteNames()
{
$m = $this->mapper;
$utils = $this->utils;
$utils->mapperDict = array();
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content',
$utils->urlFor(array('controller' => 'content')));
$this->assertEquals('/admin/comments',
$utils->urlFor(array('controller' => 'admin/comments')));
$this->assertEquals('/category',
$utils->urlFor('category_home'));
$this->assertEquals('/category/food',
$utils->urlFor('category_home', array('section' => 'food')));
$this->assertNull($utils->urlFor('home', array('action' => 'view', 'section' => 'home')));
$this->assertNull($utils->urlFor('home', array('controller' => 'content')));
$this->assertEquals('/',
$utils->urlFor('/'));
}
public function testWithRouteNamesAndDefaults()
{
$m = $this->mapper;
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section', array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->connect('building', 'building/:campus/:building/alljacks', array('controller' => 'building', 'action' => 'showjacks'));
$m->createRegs(array('content', 'blog', 'admin/comments', 'building'));
$utils->mapperDict = array('controller' => 'building', 'action' => 'showjacks', 'campus' => 'wilma', 'building' => 'port');
$this->assertEquals('/building/wilma/port/alljacks', $utils->urlFor());
$this->assertEquals('/', $utils->urlFor('home'));
}
// callback used by testRedirectTo
// Python version is inlined in test_redirect_to
public function printer($echo)
{
$this->redirectToResult = $echo;
}
public function testRedirectTo()
{
$m = $this->mapper;
$m->environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'www.example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$callback = array($this, 'printer');
$utils->redirect = $callback;
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->redirectToResult = null;
$utils->redirectTo(array('controller' => 'content', 'action' => 'view'));
$this->assertEquals('/content/view', $this->redirectToResult);
$this->redirectToResult = null;
$utils->redirectTo(array('controller' => 'content', 'action' => 'lookup', 'id' => 4));
$this->assertEquals('/content/lookup/4', $this->redirectToResult);
$this->redirectToResult = null;
$utils->redirectTo(array('controller' => 'admin/comments', 'action' => 'splash'));
$this->assertEquals('/admin/comments/splash', $this->redirectToResult);
$this->redirectToResult = null;
$utils->redirectTo('http://www.example.com/');
$this->assertEquals('http://www.example.com/', $this->redirectToResult);
$this->redirectToResult = null;
$utils->redirectTo('/somewhere.html', array('var' => 'keyword'));
$this->assertEquals('/somewhere.html?var=keyword', $this->redirectToResult);
}
public function testStaticRoute()
{
$m = $this->mapper;
$utils = $m->utils;
$utils->mapperDict = array();
$environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'example.com');
Horde_Routes_TestHelper::updateMapper($m, $environ);
$m->connect(':controller/:action/:id');
$m->connect('home', 'http://www.groovie.org/', array('_static' => true));
$m->connect('space', '/nasa/images', array('_static' => true));
$m->createRegs(array('content', 'blog'));
$this->assertEquals('http://www.groovie.org/',
$utils->urlFor('home'));
$this->assertEquals('http://www.groovie.org/?s=stars',
$utils->urlFor('home', array('s' => 'stars')));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/nasa/images?search=all',
$utils->urlFor('space', array('search' => 'all')));
}
public function testStaticRouteWithScript()
{
$m = $this->mapper;
$m->environ = array('SCRIPT_NAME' => '/webapp', 'HTTP_HOST' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect(':controller/:action/:id');
$m->connect('home', 'http://www.groovie.org/', array('_static' => true));
$m->connect('space', '/nasa/images', array('_static' => true));
$m->createRegs(array('content', 'blog'));
$this->assertEquals('http://www.groovie.org/',
$utils->urlFor('home'));
$this->assertEquals('http://www.groovie.org/?s=stars',
$utils->urlFor('home', array('s' => 'stars')));
$this->assertEquals('/webapp/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/webapp/nasa/images?search=all',
$utils->urlFor('space', array('search' => 'all')));
$this->assertEquals('http://example.com/webapp/nasa/images',
$utils->urlFor('space', array('protocol' => 'http')));
}
public function testNoNamedPath()
{
$m = $this->mapper;
$m->environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect(':controller/:action/:id');
$m->connect('home', 'http://www.groovie.org', array('_static' => true));
$m->connect('space', '/nasa/images', array('_static' => true));
$m->createRegs(array('content', 'blog'));
$this->assertEquals('http://www.google.com/search',
$utils->urlFor('http://www.google.com/search'));
$this->assertEquals('http://www.google.com/search?q=routes',
$utils->urlFor('http://www.google.com/search', array('q'=>'routes')));
$this->assertEquals('/delicious.jpg',
$utils->urlFor('/delicious.jpg'));
$this->assertEquals('/delicious/search?v=routes',
$utils->urlFor('/delicious/search', array('v'=>'routes')));
}
public function testAppendSlash()
{
$m = $this->mapper;
$m->environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'example.com');
$m->appendSlash = true;
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect(':controller/:action/:id');
$m->connect('home', 'http://www.groovie.org/', array('_static' => true));
$m->connect('space', '/nasa/images', array('_static' => true));
$m->createRegs(array('content', 'blog'));
$this->assertEquals('http://www.google.com/search',
$utils->urlFor('http://www.google.com/search'));
$this->assertEquals('http://www.google.com/search?q=routes',
$utils->urlFor('http://www.google.com/search', array('q'=>'routes')));
$this->assertEquals('/delicious.jpg',
$utils->urlFor('/delicious.jpg'));
$this->assertEquals('/delicious/search?v=routes',
$utils->urlFor('/delicious/search', array('v' => 'routes')));
$this->assertEquals('/content/list/',
$utils->urlFor(array('controller' => '/content', 'action' => 'list')));
$this->assertEquals('/content/list/?page=1',
$utils->urlFor(array('controller' => '/content', 'action' => 'list', 'page' => '1')));
}
public function testNoNamedPathWithScript()
{
$m = $this->mapper;
$m->environ = array('SCRIPT_NAME' => '/webapp', 'HTTP_HOST' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect(':controller/:action/:id');
$m->connect('home', 'http://www.groovie.org/', array('_static' => true));
$m->connect('space', '/nasa/images', array('_static' => true));
$m->createRegs(array('content', 'blog'));
$this->assertEquals('http://www.google.com/search',
$utils->urlFor('http://www.google.com/search'));
$this->assertEquals('http://www.google.com/search?q=routes',
$utils->urlFor('http://www.google.com/search', array('q'=>'routes')));
$this->assertEquals('/webapp/delicious.jpg',
$utils->urlFor('/delicious.jpg'));
$this->assertEquals('/webapp/delicious/search?v=routes',
$utils->urlFor('/delicious/search', array('v'=>'routes')));
}
// callback used by testRouteFilter
// Python version is inlined in test_route_filter
public function articleFilter($kargs)
{
$article = isset($kargs['article']) ? $kargs['article'] : null;
unset($kargs['article']);
if ($article !== null) {
$kargs['year'] = isset($article['year']) ? $article['year'] : 2004;
$kargs['month'] = isset($article['month']) ? $article['month'] : 12;
$kargs['day'] = isset($article['day']) ? $article['day'] : 20;
$kargs['slug'] = isset($article['slug']) ? $article['slug'] : 'default';
}
return $kargs;
}
public function testRouteFilter()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$callback = array($this, 'articleFilter');
$m->connect(':controller/:(action)-:(id).html');
$m->connect('archives', 'archives/:year/:month/:day/:slug',
array('controller' =>'archives', 'action' =>'view', '_filter' => $callback));
$m->createRegs(array('content', 'archives', 'admin/comments'));
$this->assertNull($utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertNull($utils->urlFor(array('controller' => 'content')));
$this->assertEquals('/content/view-3.html',
$utils->urlFor(array('controller' => 'content', 'action' => 'view', 'id' => 3)));
$this->assertEquals('/content/index-2.html',
$utils->urlFor(array('controller' => 'content', 'id' => 2)));
$this->assertEquals('/archives/2005/10/5/happy',
$utils->urlFor('archives', array('year' => 2005, 'month' => 10,
'day' => 5, 'slug' => 'happy')));
$story = array('year' => 2003, 'month' => 8, 'day' => 2, 'slug' => 'woopee');
$empty = array();
$expected = array('controller' => 'archives', 'action' => 'view', 'year' => '2005',
'month' => '10', 'day' => '5', 'slug' => 'happy');
$this->assertEquals($expected, $m->match('/archives/2005/10/5/happy'));
$this->assertEquals('/archives/2003/8/2/woopee',
$utils->urlFor('archives', array('article' => $story)));
$this->assertEquals('/archives/2004/12/20/default',
$utils->urlFor('archives', array('article' => $empty)));
}
public function testWithSslEnviron()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'HTTPS' => 'on', 'SERVER_PORT' => '443',
'PATH_INFO' => '/', 'HTTP_HOST' => 'example.com',
'SERVER_NAME' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'archives', 'admin/comments'));
// HTTPS is on, but we're running on a different port internally
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content/index/2',
$utils->urlFor(array('controller' => 'content', 'id' => 2)));
$this->assertEquals('https://nowhere.com/content',
$utils->urlFor(array('host' => 'nowhere.com', 'controller' => 'content')));
// If HTTPS is on, but the port isn't 443, we'll need to include the port info
$m->environ['SERVER_PORT'] = '8080';
$utils->mapperDict = array();
$this->assertEquals('/content/index/2',
$utils->urlFor(array('controller' => 'content', 'id' => '2')));
$this->assertEquals('https://nowhere.com/content',
$utils->urlFor(array('host' => 'nowhere.com', 'controller' => 'content')));
$this->assertEquals('https://nowhere.com:8080/content',
$utils->urlFor(array('host' => 'nowhere.com:8080', 'controller' => 'content')));
$this->assertEquals('http://nowhere.com/content',
$utils->urlFor(array('host' => 'nowhere.com', 'protocol' => 'http',
'controller' => 'content')));
}
public function testWithHttpEnviron()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'SERVER_PORT' => '1080', 'PATH_INFO' => '/',
'HTTP_HOST' => 'example.com', 'SERVER_NAME' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'archives', 'admin/comments'));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content/index/2',
$utils->urlFor(array('controller' => 'content', 'id' => 2)));
$this->assertEquals('https://example.com/content',
$utils->urlFor(array('protocol' => 'https', 'controller' => 'content')));
}
public function testSubdomains()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'PATH_INFO' => '/',
'HTTP_HOST' => 'example.com', 'SERVER_NAME' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->subDomains = true;
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'archives', 'admin/comments'));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content/index/2',
$utils->urlFor(array('controller' => 'content', 'id' => 2)));
$m->environ['HTTP_HOST'] = 'sub.example.com';
$utils->mapperDict = array('subDomain' => 'sub');
$this->assertEquals('/content/view/3',
$utils->urlFor(array('controller' => 'content', 'action' => 'view', 'id' => 3)));
$this->assertEquals('http://new.example.com/content',
$utils->urlFor(array('controller' => 'content', 'subDomain' => 'new')));
}
public function testSubdomainsWithExceptions()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'PATH_INFO' => '/',
'HTTP_HOST' => 'example.com', 'SERVER_NAME' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->subDomains = true;
$m->subDomainsIgnore = array('www');
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'archives', 'admin/comments'));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content/index/2',
$utils->urlFor(array('controller' => 'content', 'id' => 2)));
$m->environ = array('HTTP_HOST' => 'sub.example.com');
$utils->mapperDict = array('subDomain' => 'sub');
$this->assertEquals('/content/view/3',
$utils->urlFor(array('controller' => 'content', 'action' => 'view', 'id' => 3)));
$this->assertEquals('http://new.example.com/content',
$utils->urlFor(array('controller' => 'content', 'subDomain' => 'new')));
$this->assertEquals('http://example.com/content',
$utils->urlFor(array('controller' => 'content', 'subDomain' => 'www')));
$utils->mapperDict = array('subDomain' => 'www');
$this->assertEquals('http://example.com/content/view/3',
$utils->urlFor(array('controller' => 'content', 'action' => 'view', 'id' => 3)));
$this->assertEquals('http://new.example.com/content',
$utils->urlFor(array('controller' => 'content', 'subDomain' => 'new')));
$this->assertEquals('/content',
$utils->urlFor(array('controller' => 'content', 'subDomain' => 'sub')));
}
public function testSubdomainsWithNamedRoutes()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'PATH_INFO' => '/',
'HTTP_HOST' => 'example.com', 'SERVER_NAME' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->subDomains = true;
$m->connect(':controller/:action/:id');
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->connect('building', 'building/:campus/:building/alljacks',
array('controller' => 'building', 'action' => 'showjacks'));
$m->createRegs(array('content','blog','admin/comments','building'));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/content/index/2',
$utils->urlFor(array('controller' => 'content', 'id' => 2)));
$this->assertEquals('/category',
$utils->urlFor('category_home'));
$this->assertEquals('http://new.example.com/category',
$utils->urlFor('category_home', array('subDomain' => 'new')));
}
public function testSubdomainsWithPorts()
{
$m = new Horde_Routes_Mapper();
$m->environ = array('SCRIPT_NAME' => '', 'PATH_INFO' => '/',
'HTTP_HOST' => 'example.com:8000', 'SERVER_NAME' => 'example.com');
$utils = $m->utils;
$utils->mapperDict = array();
$m->subDomains = true;
$m->connect(':controller/:action/:id');
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->connect('building', 'building/:campus/:building/alljacks',
array('controller' => 'building', 'action' => 'showjacks'));
$m->createRegs(array('content', 'blog', 'admin/comments', 'building'));
$this->assertEquals('/content/view',
$utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertEquals('/category',
$utils->urlFor('category_home'));
$this->assertEquals('http://new.example.com:8000/category',
$utils->urlFor('category_home', array('subDomain' => 'new')));
$this->assertEquals('http://joy.example.com:8000/building/west/merlot/alljacks',
$utils->urlFor('building', array('campus' => 'west', 'building' => 'merlot',
'subDomain' => 'joy')));
$m->environ = array('HTTP_HOST' => 'example.com');
$this->assertEquals('http://new.example.com/category',
$utils->urlFor('category_home', array('subDomain' => 'new')));
}
public function testControllerScan()
{
$hereDir = __DIR__;
$controllerDir = "$hereDir/fixtures/controllers";
$controllers = Horde_Routes_Utils::controllerScan($controllerDir);
$this->assertEquals(3, count($controllers));
$this->assertEquals('admin/users', $controllers[0]);
$this->assertEquals('content', $controllers[1]);
$this->assertEquals('users', $controllers[2]);
}
public function testAutoControllerScan()
{
$hereDir = __DIR__;
$controllerDir = "$hereDir/fixtures/controllers";
$m = new Horde_Routes_Mapper(array('directory' => $controllerDir));
$m->alwaysScan = true;
$m->connect(':controller/:action/:id');
$expected = array('action' => 'index', 'controller' => 'content', 'id' => null);
$this->assertEquals($expected, $m->match('/content'));
$expected = array('action' => 'index', 'controller' => 'users', 'id' => null);
$this->assertEquals($expected, $m->match('/users'));
$expected = array('action' => 'index', 'controller' => 'admin/users', 'id' => null);
$this->assertEquals($expected, $m->match('/admin/users'));
}
}
Horde_Routes-2.0.5/test/Horde/Routes/UtilWithExplicitTest.php 0000664 0001750 0001750 00000025224 12654066370 022367 0 ustar jan jan
* @license http://www.horde.org/licenses/bsd BSD
* @package Routes
*/
require_once __DIR__ . '/TestHelper.php';
/**
* @package Routes
*/
class Horde_Routes_UtilWithExplicitTest extends PHPUnit_Framework_TestCase {
public function setUp()
{
$m = new Horde_Routes_Mapper(array('explicit' => true));
$m->connect('archive/:year/:month/:day',
array('controller' => 'blog',
'action' => 'view',
'month' => null,
'day' => null,
'requirements' => array('month' => '\d{1,2}', 'day' => '\d{1,2}')));
$m->connect('viewpost/:id', array('controller' => 'post', 'action' => 'view', 'id' => null));
$m->connect(':controller/:action/:id');
$m->environ = array('SERVER_NAME' => 'www.test.com');
$this->mapper = $m;
$this->utils = $m->utils;
}
public function testUrlFor()
{
$utils = $this->utils;
$utils->mapperDict = array();
$this->assertNull($utils->urlFor(array('controller' => 'blog')));
$this->assertNull($utils->urlFor());
$this->assertEquals('/blog/view/3',
$utils->urlFor(array('controller' => 'blog', 'action' => 'view',
'id' => 3)));
$this->assertEquals('https://www.test.com/viewpost',
$utils->urlFor(array('controller' => 'post', 'action' => 'view',
'protocol' => 'https')));
$this->assertEquals('http://www.test.org/content/view/2',
$utils->urlFor(array('host' => 'www.test.org', 'controller' => 'content',
'action' => 'view', 'id' => 2)));
$m = $this->mapper;
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertEquals('/content/splash/2',
$utils->urlFor(array('controller' => 'content', 'action' => 'splash',
'id' => 2)));
}
public function testUrlForWithDefaults()
{
$utils = $this->utils;
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'id' => 4);
$this->assertNull($utils->urlFor());
$this->assertNull($utils->urlFor(array('controller' => 'post')));
$this->assertNull($utils->urlFor(array('id' => 2)));
$this->assertEquals('/viewpost/4',
$utils->urlFor(array('controller' => 'post', 'action' => 'view',
'id' => 4)));
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'year' => 2004);
$this->assertNull($utils->urlFor(array('month' => 10)));
$this->assertNull($utils->urlFor(array('month' => 9, 'day' => 2)));
$this->assertNull($utils->urlFor(array('controller' => 'blog', 'year' => null)));
}
public function testUrlForWithMoreDefaults()
{
$utils = $this->utils;
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'id' => 4);
$this->assertNull($utils->urlFor());
$this->assertNull($utils->urlFor(array('controller' => 'post')));
$this->assertNull($utils->urlFor(array('id' => 2)));
$this->assertEquals('/viewpost/4',
$utils->urlFor(array('controller' => 'post', 'action' => 'view',
'id' => 4)));
$utils->mapperDict = array('controller' => 'blog', 'action' => 'view', 'year' => 2004);
$this->assertNull($utils->urlFor(array('month' => 10)));
$this->assertNull($utils->urlFor());
}
public function testUrlForWithDefaultsAndQualified()
{
$utils = $this->utils;
$m = $this->mapper;
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->connect(':controller/:action/:id');
$m->createRegs(array('content', 'blog', 'admin/comments'));
$environ = array('SCRIPT_NAME' => '', 'SERVER_NAME' => 'www.example.com',
'SERVER_PORT' => '80', 'PATH_INFO' => '/blog/view/4');
Horde_Routes_TestHelper::updateMapper($m, $environ);
$this->assertNull($utils->urlFor());
$this->assertNull($utils->urlFor(array('controller' => 'post')));
$this->assertNull($utils->urlFor(array('id' => 2)));
$this->assertNull($utils->urlFor(array('qualified' => true, 'controller' => 'blog', 'id' => 4)));
$this->assertEquals('http://www.example.com/blog/view/4',
$utils->urlFor(array('qualified' => true, 'controller' => 'blog',
'action' => 'view', 'id' => 4)));
$this->assertEquals('/viewpost/4',
$utils->urlFor(array('controller' => 'post', 'action' => 'view', 'id' => 4)));
$environ = array('SCRIPT_NAME' => '', 'HTTP_HOST' => 'www.example.com:8080', 'PATH_INFO' => '/blog/view/4');
Horde_Routes_TestHelper::updateMapper($m, $environ);
$this->assertNull($utils->urlFor(array('controller' => 'post')));
$this->assertEquals('http://www.example.com:8080/blog/view/4',
$utils->urlFor(array('qualified' => true, 'controller' => 'blog',
'action' => 'view', 'id' => 4)));
}
public function testWithRouteNames()
{
$m = $this->mapper;
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->createRegs(array('content', 'blog', 'admin/comments'));
$this->assertNull($utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertNull($utils->urlFor(array('controller' => 'content')));
$this->assertNull($utils->urlFor(array('controller' => 'admin/comments')));
$this->assertEquals('/category',
$utils->urlFor('category_home'));
$this->assertEquals('/category/food',
$utils->urlFor('category_home', array('section' => 'food')));
$this->assertNull($utils->urlFor('home', array('action' => 'view', 'section' => 'home')));
$this->assertNull($utils->urlFor('home', array('controller' => 'content')));
$this->assertEquals('/', $utils->urlFor('home'));
}
public function testWithRouteNamesAndDefaults()
{
$m = $this->mapper;
$utils = $m->utils;
$utils->mapperDict = array();
$m->connect('home', '', array('controller' => 'blog', 'action' => 'splash'));
$m->connect('category_home', 'category/:section',
array('controller' => 'blog', 'action' => 'view', 'section' => 'home'));
$m->connect('building', 'building/:campus/:building/alljacks',
array('controller' => 'building', 'action' => 'showjacks'));
$m->createRegs(array('content', 'blog', 'admin/comments', 'building'));
$utils->mapperDict = array('controller' => 'building', 'action' => 'showjacks',
'campus' => 'wilma', 'building' => 'port');
$this->assertNull($utils->urlFor());
$this->assertEquals('/building/wilma/port/alljacks',
$utils->urlFor(array('controller' => 'building', 'action' => 'showjacks',
'campus' => 'wilma', 'building' => 'port')));
$this->assertEquals('/', $utils->urlFor('home'));
}
public function testWithResourceRouteNames()
{
$m = new Horde_Routes_Mapper();
$utils = $m->utils;
$utils->mapperDict = array();
$m->resource('message', 'messages',
array('member' => array('mark' => 'GET'),
'collection' => array('rss' => 'GET')));
$m->createRegs(array('messages'));
$this->assertNull($utils->urlFor(array('controller' => 'content', 'action' => 'view')));
$this->assertNull($utils->urlFor(array('controller' => 'content')));
$this->assertNull($utils->urlFor(array('controller' => 'admin/comments')));
$this->assertEquals('/messages',
$utils->urlFor('messages'));
$this->assertEquals('/messages/rss',
$utils->urlFor('rss_messages'));
$this->assertEquals('/messages/4',
$utils->urlFor('message', array('id' => 4)));
$this->assertEquals('/messages/4/edit',
$utils->urlFor('edit_message', array('id' => 4)));
$this->assertEquals('/messages/4/mark',
$utils->urlFor('mark_message', array('id' => 4)));
$this->assertEquals('/messages/new',
$utils->urlFor('new_message'));
$this->assertEquals('/messages.xml',
$utils->urlFor('formatted_messages', array('format' => 'xml')));
$this->assertEquals('/messages/rss.xml',
$utils->urlFor('formatted_rss_messages', array('format' => 'xml')));
$this->assertEquals('/messages/4.xml',
$utils->urlFor('formatted_message', array('id' => 4, 'format' => 'xml')));
$this->assertEquals('/messages/4/edit.xml',
$utils->urlFor('formatted_edit_message', array('id' => 4, 'format' => 'xml')));
$this->assertEquals('/messages/4/mark.xml',
$utils->urlFor('formatted_mark_message', array('id' => 4, 'format' => 'xml')));
$this->assertEquals('/messages/new.xml',
$utils->urlFor('formatted_new_message', array('format' => 'xml')));
}
}