mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-24 04:29:04 +01:00
Summary: This enables CORGI. Currently, `AphrontSite` subclasses can't really have their own routes. They can do this sort of hacky rewriting of paths, but that's a mess and not desirable in the long run. Instead, let subclasses build their own routing maps. This will let CORP and ORG have their own routing maps. I was able to get rid of the `PhameBlogResourcesSite` since it can really just share the standard resources site. Test Plan: - With no base URI set, and a base URI set, loaded main page and resources (from main site). - With file domain set, loaded resources from main site and file site. - Loaded a skinned blog from a domain. - Loaded a skinned blog from the main site. - Viewed "Request" tab of DarkConsole to see site/controller info. Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D14008
159 lines
3.5 KiB
PHP
159 lines
3.5 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Collection of routes on a site for an application.
|
|
*
|
|
* @task info Map Information
|
|
* @task routing Routing
|
|
*/
|
|
final class AphrontRoutingMap extends Phobject {
|
|
|
|
private $site;
|
|
private $application;
|
|
private $routes = array();
|
|
|
|
|
|
/* -( Map Info )----------------------------------------------------------- */
|
|
|
|
|
|
public function setSite(AphrontSite $site) {
|
|
$this->site = $site;
|
|
return $this;
|
|
}
|
|
|
|
public function getSite() {
|
|
return $this->site;
|
|
}
|
|
|
|
public function setApplication(PhabricatorApplication $application) {
|
|
$this->application = $application;
|
|
return $this;
|
|
}
|
|
|
|
public function getApplication() {
|
|
return $this->application;
|
|
}
|
|
|
|
public function setRoutes(array $routes) {
|
|
$this->routes = $routes;
|
|
return $this;
|
|
}
|
|
|
|
public function getRoutes() {
|
|
return $this->routes;
|
|
}
|
|
|
|
|
|
/* -( Routing )------------------------------------------------------------ */
|
|
|
|
|
|
/**
|
|
* Find the route matching a path, if one exists.
|
|
*
|
|
* @param string Path to route.
|
|
* @return AphrontRoutingResult|null Routing result, if path matches map.
|
|
* @task routing
|
|
*/
|
|
public function routePath($path) {
|
|
$map = $this->getRoutes();
|
|
|
|
foreach ($map as $route => $value) {
|
|
$match = $this->tryRoute($route, $value, $path);
|
|
if (!$match) {
|
|
continue;
|
|
}
|
|
|
|
$result = $this->newRoutingResult();
|
|
$application = $result->getApplication();
|
|
|
|
$controller_class = $match['class'];
|
|
$controller = newv($controller_class, array());
|
|
$controller->setCurrentApplication($application);
|
|
|
|
$result
|
|
->setController($controller)
|
|
->setURIData($match['data']);
|
|
|
|
return $result;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Test a sub-map to see if any routes match a path.
|
|
*
|
|
* @param string Path to route.
|
|
* @param string Pattern from the map.
|
|
* @param string Value from the map.
|
|
* @return dict<string, wild>|null Match details, if path matches sub-map.
|
|
* @task routing
|
|
*/
|
|
private function tryRoute($route, $value, $path) {
|
|
$has_submap = is_array($value);
|
|
|
|
if (!$has_submap) {
|
|
// If the value is a controller rather than a sub-map, any matching
|
|
// route must completely consume the path.
|
|
$pattern = '(^'.$route.'\z)';
|
|
} else {
|
|
$pattern = '(^'.$route.')';
|
|
}
|
|
|
|
$data = null;
|
|
$ok = preg_match($pattern, $path, $data);
|
|
if ($ok === false) {
|
|
throw new Exception(
|
|
pht(
|
|
'Routing fragment "%s" is not a valid regular expression.',
|
|
$route));
|
|
}
|
|
|
|
if (!$ok) {
|
|
return null;
|
|
}
|
|
|
|
$path_match = $data[0];
|
|
|
|
// Clean up the data. We only want to retain named capturing groups, not
|
|
// the duplicated numeric captures.
|
|
foreach ($data as $k => $v) {
|
|
if (is_numeric($k)) {
|
|
unset($data[$k]);
|
|
}
|
|
}
|
|
|
|
if (!$has_submap) {
|
|
return array(
|
|
'class' => $value,
|
|
'data' => $data,
|
|
);
|
|
}
|
|
|
|
$sub_path = substr($path, strlen($path_match));
|
|
foreach ($value as $sub_route => $sub_value) {
|
|
$result = $this->tryRoute($sub_route, $sub_value, $sub_path);
|
|
if ($result) {
|
|
$result['data'] += $data;
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Build a new routing result for this map.
|
|
*
|
|
* @return AphrontRoutingResult New, empty routing result.
|
|
* @task routing
|
|
*/
|
|
private function newRoutingResult() {
|
|
return id(new AphrontRoutingResult())
|
|
->setSite($this->getSite())
|
|
->setApplication($this->getApplication());
|
|
}
|
|
|
|
}
|