languageHierarchyPaths.class.inc in Language Hierarchy 7
Class to extend Drupal path handling with fallbacks by language hierarchy.
File
modules/language_hierarchy_paths/languageHierarchyPaths.class.incView source
<?php
/**
* @file
* Class to extend Drupal path handling with fallbacks by language hierarchy.
*/
class languageHierarchyPaths extends DrupalPathinc {
/**
* Given an alias, return its Drupal system URL if one exists. Given a Drupal
* system URL return one of its aliases if such a one exists. Otherwise,
* return FALSE.
*
* @param $action
* One of the following values:
* - wipe: delete the alias cache.
* - alias: return an alias for a given Drupal system path (if one exists).
* - source: return the Drupal system URL for a path alias (if one exists).
* @param $path
* The path to investigate for corresponding aliases or system URLs.
* @param $path_language
* Optional language code to search the path with. Defaults to the page language.
* If there's no path defined for that language it will search paths without
* language.
*
* @return
* Either a Drupal system path, an aliased path, or FALSE if no path was
* found.
*/
function drupal_lookup_path($action, $path = '', $path_language = NULL) {
global $language_url;
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['cache'] =& drupal_static(__FUNCTION__);
}
$cache =& $drupal_static_fast['cache'];
if (!isset($cache)) {
$cache = array(
'map' => array(),
'no_source' => array(),
'whitelist' => NULL,
'system_paths' => array(),
'no_aliases' => array(),
'first_call' => TRUE,
);
}
// Retrieve the path alias whitelist.
if (!isset($cache['whitelist'])) {
$cache['whitelist'] = variable_get('path_alias_whitelist', NULL);
if (!isset($cache['whitelist'])) {
$cache['whitelist'] = $this
->drupal_path_alias_whitelist_rebuild();
}
}
// If no language is explicitly specified we default to the current URL
// language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path
// alias matching the URL path.
$path_language = $path_language ? $path_language : $language_url->language;
if ($action == 'wipe') {
$cache = array();
$cache['whitelist'] = $this
->drupal_path_alias_whitelist_rebuild();
}
elseif ($cache['whitelist'] && $path != '') {
if ($action == 'alias') {
// During the first call to drupal_lookup_path() per language, load the
// expected system paths for the page from cache.
if (!empty($cache['first_call'])) {
$cache['first_call'] = FALSE;
$cache['map'][$path_language] = array();
// Load system paths from cache.
$cid = $this
->current_path();
if ($cached = cache_get($cid, 'cache_path')) {
$cache['system_paths'] = $cached->data;
// Now fetch the aliases corresponding to these system paths.
$args = array(
':system' => $cache['system_paths'],
':language' => $path_language,
':language_none' => LANGUAGE_NONE,
);
// Always get the language-specific alias before the language-neutral
// one. For example 'de' is less than 'und' so the order needs to be
// ASC, while 'xx-lolspeak' is more than 'und' so the order needs to
// be DESC. We also order by pid ASC so that fetchAllKeyed() returns
// the most recently created alias for each source. Subsequent queries
// using fetchField() must use pid DESC to have the same effect.
// For performance reasons, the query builder is not used here.
if ($path_language == LANGUAGE_NONE) {
// Prevent PDO from complaining about a token the query doesn't use.
unset($args[':language']);
$result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language = :language_none ORDER BY pid ASC', $args);
}
elseif ($candidates = language_hierarchy_get_ancestors($path_language, TRUE)) {
// Build up a select query that will get all source-alias pairs
// for the cached paths, for all languages in the fallback tree.
// Each language will be given a numerical index to be ordered by,
// using the ORDER BY CASE ... END DESC construct. For example:
// ORDER BY CASE
// WHEN language = 'pt-br' THEN 0
// WHEN language = 'pt' THEN 1
// WHEN language = 'und' THEN 2
// END DESC
// This ensures the most specific language comes last in the
// result set (and most recent aliases come last within that due
// to the secondary sort on pid). The use of fetchAllKeyed()
// ensures that the last result for any source-alias pair is the
// one that gets used.
$candidates = array_keys($candidates);
array_unshift($candidates, $path_language);
$candidates[] = LANGUAGE_NONE;
unset($args[':language'], $args[':language_none']);
$query = "SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (";
$candidate_args = array();
$order = "";
foreach (array_values($candidates) as $i => $candidate_langcode) {
$candidate_args[':candidate_' . $i] = $candidate_langcode;
$order .= " WHEN language = :candidate_{$i} THEN {$i}";
}
$args += $candidate_args;
$query .= implode(', ', array_keys($candidate_args)) . ") ORDER BY CASE {$order} END DESC, pid ASC";
$result = db_query($query, $args);
}
elseif ($path_language > LANGUAGE_NONE) {
$result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language ASC, pid ASC', $args);
}
else {
$result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language DESC, pid ASC', $args);
}
$cache['map'][$path_language] = $result
->fetchAllKeyed();
// Keep a record of paths with no alias to avoid querying twice.
$cache['no_aliases'][$path_language] = array_flip(array_diff_key($cache['system_paths'], array_keys($cache['map'][$path_language])));
}
}
// If the alias has already been loaded, return it.
if (isset($cache['map'][$path_language][$path])) {
return $cache['map'][$path_language][$path];
}
elseif (!isset($cache['whitelist'][strtok($path, '/')])) {
return FALSE;
}
elseif (!isset($cache['no_aliases'][$path_language][$path])) {
$args = array(
':source' => $path,
':language' => $path_language,
':language_none' => LANGUAGE_NONE,
);
// See the queries above.
if ($path_language == LANGUAGE_NONE) {
unset($args[':language']);
$alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language = :language_none ORDER BY pid DESC", $args)
->fetchField();
}
elseif ($candidates = language_hierarchy_get_ancestors($path_language, TRUE)) {
$candidates = array_keys($candidates);
array_unshift($candidates, $path_language);
$candidates[] = LANGUAGE_NONE;
unset($args[':language'], $args[':language_none']);
$query = "SELECT alias FROM {url_alias} WHERE source = :source AND language IN (";
$candidate_args = array();
$order = "";
foreach (array_values($candidates) as $i => $candidate_langcode) {
$candidate_args[':candidate_' . $i] = $candidate_langcode;
$order .= " WHEN language = :candidate_{$i} THEN {$i}";
}
$args += $candidate_args;
$query .= implode(', ', array_keys($candidate_args)) . ") ORDER BY CASE {$order} END ASC, pid DESC";
$alias = db_query($query, $args)
->fetchField();
}
elseif ($path_language > LANGUAGE_NONE) {
$alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", $args)
->fetchField();
}
else {
$alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language ASC, pid DESC", $args)
->fetchField();
}
$cache['map'][$path_language][$path] = $alias;
return $alias;
}
}
elseif ($action == 'source' && !isset($cache['no_source'][$path_language][$path])) {
// Look for the value $path within the cached $map
$source = FALSE;
if (!isset($cache['map'][$path_language]) || !($source = array_search($path, $cache['map'][$path_language]))) {
$args = array(
':alias' => $path,
':language' => $path_language,
':language_none' => LANGUAGE_NONE,
);
// See the queries above.
if ($path_language == LANGUAGE_NONE) {
unset($args[':language']);
$result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language = :language_none ORDER BY pid DESC", $args);
}
elseif ($candidates = language_hierarchy_get_ancestors($path_language, TRUE)) {
$candidates = array_keys($candidates);
array_unshift($candidates, $path_language);
$candidates[] = LANGUAGE_NONE;
unset($args[':language'], $args[':language_none']);
$query = "SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (";
$candidate_args = array();
$order = "";
foreach (array_values($candidates) as $i => $candidate_langcode) {
$candidate_args[':candidate_' . $i] = $candidate_langcode;
$order .= " WHEN language = :candidate_{$i} THEN {$i}";
}
$args += $candidate_args;
$query .= implode(', ', array_keys($candidate_args)) . ") ORDER BY CASE {$order} END ASC, pid DESC";
$result = db_query($query, $args);
}
elseif ($path_language > LANGUAGE_NONE) {
$result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", $args);
}
else {
$result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language ASC, pid DESC", $args);
}
if ($source = $result
->fetchField()) {
$cache['map'][$path_language][$source] = $path;
}
else {
// We can't record anything into $map because we do not have a valid
// index and there is no need because we have not learned anything
// about any Drupal path. Thus cache to $no_source.
$cache['no_source'][$path_language][$path] = TRUE;
}
}
return $source;
}
}
return FALSE;
}
}
Classes
Name | Description |
---|---|
languageHierarchyPaths | @file Class to extend Drupal path handling with fallbacks by language hierarchy. |