Push construction of routing maps into Sites
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
This commit is contained in:
parent
2665970762
commit
bcc5e55af2
|
@ -1,28 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
$root = dirname(dirname(dirname(__FILE__)));
|
|
||||||
require_once $root.'/scripts/__init_script__.php';
|
|
||||||
|
|
||||||
if ($argc !== 2 || $argv[1] === '--help') {
|
|
||||||
echo pht('Usage: %s', 'aphrontpath.php <url>')."\n";
|
|
||||||
echo pht(
|
|
||||||
"Purpose: Print controller which will process passed %s.\n",
|
|
||||||
'<url>');
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = parse_url($argv[1]);
|
|
||||||
$path = '/'.(isset($url['path']) ? ltrim($url['path'], '/') : '');
|
|
||||||
|
|
||||||
$config_key = 'aphront.default-application-configuration-class';
|
|
||||||
$application = PhabricatorEnv::newObjectFromConfig($config_key);
|
|
||||||
$application->setRequest(new AphrontRequest('', $path));
|
|
||||||
|
|
||||||
list($controller) = $application->buildControllerForPath($path);
|
|
||||||
if (!$controller && substr($path, -1) !== '/') {
|
|
||||||
list($controller) = $application->buildControllerForPath($path.'/');
|
|
||||||
}
|
|
||||||
if ($controller) {
|
|
||||||
echo get_class($controller)."\n";
|
|
||||||
}
|
|
|
@ -158,6 +158,8 @@ phutil_register_library_map(array(
|
||||||
'AphrontRequest' => 'aphront/AphrontRequest.php',
|
'AphrontRequest' => 'aphront/AphrontRequest.php',
|
||||||
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
||||||
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
||||||
|
'AphrontRoutingMap' => 'aphront/site/AphrontRoutingMap.php',
|
||||||
|
'AphrontRoutingResult' => 'aphront/site/AphrontRoutingResult.php',
|
||||||
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php',
|
||||||
'AphrontSite' => 'aphront/site/AphrontSite.php',
|
'AphrontSite' => 'aphront/site/AphrontSite.php',
|
||||||
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
|
'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php',
|
||||||
|
@ -166,7 +168,6 @@ phutil_register_library_map(array(
|
||||||
'AphrontTagView' => 'view/AphrontTagView.php',
|
'AphrontTagView' => 'view/AphrontTagView.php',
|
||||||
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
|
'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php',
|
||||||
'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php',
|
'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php',
|
||||||
'AphrontURIMapper' => 'aphront/AphrontURIMapper.php',
|
|
||||||
'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php',
|
'AphrontUnhandledExceptionResponse' => 'aphront/response/AphrontUnhandledExceptionResponse.php',
|
||||||
'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php',
|
'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php',
|
||||||
'AphrontView' => 'view/AphrontView.php',
|
'AphrontView' => 'view/AphrontView.php',
|
||||||
|
@ -3126,7 +3127,6 @@ phutil_register_library_map(array(
|
||||||
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
|
'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php',
|
||||||
'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php',
|
'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php',
|
||||||
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
|
'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php',
|
||||||
'PhameBlogResourceSite' => 'applications/phame/site/PhameBlogResourceSite.php',
|
|
||||||
'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php',
|
'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php',
|
||||||
'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php',
|
'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php',
|
||||||
'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php',
|
'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php',
|
||||||
|
@ -3777,6 +3777,8 @@ phutil_register_library_map(array(
|
||||||
'AphrontRequest' => 'Phobject',
|
'AphrontRequest' => 'Phobject',
|
||||||
'AphrontRequestTestCase' => 'PhabricatorTestCase',
|
'AphrontRequestTestCase' => 'PhabricatorTestCase',
|
||||||
'AphrontResponse' => 'Phobject',
|
'AphrontResponse' => 'Phobject',
|
||||||
|
'AphrontRoutingMap' => 'Phobject',
|
||||||
|
'AphrontRoutingResult' => 'Phobject',
|
||||||
'AphrontSideNavFilterView' => 'AphrontView',
|
'AphrontSideNavFilterView' => 'AphrontView',
|
||||||
'AphrontSite' => 'Phobject',
|
'AphrontSite' => 'Phobject',
|
||||||
'AphrontStackTraceView' => 'AphrontView',
|
'AphrontStackTraceView' => 'AphrontView',
|
||||||
|
@ -3785,7 +3787,6 @@ phutil_register_library_map(array(
|
||||||
'AphrontTagView' => 'AphrontView',
|
'AphrontTagView' => 'AphrontView',
|
||||||
'AphrontTokenizerTemplateView' => 'AphrontView',
|
'AphrontTokenizerTemplateView' => 'AphrontView',
|
||||||
'AphrontTypeaheadTemplateView' => 'AphrontView',
|
'AphrontTypeaheadTemplateView' => 'AphrontView',
|
||||||
'AphrontURIMapper' => 'Phobject',
|
|
||||||
'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse',
|
'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse',
|
||||||
'AphrontUsageException' => 'AphrontException',
|
'AphrontUsageException' => 'AphrontException',
|
||||||
'AphrontView' => array(
|
'AphrontView' => array(
|
||||||
|
@ -7238,7 +7239,6 @@ phutil_register_library_map(array(
|
||||||
'PhameBlogListController' => 'PhameController',
|
'PhameBlogListController' => 'PhameController',
|
||||||
'PhameBlogLiveController' => 'PhameController',
|
'PhameBlogLiveController' => 'PhameController',
|
||||||
'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhameBlogResourceSite' => 'PhameSite',
|
|
||||||
'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhameBlogSite' => 'PhameSite',
|
'PhameBlogSite' => 'PhameSite',
|
||||||
'PhameBlogSkin' => 'PhabricatorController',
|
'PhameBlogSkin' => 'PhabricatorController',
|
||||||
|
|
|
@ -26,6 +26,8 @@ final class AphrontRequest extends Phobject {
|
||||||
private $requestData;
|
private $requestData;
|
||||||
private $user;
|
private $user;
|
||||||
private $applicationConfiguration;
|
private $applicationConfiguration;
|
||||||
|
private $site;
|
||||||
|
private $controller;
|
||||||
private $uriData;
|
private $uriData;
|
||||||
private $cookiePrefix;
|
private $cookiePrefix;
|
||||||
|
|
||||||
|
@ -77,6 +79,24 @@ final class AphrontRequest extends Phobject {
|
||||||
return $uri->getDomain();
|
return $uri->getDomain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setSite(AphrontSite $site) {
|
||||||
|
$this->site = $site;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSite() {
|
||||||
|
return $this->site;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setController(AphrontController $controller) {
|
||||||
|
$this->controller = $controller;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getController() {
|
||||||
|
return $this->controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Accessing Request Data )--------------------------------------------- */
|
/* -( Accessing Request Data )--------------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class AphrontURIMapper extends Phobject {
|
|
||||||
|
|
||||||
private $map;
|
|
||||||
|
|
||||||
public function __construct(array $map) {
|
|
||||||
$this->map = $map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mapPath($path) {
|
|
||||||
$map = $this->map;
|
|
||||||
foreach ($map as $rule => $value) {
|
|
||||||
list($controller, $data) = $this->tryRule($rule, $value, $path);
|
|
||||||
if ($controller) {
|
|
||||||
foreach ($data as $k => $v) {
|
|
||||||
if (is_numeric($k)) {
|
|
||||||
unset($data[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array($controller, $data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function tryRule($rule, $value, $path) {
|
|
||||||
$match = null;
|
|
||||||
$pattern = '#^'.$rule.(is_array($value) ? '' : '$').'#';
|
|
||||||
if (!preg_match($pattern, $path, $match)) {
|
|
||||||
return array(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_array($value)) {
|
|
||||||
return array($value, $match);
|
|
||||||
}
|
|
||||||
|
|
||||||
$path = substr($path, strlen($match[0]));
|
|
||||||
foreach ($value as $srule => $sval) {
|
|
||||||
list($controller, $data) = $this->tryRule($srule, $sval, $path);
|
|
||||||
if ($controller) {
|
|
||||||
return array($controller, $data + $match);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -210,7 +210,9 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
));
|
));
|
||||||
$multimeter->setEventContext('web.'.$controller_class);
|
$multimeter->setEventContext('web.'.$controller_class);
|
||||||
|
|
||||||
|
$request->setController($controller);
|
||||||
$request->setURIMap($uri_data);
|
$request->setURIMap($uri_data);
|
||||||
|
|
||||||
$controller->setRequest($request);
|
$controller->setRequest($request);
|
||||||
|
|
||||||
// If execution throws an exception and then trying to render that
|
// If execution throws an exception and then trying to render that
|
||||||
|
@ -283,35 +285,13 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using builtin and application routes, build the appropriate
|
* Build a controller to respond to the request.
|
||||||
* @{class:AphrontController} class for the request. To route a request, we
|
|
||||||
* first test if the HTTP_HOST is configured as a valid Phabricator URI. If
|
|
||||||
* it isn't, we do a special check to see if it's a custom domain for a blog
|
|
||||||
* in the Phame application and if that fails we error. Otherwise, we test
|
|
||||||
* against all application routes from installed
|
|
||||||
* @{class:PhabricatorApplication}s.
|
|
||||||
*
|
|
||||||
* If we match a route, we construct the controller it points at, build it,
|
|
||||||
* and return it.
|
|
||||||
*
|
|
||||||
* If we fail to match a route, but the current path is missing a trailing
|
|
||||||
* "/", we try routing the same path with a trailing "/" and do a redirect
|
|
||||||
* if that has a valid route. The idea is to canoncalize URIs for consistency,
|
|
||||||
* but avoid breaking noncanonical URIs that we can easily salvage.
|
|
||||||
*
|
|
||||||
* NOTE: We only redirect on GET. On POST, we'd drop parameters and most
|
|
||||||
* likely mutate the request implicitly, and a bad POST usually indicates a
|
|
||||||
* programming error rather than a sloppy typist.
|
|
||||||
*
|
|
||||||
* If the failing path already has a trailing "/", or we can't route the
|
|
||||||
* version with a "/", we call @{method:build404Controller}, which build a
|
|
||||||
* fallback @{class:AphrontController}.
|
|
||||||
*
|
*
|
||||||
* @return pair<AphrontController,dict> Controller and dictionary of request
|
* @return pair<AphrontController,dict> Controller and dictionary of request
|
||||||
* parameters.
|
* parameters.
|
||||||
* @task routing
|
* @task routing
|
||||||
*/
|
*/
|
||||||
final public function buildController() {
|
final private function buildController() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
// If we're configured to operate in cluster mode, reject requests which
|
// If we're configured to operate in cluster mode, reject requests which
|
||||||
|
@ -373,78 +353,48 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Really, the Site should get more control here and be able to
|
$maps = $site->getRoutingMaps();
|
||||||
// do its own routing logic if it wants, but we don't need that for now.
|
$path = $request->getPath();
|
||||||
$path = $site->getPathForRouting($request);
|
|
||||||
|
|
||||||
list($controller, $uri_data) = $this->buildControllerForPath($path);
|
$result = $this->routePath($maps, $path);
|
||||||
if (!$controller) {
|
if ($result) {
|
||||||
if (!preg_match('@/$@', $path)) {
|
return $result;
|
||||||
// If we failed to match anything but don't have a trailing slash, try
|
|
||||||
// to add a trailing slash and issue a redirect if that resolves.
|
|
||||||
list($controller, $uri_data) = $this->buildControllerForPath($path.'/');
|
|
||||||
|
|
||||||
// NOTE: For POST, just 404 instead of redirecting, since the redirect
|
|
||||||
// will be a GET without parameters.
|
|
||||||
|
|
||||||
if ($controller && !$request->isHTTPPost()) {
|
|
||||||
$slash_uri = $request->getRequestURI()->setPath($path.'/');
|
|
||||||
|
|
||||||
$external = strlen($request->getRequestURI()->getDomain());
|
|
||||||
return $this->buildRedirectController($slash_uri, $external);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this->build404Controller();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return array($controller, $uri_data);
|
// If we failed to match anything but don't have a trailing slash, try
|
||||||
}
|
// to add a trailing slash and issue a redirect if that resolves.
|
||||||
|
|
||||||
|
// NOTE: We only do this for GET, since redirects switch to GET and drop
|
||||||
|
// data like POST parameters.
|
||||||
|
if (!preg_match('@/$@', $path) && $request->isHTTPGet()) {
|
||||||
|
$result = $this->routePath($maps, $path.'/');
|
||||||
|
if ($result) {
|
||||||
|
$slash_uri = $request->getRequestURI()->setPath($path.'/');
|
||||||
|
$external = strlen($request->getRequestURI()->getDomain());
|
||||||
|
return $this->buildRedirectController($slash_uri, $external);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->build404Controller();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map a specific path to the corresponding controller. For a description
|
* Map a specific path to the corresponding controller. For a description
|
||||||
* of routing, see @{method:buildController}.
|
* of routing, see @{method:buildController}.
|
||||||
*
|
*
|
||||||
|
* @param list<AphrontRoutingMap> List of routing maps.
|
||||||
|
* @param string Path to route.
|
||||||
* @return pair<AphrontController,dict> Controller and dictionary of request
|
* @return pair<AphrontController,dict> Controller and dictionary of request
|
||||||
* parameters.
|
* parameters.
|
||||||
* @task routing
|
* @task routing
|
||||||
*/
|
*/
|
||||||
final public function buildControllerForPath($path) {
|
private function routePath(array $maps, $path) {
|
||||||
$maps = array();
|
foreach ($maps as $map) {
|
||||||
|
$result = $map->routePath($path);
|
||||||
$applications = PhabricatorApplication::getAllInstalledApplications();
|
if ($result) {
|
||||||
foreach ($applications as $application) {
|
return array($result->getController(), $result->getURIData());
|
||||||
$maps[] = array($application, $application->getRoutes());
|
|
||||||
}
|
|
||||||
|
|
||||||
$current_application = null;
|
|
||||||
$controller_class = null;
|
|
||||||
foreach ($maps as $map_info) {
|
|
||||||
list($application, $map) = $map_info;
|
|
||||||
|
|
||||||
$mapper = new AphrontURIMapper($map);
|
|
||||||
list($controller_class, $uri_data) = $mapper->mapPath($path);
|
|
||||||
|
|
||||||
if ($controller_class) {
|
|
||||||
if ($application) {
|
|
||||||
$current_application = $application;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$controller_class) {
|
|
||||||
return array(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = $this->getRequest();
|
|
||||||
|
|
||||||
$controller = newv($controller_class, array());
|
|
||||||
if ($current_application) {
|
|
||||||
$controller->setCurrentApplication($current_application);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($controller, $uri_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildSiteForRequest(AphrontRequest $request) {
|
private function buildSiteForRequest(AphrontRequest $request) {
|
||||||
|
@ -469,6 +419,8 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
$host));
|
$host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$request->setSite($site);
|
||||||
|
|
||||||
return $site;
|
return $site;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
159
src/aphront/site/AphrontRoutingMap.php
Normal file
159
src/aphront/site/AphrontRoutingMap.php
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
<?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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
src/aphront/site/AphrontRoutingResult.php
Normal file
55
src/aphront/site/AphrontRoutingResult.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details about a routing map match for a path.
|
||||||
|
*
|
||||||
|
* @param info Result Information
|
||||||
|
*/
|
||||||
|
final class AphrontRoutingResult extends Phobject {
|
||||||
|
|
||||||
|
private $site;
|
||||||
|
private $application;
|
||||||
|
private $controller;
|
||||||
|
private $uriData;
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Result Information )------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
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 setController(AphrontController $controller) {
|
||||||
|
$this->controller = $controller;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getController() {
|
||||||
|
return $this->controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setURIData(array $uri_data) {
|
||||||
|
$this->uriData = $uri_data;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURIData() {
|
||||||
|
return $this->uriData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,14 +7,7 @@ abstract class AphrontSite extends Phobject {
|
||||||
|
|
||||||
abstract public function shouldRequireHTTPS();
|
abstract public function shouldRequireHTTPS();
|
||||||
abstract public function newSiteForRequest(AphrontRequest $request);
|
abstract public function newSiteForRequest(AphrontRequest $request);
|
||||||
|
abstract public function getRoutingMaps();
|
||||||
/**
|
|
||||||
* NOTE: This is temporary glue; eventually, sites will return an entire
|
|
||||||
* route map.
|
|
||||||
*/
|
|
||||||
public function getPathForRouting(AphrontRequest $request) {
|
|
||||||
return $request->getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isHostMatch($host, array $uris) {
|
protected function isHostMatch($host, array $uris) {
|
||||||
foreach ($uris as $uri) {
|
foreach ($uris as $uri) {
|
||||||
|
@ -32,14 +25,9 @@ abstract class AphrontSite extends Phobject {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isPathPrefixMatch($path, array $paths) {
|
protected function newRoutingMap() {
|
||||||
foreach ($paths as $candidate) {
|
return id(new AphrontRoutingMap())
|
||||||
if (strncmp($path, $candidate, strlen($candidate)) === 0) {
|
->setSite($this);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final public static function getAllSites() {
|
final public static function getAllSites() {
|
||||||
|
|
|
@ -37,4 +37,17 @@ final class PhabricatorPlatformSite extends PhabricatorSite {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRoutingMaps() {
|
||||||
|
$applications = PhabricatorApplication::getAllInstalledApplications();
|
||||||
|
|
||||||
|
$maps = array();
|
||||||
|
foreach ($applications as $application) {
|
||||||
|
$maps[] = $this->newRoutingMap()
|
||||||
|
->setApplication($application)
|
||||||
|
->setRoutes($application->getRoutes());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $maps;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,20 @@ final class PhabricatorResourceSite extends PhabricatorSite {
|
||||||
return new PhabricatorResourceSite();
|
return new PhabricatorResourceSite();
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are CDN routes, so we let them through even if the "Host" header
|
|
||||||
// doesn't match anything we recognize. The
|
|
||||||
$whitelist = array(
|
|
||||||
'/res/',
|
|
||||||
'/file/data/',
|
|
||||||
'/file/xform/',
|
|
||||||
);
|
|
||||||
|
|
||||||
$path = $request->getPath();
|
|
||||||
if ($this->isPathPrefixMatch($path, $whitelist)) {
|
|
||||||
return new PhabricatorResourceSite();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRoutingMaps() {
|
||||||
|
$applications = PhabricatorApplication::getAllInstalledApplications();
|
||||||
|
|
||||||
|
$maps = array();
|
||||||
|
foreach ($applications as $application) {
|
||||||
|
$maps[] = $this->newRoutingMap()
|
||||||
|
->setApplication($application)
|
||||||
|
->setRoutes($application->getResourceRoutes());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $maps;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,10 @@ abstract class PhabricatorApplication
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getResourceRoutes() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Email Integration )-------------------------------------------------- */
|
/* -( Email Integration )-------------------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,17 @@ final class PhabricatorCelerityApplication extends PhabricatorApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
|
// We serve resources from both the platform site and the resource site.
|
||||||
|
// This is safe because the user doesn't have any direct control over
|
||||||
|
// resources.
|
||||||
|
|
||||||
|
// The advantage of serving resources from the resource site (if possible)
|
||||||
|
// is that we can use a CDN there if one is configured, but there is no
|
||||||
|
// particular security concern.
|
||||||
|
return $this->getResourceRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResourceRoutes() {
|
||||||
$extensions = CelerityResourceController::getSupportedResourceTypes();
|
$extensions = CelerityResourceController::getSupportedResourceTypes();
|
||||||
$extensions = array_keys($extensions);
|
$extensions = array_keys($extensions);
|
||||||
$extensions = implode('|', $extensions);
|
$extensions = implode('|', $extensions);
|
||||||
|
|
|
@ -14,66 +14,121 @@ final class DarkConsoleRequestPlugin extends DarkConsolePlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateData() {
|
public function generateData() {
|
||||||
|
$addr = idx($_SERVER, 'SERVER_ADDR');
|
||||||
|
if ($addr) {
|
||||||
|
$hostname = @gethostbyaddr($addr);
|
||||||
|
} else {
|
||||||
|
$hostname = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$controller = $this->getRequest()->getController();
|
||||||
|
if ($controller) {
|
||||||
|
$controller_class = get_class($controller);
|
||||||
|
} else {
|
||||||
|
$controller_class = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$site = $this->getRequest()->getSite();
|
||||||
|
if ($site) {
|
||||||
|
$site_class = get_class($site);
|
||||||
|
} else {
|
||||||
|
$site_class = null;
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'Request' => $_REQUEST,
|
'request' => $_REQUEST,
|
||||||
'Server' => $_SERVER,
|
'server' => $_SERVER,
|
||||||
|
'special' => array(
|
||||||
|
'site' => $site_class,
|
||||||
|
'controller' => $controller_class,
|
||||||
|
'machine' => php_uname('n'),
|
||||||
|
'host' => $addr,
|
||||||
|
'hostname' => $hostname,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderPanel() {
|
public function renderPanel() {
|
||||||
$data = $this->getData();
|
$data = $this->getData();
|
||||||
|
|
||||||
$sections = array(
|
$special_map = array(
|
||||||
'Basics' => array(
|
'site' => pht('Site'),
|
||||||
'Machine' => php_uname('n'),
|
'controller' => pht('Controller'),
|
||||||
),
|
'machine' => pht('Machine'),
|
||||||
|
'host' => pht('Host'),
|
||||||
|
'hostname' => pht('Hostname'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// NOTE: This may not be present for some SAPIs, like php-fpm.
|
$special = idx($data, 'special', array());
|
||||||
if (!empty($data['Server']['SERVER_ADDR'])) {
|
|
||||||
$addr = $data['Server']['SERVER_ADDR'];
|
$rows = array();
|
||||||
$sections['Basics']['Host'] = $addr;
|
foreach ($special_map as $key => $label) {
|
||||||
$sections['Basics']['Hostname'] = @gethostbyaddr($addr);
|
$rows[] = array(
|
||||||
|
$label,
|
||||||
|
idx($special, $key),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sections = array_merge($sections, $data);
|
$sections = array();
|
||||||
|
$sections[] = array(
|
||||||
|
'name' => pht('Basics'),
|
||||||
|
'rows' => $rows,
|
||||||
|
);
|
||||||
|
|
||||||
$mask = array(
|
$mask = array(
|
||||||
'HTTP_COOKIE' => true,
|
'HTTP_COOKIE' => true,
|
||||||
'HTTP_X_PHABRICATOR_CSRF' => true,
|
'HTTP_X_PHABRICATOR_CSRF' => true,
|
||||||
);
|
);
|
||||||
|
|
||||||
$out = array();
|
$maps = array(
|
||||||
foreach ($sections as $header => $map) {
|
array(
|
||||||
|
'name' => pht('Request'),
|
||||||
|
'data' => idx($data, 'request', array()),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => pht('Server'),
|
||||||
|
'data' => idx($data, 'server', array()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($maps as $map) {
|
||||||
|
$data = $map['data'];
|
||||||
$rows = array();
|
$rows = array();
|
||||||
foreach ($map as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
if (isset($mask[$key])) {
|
if (isset($mask[$key])) {
|
||||||
$rows[] = array(
|
$value = phutil_tag('em', array(), pht('(Masked)'));
|
||||||
$key,
|
} else if (is_array($value)) {
|
||||||
phutil_tag('em', array(), pht('(Masked)')),
|
$value = @json_encode($value);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
$rows[] = array(
|
$value = $value;
|
||||||
$key,
|
|
||||||
(is_array($value) ? json_encode($value) : $value),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
$key,
|
||||||
|
$value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$table = new AphrontTableView($rows);
|
$sections[] = array(
|
||||||
$table->setHeaders(
|
'name' => $map['name'],
|
||||||
array(
|
'rows' => $rows,
|
||||||
$header,
|
);
|
||||||
null,
|
|
||||||
));
|
|
||||||
$table->setColumnClasses(
|
|
||||||
array(
|
|
||||||
'header',
|
|
||||||
'wide wrap',
|
|
||||||
));
|
|
||||||
$out[] = $table->render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return phutil_implode_html("\n", $out);
|
$out = array();
|
||||||
|
foreach ($sections as $section) {
|
||||||
|
$out[] = id(new AphrontTableView($section['rows']))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
$section['name'],
|
||||||
|
null,
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'header',
|
||||||
|
'wide wrap',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,25 +78,36 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
|
||||||
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
|
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
|
||||||
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
|
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
|
||||||
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
|
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
|
||||||
'data/'.
|
|
||||||
'(?:@(?P<instance>[^/]+)/)?'.
|
|
||||||
'(?P<key>[^/]+)/'.
|
|
||||||
'(?P<phid>[^/]+)/'.
|
|
||||||
'(?:(?P<token>[^/]+)/)?'.
|
|
||||||
'.*'
|
|
||||||
=> 'PhabricatorFileDataController',
|
|
||||||
'proxy/' => 'PhabricatorFileProxyController',
|
'proxy/' => 'PhabricatorFileProxyController',
|
||||||
'xform/'.
|
|
||||||
'(?:@(?P<instance>[^/]+)/)?'.
|
|
||||||
'(?P<transform>[^/]+)/'.
|
|
||||||
'(?P<phid>[^/]+)/'.
|
|
||||||
'(?P<key>[^/]+)/'
|
|
||||||
=> 'PhabricatorFileTransformController',
|
|
||||||
'transforms/(?P<id>[1-9]\d*)/' =>
|
'transforms/(?P<id>[1-9]\d*)/' =>
|
||||||
'PhabricatorFileTransformListController',
|
'PhabricatorFileTransformListController',
|
||||||
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
|
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
|
||||||
'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
|
'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
|
||||||
),
|
) + $this->getResourceSubroutes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResourceRoutes() {
|
||||||
|
return array(
|
||||||
|
'/file/' => $this->getResourceSubroutes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getResourceSubroutes() {
|
||||||
|
return array(
|
||||||
|
'data/'.
|
||||||
|
'(?:@(?P<instance>[^/]+)/)?'.
|
||||||
|
'(?P<key>[^/]+)/'.
|
||||||
|
'(?P<phid>[^/]+)/'.
|
||||||
|
'(?:(?P<token>[^/]+)/)?'.
|
||||||
|
'.*'
|
||||||
|
=> 'PhabricatorFileDataController',
|
||||||
|
'xform/'.
|
||||||
|
'(?:@(?P<instance>[^/]+)/)?'.
|
||||||
|
'(?P<transform>[^/]+)/'.
|
||||||
|
'(?P<phid>[^/]+)/'.
|
||||||
|
'(?P<key>[^/]+)/'
|
||||||
|
=> 'PhabricatorFileTransformController',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,6 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/phame/' => array(
|
'/phame/' => array(
|
||||||
'' => 'PhamePostListController',
|
'' => 'PhamePostListController',
|
||||||
'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)'
|
|
||||||
=> 'PhameResourceController',
|
|
||||||
|
|
||||||
'live/(?P<id>[^/]+)/(?P<more>.*)' => 'PhameBlogLiveController',
|
'live/(?P<id>[^/]+)/(?P<more>.*)' => 'PhameBlogLiveController',
|
||||||
'post/' => array(
|
'post/' => array(
|
||||||
'(?:(?P<filter>draft|all)/)?' => 'PhamePostListController',
|
'(?:(?P<filter>draft|all)/)?' => 'PhamePostListController',
|
||||||
|
@ -65,6 +62,34 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
|
||||||
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
|
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
|
||||||
'new/' => 'PhameBlogEditController',
|
'new/' => 'PhameBlogEditController',
|
||||||
),
|
),
|
||||||
|
) + $this->getResourceSubroutes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResourceRoutes() {
|
||||||
|
return array(
|
||||||
|
'/phame/' => $this->getResourceSubroutes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getResourceSubroutes() {
|
||||||
|
return array(
|
||||||
|
'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)' =>
|
||||||
|
'PhameResourceController',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlogRoutes() {
|
||||||
|
return array(
|
||||||
|
'/(?P<more>.*)' => 'PhameBlogLiveController',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlogCDNRoutes() {
|
||||||
|
return array(
|
||||||
|
'/phame/' => array(
|
||||||
|
'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)' =>
|
||||||
|
'PhameResourceController',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,20 @@ final class PhameBlogLiveController extends PhameController {
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
$id = $request->getURIData('id');
|
|
||||||
|
|
||||||
$blog = id(new PhameBlogQuery())
|
$site = $request->getSite();
|
||||||
->setViewer($user)
|
if ($site instanceof PhameBlogSite) {
|
||||||
->withIDs(array($id))
|
$blog = $site->getBlog();
|
||||||
->executeOne();
|
} else {
|
||||||
if (!$blog) {
|
$id = $request->getURIData('id');
|
||||||
return new Aphront404Response();
|
|
||||||
|
$blog = id(new PhameBlogQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$blog) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($blog->getDomain() && ($request->getHost() != $blog->getDomain())) {
|
if ($blog->getDomain() && ($request->getHost() != $blog->getDomain())) {
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhameBlogResourceSite extends PhameSite {
|
|
||||||
|
|
||||||
public function getDescription() {
|
|
||||||
return pht('Serves static resources for blogs.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPriority() {
|
|
||||||
return 3000;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function newSiteForRequest(AphrontRequest $request) {
|
|
||||||
if (!$this->isPhameActive()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$whitelist = array(
|
|
||||||
'/phame/r/',
|
|
||||||
);
|
|
||||||
|
|
||||||
$path = $request->getPath();
|
|
||||||
if (!$this->isPathPrefixMatch($path, $whitelist)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PhameBlogResourceSite();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -24,7 +24,7 @@ final class PhameBlogSite extends PhameSite {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPriority() {
|
public function getPriority() {
|
||||||
return 4000;
|
return 3000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newSiteForRequest(AphrontRequest $request) {
|
public function newSiteForRequest(AphrontRequest $request) {
|
||||||
|
@ -53,11 +53,14 @@ final class PhameBlogSite extends PhameSite {
|
||||||
return id(new PhameBlogSite())->setBlog($blog);
|
return id(new PhameBlogSite())->setBlog($blog);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPathForRouting(AphrontRequest $request) {
|
public function getRoutingMaps() {
|
||||||
$path = $request->getPath();
|
$app = PhabricatorApplication::getByClass('PhabricatorPhameApplication');
|
||||||
$id = $this->getBlog()->getID();
|
|
||||||
|
|
||||||
return "/phame/live/{$id}/{$path}";
|
$maps = array();
|
||||||
|
$maps[] = $this->newRoutingMap()
|
||||||
|
->setApplication($app)
|
||||||
|
->setRoutes($app->getBlogRoutes());
|
||||||
|
return $maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue