class Router
{
var $m = null;
+ static $inst = null;
+ static $bare = array('requesttoken', 'accesstoken', 'userauthorization',
+ 'postnotice', 'updateprofile', 'finishremotesubscribe',
+ 'finishopenidlogin', 'finishaddopenid');
+
+ static function get()
+ {
+ if (!Router::$inst) {
+ Router::$inst = new Router();
+ }
+ return Router::$inst;
+ }
function __construct()
+ {
+ if (!$this->m) {
+ $this->m = $this->initialize();
+ }
+ }
+
+ function initialize()
{
$m = Net_URL_Mapper::getInstance();
$main = array('login', 'logout', 'register', 'subscribe',
'unsubscribe', 'confirmaddress', 'recoverpassword',
'invite', 'favor', 'disfavor', 'sup',
- 'tagother', 'block');
+ 'block', 'subedit');
foreach ($main as $a) {
$m->connect('main/'.$a, array('action' => $a));
}
+ $m->connect('main/sup/:seconds', array('action' => 'sup'),
+ array('seconds' => '[0-9]+'));
+
+ $m->connect('main/tagother/:id', array('action' => 'tagother'));
+
// these take a code
foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) {
$m->connect('main/openid', array('action' => 'openidlogin'));
$m->connect('main/remote', array('action' => 'remotesubscribe'));
+ $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+'));
+
+ foreach (Router::$bare as $action) {
+ $m->connect('index.php?action=' . $action, array('action' => $action));
+ }
// settings
foreach (array('profile', 'avatar', 'password', 'openid', 'im',
- 'email', 'sms', 'twitter', 'other') as $s) {
+ 'email', 'sms', 'twitter', 'design', 'other') as $s) {
$m->connect('settings/'.$s, array('action' => $s.'settings'));
}
foreach (array('group', 'people', 'notice') as $s) {
$m->connect('search/'.$s, array('action' => $s.'search'));
+ $m->connect('search/'.$s.'?q=:q',
+ array('action' => $s.'search'),
+ array('q' => '.+'));
}
+ // The second of these is needed to make the link work correctly
+ // when inserted into the page. The first is needed to match the
+ // route on the way in. Seems to be another Net_URL_Mapper bug to me.
$m->connect('search/notice/rss', array('action' => 'noticesearchrss'));
+ $m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
+ array('q' => '.+'));
// notice
$m->connect('notice/new', array('action' => 'newnotice'));
+ $m->connect('notice/new?replyto=:replyto',
+ array('action' => 'newnotice'),
+ array('replyto' => '[A-Za-z0-9_-]+'));
$m->connect('notice/:notice',
array('action' => 'shownotice'),
array('notice' => '[0-9]+'));
array('action' => 'deletenotice'),
array('notice' => '[0-9]+'));
+ // conversation
+
+ $m->connect('conversation/:id',
+ array('action' => 'conversation'),
+ array('id' => '[0-9]+'));
+
$m->connect('message/new', array('action' => 'newmessage'));
+ $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => '[A-Za-z0-9_-]+'));
$m->connect('message/:message',
array('action' => 'showmessage'),
array('message' => '[0-9]+'));
array('action' => 'userbyid'),
array('id' => '[0-9]+'));
- $m->connect('tags/?', array('action' => 'publictagcloud'));
- $m->connect('tag/?', array('action' => 'publictagcloud'));
+ $m->connect('tags/', array('action' => 'publictagcloud'));
+ $m->connect('tag/', array('action' => 'publictagcloud'));
+ $m->connect('tags', array('action' => 'publictagcloud'));
+ $m->connect('tag', array('action' => 'publictagcloud'));
$m->connect('tag/:tag/rss',
array('action' => 'tagrss'),
array('tag' => '[a-zA-Z0-9]+'));
array('action' => 'peopletag'),
array('tag' => '[a-zA-Z0-9]+'));
- $m->connect('featured/?', array('action' => 'featured'));
- $m->connect('favorited/?', array('action' => 'favorited'));
+ $m->connect('featured/', array('action' => 'featured'));
+ $m->connect('featured', array('action' => 'featured'));
+ $m->connect('favorited/', array('action' => 'favorited'));
+ $m->connect('favorited', array('action' => 'favorited'));
// groups
array('action' => 'showgroup'),
array('nickname' => '[a-zA-Z0-9]+'));
- $m->connect('group/?', array('action' => 'groups'));
+ $m->connect('group/', array('action' => 'groups'));
+ $m->connect('group', array('action' => 'groups'));
+ $m->connect('groups/', array('action' => 'groups'));
+ $m->connect('groups', array('action' => 'groups'));
// Twitter-compatible API
$m->connect('api/statuses/:method/:argument',
array('action' => 'api',
'apiaction' => 'statuses'),
- array('method' => '(user_timeline|show|destroy|friends|followers)'));
+ array('method' => '(user_timeline|friends_timeline|replies|show|destroy|friends|followers)'));
// users
- $m->connect('api/users/show/:argument',
+ $m->connect('api/users/:method/:argument',
array('action' => 'api',
- 'apiaction' => 'users'));
+ 'apiaction' => 'users'),
+ array('method' => 'show(\.(xml|json))?'));
$m->connect('api/users/:method',
array('action' => 'api',
'apiaction' => 'users'),
- array('method' => 'show(\.(xml|json|atom|rss))?'));
+ array('method' => 'show(\.(xml|json))?'));
// direct messages
- $m->connect('api/direct_messages/:method',
- array('action' => 'api',
- 'apiaction' => 'direct_messages'),
- array('method' => '(sent|new)(\.(xml|json|atom|rss))?'));
+ foreach (array('xml', 'json') as $e) {
+ $m->connect('api/direct_messages/new.'.$e,
+ array('action' => 'api',
+ 'apiaction' => 'direct_messages',
+ 'method' => 'create.'.$e));
+ }
+
+ foreach (array('xml', 'json', 'rss', 'atom') as $e) {
+ $m->connect('api/direct_messages.'.$e,
+ array('action' => 'api',
+ 'apiaction' => 'direct_messages',
+ 'method' => 'direct_messages.'.$e));
+ }
+
+ foreach (array('xml', 'json', 'rss', 'atom') as $e) {
+ $m->connect('api/direct_messages/sent.'.$e,
+ array('action' => 'api',
+ 'apiaction' => 'direct_messages',
+ 'method' => 'sent.'.$e));
+ }
$m->connect('api/direct_messages/destroy/:argument',
array('action' => 'api',
'apiaction' => 'direct_messages'));
- $m->connect('api/:method',
- array('action' => 'api',
- 'apiaction' => 'direct_messages'),
- array('method' => 'direct_messages(\.(xml|json|atom|rss))?'));
-
// friendships
$m->connect('api/friendships/:method/:argument',
$m->connect('api/friendships/:method',
array('action' => 'api',
'apiaction' => 'friendships'),
- array('method' => 'exists(\.(xml|json|rss|atom))'));
+ array('method' => 'exists(\.(xml|json))'));
+
+ // Social graph
+
+ $m->connect('api/friends/ids/:argument',
+ array('action' => 'api',
+ 'apiaction' => 'statuses',
+ 'method' => 'friendsIDs'));
+
+ foreach (array('xml', 'json') as $e) {
+ $m->connect('api/friends/ids.'.$e,
+ array('action' => 'api',
+ 'apiaction' => 'statuses',
+ 'method' => 'friendsIDs.'.$e));
+ }
+
+ $m->connect('api/followers/ids/:argument',
+ array('action' => 'api',
+ 'apiaction' => 'statuses',
+ 'method' => 'followersIDs'));
+
+ foreach (array('xml', 'json') as $e) {
+ $m->connect('api/followers/ids.'.$e,
+ array('action' => 'api',
+ 'apiaction' => 'statuses',
+ 'method' => 'followersIDs.'.$e));
+ }
// account
'apiaction' => 'favorites',
'method' => 'favorites'));
- $m->connect('api/:method',
- array('action' => 'api',
- 'apiaction' => 'favorites'),
- array('method' => 'favorites(\.(xml|json|rss|atom))?'));
+ foreach (array('xml', 'json', 'rss', 'atom') as $e) {
+ $m->connect('api/favorites.'.$e,
+ array('action' => 'api',
+ 'apiaction' => 'favorites',
+ 'method' => 'favorites.'.$e));
+ }
// notifications
array('action' => 'api',
'apiaction' => 'laconica'));
+ // search
+ $m->connect('api/search.atom', array('action' => 'twitapisearchatom'));
+ $m->connect('api/search.json', array('action' => 'twitapisearchjson'));
+ $m->connect('api/trends.json', array('action' => 'twitapitrends'));
+
// user stuff
foreach (array('subscriptions', 'subscribers',
array('action' => 'showstream'),
array('nickname' => '[a-zA-Z0-9]{1,64}'));
- $this->m = $m;
+ Event::handle('RouterInitialized', array($m));
+
+ return $m;
}
function map($path)
{
- return $this->m->match($path);
+ try {
+ $match = $this->m->match($path);
+ } catch (Net_URL_Mapper_InvalidException $e) {
+ common_log(LOG_ERR, "Problem getting route for $path - " .
+ $e->getMessage());
+ $cac = new ClientErrorAction("Page not found.", 404);
+ $cac->showPage();
+ }
+
+ return $match;
}
- function build($action, $args=null, $fragment=null)
+ function build($action, $args=null, $params=null, $fragment=null)
{
$action_arg = array('action' => $action);
if ($args) {
- $args = array_merge($args, $action_arg);
+ $args = array_merge($action_arg, $args);
} else {
$args = $action_arg;
}
- return $this->m->generate($args, null, $fragment);
+ $url = $this->m->generate($args, $params, $fragment);
+
+ // Due to a bug in the Net_URL_Mapper code, the returned URL may
+ // contain a malformed query of the form ?p1=v1?p2=v2?p3=v3. We
+ // repair that here rather than modifying the upstream code...
+
+ $qpos = strpos($url, '?');
+ if ($qpos !== false) {
+ $url = substr($url, 0, $qpos+1) .
+ str_replace('?', '&', substr($url, $qpos+1));
+ }
+ return $url;
}
-}
\ No newline at end of file
+}