Commit 2c79c025 authored by Crell's avatar Crell Committed by effulgentsia
Browse files

Copy in old dumping logic. Still being refactored.

parent eba77ad5
......@@ -3,17 +3,21 @@
namespace Drupal\Core\Routing;
use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Drupal\Core\Database\Connection;
/**
* Description of UrlMatcherDumper
*
* @author crell
* Description of UrlMatcherDumper.
*/
class UrlMatcherDumper implements MatcherDumperInterface {
/**
* The maximum number of path elements for a route pattern;
*/
const MAX_PARTS = 9;
/**
* The database connection to which to dump route information.
*
......@@ -58,7 +62,34 @@ public function addRoutes(RouteCollection $routes) {
*
* @return string A PHP class representing the matcher class
*/
function dump(array $options = array()) {
public function dump(array $options = array()) {
$options += array(
'route_set' => '',
);
$compiled = $this->compileRoutes($this->routes, $route_set);
// Convert all of the routes into database records.
$insert = $this->connection->insert('router');
foreach ($this->routes as $name => $route) {
$insert->values($record);
}
// Delete any old records in this route set first, then insert the new ones.
// That avoids stale data. The transaction makes it atomic to avoid
// unstable router states due to random failures.
$txn = $this->connection->startTransaction();
$this->connection->delete('router')
->condition('route_set', $options['route_set'])
->execute();
$insert->execute();
// Transaction ends here.
}
......@@ -67,8 +98,187 @@ function dump(array $options = array()) {
*
* @return RouteCollection A RouteCollection instance
*/
function getRoutes() {
public function getRoutes() {
return $this->routes;
}
protected function compileRoutes(RouteCollection $routes, $route_set) {
// First pass: separate callbacks from paths, making paths ready for
// matching. Calculate fitness, and fill some default values.
$menu = array();
$masks = array();
foreach ($routes as $name => $item) {
$path = $item->getPattern();
$move = FALSE;
$parts = explode('/', $path, static::MAX_PARTS);
$number_parts = count($parts);
// We store the highest index of parts here to save some work in the fit
// calculation loop.
$slashes = $number_parts - 1;
$num_placeholders = count(array_filter($parts, function($value) {
return strpos($value, '{') !== FALSE;
}));
$fit = $this->getFit($path);
if ($fit) {
$move = TRUE;
}
else {
// If there is no placeholder, it fits maximally.
$fit = (1 << $number_parts) - 1;
}
$masks[$fit] = 1;
$item += array(
'title' => '',
'weight' => 0,
'type' => MENU_NORMAL_ITEM,
'module' => '',
'_number_parts' => $number_parts,
'_parts' => $parts,
'_fit' => $fit,
);
if ($move) {
$new_path = implode('/', $item['_parts']);
$menu[$new_path] = $item;
$sort[$new_path] = $number_parts;
}
else {
$menu[$path] = $item;
$sort[$path] = $number_parts;
}
}
// Sort the route list.
array_multisort($sort, SORT_NUMERIC, $menu);
// Apply inheritance rules.
foreach ($menu as $path => $v) {
$item = &$menu[$path];
for ($i = $item['_number_parts'] - 1; $i; $i--) {
$parent_path = implode('/', array_slice($item['_parts'], 0, $i));
if (isset($menu[$parent_path])) {
$parent = &$menu[$parent_path];
// If an access callback is not found for a default local task we use
// the callback from the parent, since we expect them to be identical.
// In all other cases, the access parameters must be specified.
if (($item['type'] == MENU_DEFAULT_LOCAL_TASK) && !isset($item['access callback']) && isset($parent['access callback'])) {
$item['access callback'] = $parent['access callback'];
if (!isset($item['access arguments']) && isset($parent['access arguments'])) {
$item['access arguments'] = $parent['access arguments'];
}
}
// Same for theme callbacks.
if (!isset($item['theme callback']) && isset($parent['theme callback'])) {
$item['theme callback'] = $parent['theme callback'];
if (!isset($item['theme arguments']) && isset($parent['theme arguments'])) {
$item['theme arguments'] = $parent['theme arguments'];
}
}
}
}
if (!isset($item['access callback']) && isset($item['access arguments'])) {
// Default callback.
$item['access callback'] = 'user_access';
}
if (!isset($item['access callback']) || empty($item['page callback'])) {
$item['access callback'] = 0;
}
if (is_bool($item['access callback'])) {
$item['access callback'] = intval($item['access callback']);
}
$item += array(
'access arguments' => array(),
'access callback' => '',
'page arguments' => array(),
'page callback' => '',
'delivery callback' => '',
'title arguments' => array(),
'title callback' => 't',
'theme arguments' => array(),
'theme callback' => '',
'description' => '',
'position' => '',
'context' => 0,
'tab_parent' => '',
'tab_root' => $path,
'path' => $path,
'file' => '',
'file path' => '',
'include file' => '',
);
// Calculate out the file to be included for each callback, if any.
if ($item['file']) {
$file_path = $item['file path'] ? $item['file path'] : drupal_get_path('module', $item['module']);
$item['include file'] = $file_path . '/' . $item['file'];
}
}
// Sort the masks so they are in order of descending fit.
$masks = array_keys($masks);
rsort($masks);
return array($menu, $masks);
// The old menu_router record structure, copied here for easy referencing.
array(
'path' => $item['path'],
'load_functions' => $item['load_functions'],
'to_arg_functions' => $item['to_arg_functions'],
'access_callback' => $item['access callback'],
'access_arguments' => serialize($item['access arguments']),
'page_callback' => $item['page callback'],
'page_arguments' => serialize($item['page arguments']),
'delivery_callback' => $item['delivery callback'],
'fit' => $item['_fit'],
'number_parts' => $item['_number_parts'],
'context' => $item['context'],
'tab_parent' => $item['tab_parent'],
'tab_root' => $item['tab_root'],
'title' => $item['title'],
'title_callback' => $item['title callback'],
'title_arguments' => ($item['title arguments'] ? serialize($item['title arguments']) : ''),
'theme_callback' => $item['theme callback'],
'theme_arguments' => serialize($item['theme arguments']),
'type' => $item['type'],
'description' => $item['description'],
'position' => $item['position'],
'weight' => $item['weight'],
'include_file' => $item['include file'],
);
}
/**
* Determines the fitness of the provided path.
*
* @param string $path
* The path whose fitness we want.
*
* @return int
* The fitness of the path, as an integer.
*/
public function getFit($path) {
$fit = 0;
$parts = explode('/', $path, static::MAX_PARTS);
foreach ($parts as $k => $part) {
if (strpos($part, '{') === FALSE) {
$fit |= 1 << ($slashes - $k);
}
}
return $fit;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment