Update to Drupal 8.0.0-beta15. For more information, see: https://www.drupal.org/node/2563023
This commit is contained in:
parent
2720a9ec4b
commit
f3791f1da3
1898 changed files with 54300 additions and 11481 deletions
|
@ -342,9 +342,12 @@ class Registry implements DestructableInterface {
|
|||
$this->processExtension($cache, $this->theme->getEngine(), 'theme_engine', $this->theme->getName(), $this->theme->getPath());
|
||||
}
|
||||
|
||||
// Finally, hooks provided by the theme itself.
|
||||
// Hooks provided by the theme itself.
|
||||
$this->processExtension($cache, $this->theme->getName(), 'theme', $this->theme->getName(), $this->theme->getPath());
|
||||
|
||||
// Discover and add all preprocess functions for theme hook suggestions.
|
||||
$this->postProcessExtension($cache, $this->theme);
|
||||
|
||||
// Let modules and themes alter the registry.
|
||||
$this->moduleHandler->alter('theme_registry', $cache);
|
||||
$this->themeManager->alterForTheme($this->theme, 'theme_registry', $cache);
|
||||
|
@ -420,7 +423,7 @@ class Registry implements DestructableInterface {
|
|||
'base hook' => TRUE,
|
||||
);
|
||||
|
||||
$module_list = array_keys((array) $this->moduleHandler->getModuleList());
|
||||
$module_list = array_keys($this->moduleHandler->getModuleList());
|
||||
|
||||
// Invoke the hook_theme() implementation, preprocess what is returned, and
|
||||
// merge it into $cache.
|
||||
|
@ -438,10 +441,23 @@ class Registry implements DestructableInterface {
|
|||
$result[$hook]['type'] = $type;
|
||||
$result[$hook]['theme path'] = $path;
|
||||
|
||||
// If a theme hook has a base hook, mark its preprocess functions always
|
||||
// incomplete in order to inherit the base hook's preprocess functions.
|
||||
if (!empty($result[$hook]['base hook'])) {
|
||||
$result[$hook]['incomplete preprocess functions'] = TRUE;
|
||||
}
|
||||
|
||||
if (isset($cache[$hook]['includes'])) {
|
||||
$result[$hook]['includes'] = $cache[$hook]['includes'];
|
||||
}
|
||||
|
||||
// Load the includes, as they may contain preprocess functions.
|
||||
if (isset($info['includes'])) {
|
||||
foreach ($info['includes'] as $include_file) {
|
||||
include_once $this->root . '/' . $include_file;
|
||||
}
|
||||
}
|
||||
|
||||
// If the theme implementation defines a file, then also use the path
|
||||
// that it defined. Otherwise use the default path. This allows
|
||||
// system.module to declare theme functions on behalf of core .include
|
||||
|
@ -556,13 +572,142 @@ class Registry implements DestructableInterface {
|
|||
$cache[$hook]['preprocess functions'][] = $name . '_preprocess_' . $hook;
|
||||
$cache[$hook]['theme path'] = $path;
|
||||
}
|
||||
// Ensure uniqueness.
|
||||
$cache[$hook]['preprocess functions'] = array_unique($cache[$hook]['preprocess functions']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the definition of the requested suggestion hook.
|
||||
*
|
||||
* @param string $hook
|
||||
* The name of the suggestion hook to complete.
|
||||
* @param array $cache
|
||||
* The theme registry, as documented in
|
||||
* \Drupal\Core\Theme\Registry::processExtension().
|
||||
*/
|
||||
protected function completeSuggestion($hook, array &$cache) {
|
||||
$previous_hook = $hook;
|
||||
$incomplete_previous_hook = array();
|
||||
while ((!isset($cache[$previous_hook]) || isset($cache[$previous_hook]['incomplete preprocess functions']))
|
||||
&& $pos = strrpos($previous_hook, '__')) {
|
||||
if (isset($cache[$previous_hook]) && !$incomplete_previous_hook && isset($cache[$previous_hook]['incomplete preprocess functions'])) {
|
||||
$incomplete_previous_hook = $cache[$previous_hook];
|
||||
unset($incomplete_previous_hook['incomplete preprocess functions']);
|
||||
}
|
||||
$previous_hook = substr($previous_hook, 0, $pos);
|
||||
|
||||
// If base hook exists clone of it for the preprocess function
|
||||
// without a template.
|
||||
// @see https://www.drupal.org/node/2457295
|
||||
if (isset($cache[$previous_hook]) && !isset($cache[$previous_hook]['incomplete preprocess functions'])) {
|
||||
$cache[$hook] = $incomplete_previous_hook + $cache[$previous_hook];
|
||||
if (isset($incomplete_previous_hook['preprocess functions'])) {
|
||||
$diff = array_diff($incomplete_previous_hook['preprocess functions'], $cache[$previous_hook]['preprocess functions']);
|
||||
$cache[$hook]['preprocess functions'] = array_merge($cache[$previous_hook]['preprocess functions'], $diff);
|
||||
}
|
||||
// If a base hook isn't set, this is the actual base hook.
|
||||
if (!isset($cache[$previous_hook]['base hook'])) {
|
||||
$cache[$hook]['base hook'] = $previous_hook;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the theme registry adding discovered functions and hooks.
|
||||
*
|
||||
* @param array $cache
|
||||
* The theme registry as documented in
|
||||
* \Drupal\Core\Theme\Registry::processExtension().
|
||||
* @param \Drupal\Core\Theme\ActiveTheme $theme
|
||||
* Current active theme.
|
||||
*
|
||||
* @see ::processExtension()
|
||||
*/
|
||||
protected function postProcessExtension(array &$cache, ActiveTheme $theme) {
|
||||
$grouped_functions = $this->getPrefixGroupedUserFunctions();
|
||||
|
||||
// Gather prefixes. This will be used to limit the found functions to the
|
||||
// expected naming conventions.
|
||||
$prefixes = array_keys((array) $this->moduleHandler->getModuleList());
|
||||
foreach (array_reverse($theme->getBaseThemes()) as $base) {
|
||||
$prefixes[] = $base->getName();
|
||||
}
|
||||
if ($theme->getEngine()) {
|
||||
$prefixes[] = $theme->getEngine() . '_engine';
|
||||
}
|
||||
$prefixes[] = $theme->getName();
|
||||
|
||||
// Collect all variable preprocess functions in the correct order.
|
||||
$suggestion_level = [];
|
||||
$matches = [];
|
||||
// Look for functions named according to the pattern and add them if they
|
||||
// have matching hooks in the registry.
|
||||
foreach ($prefixes as $prefix) {
|
||||
// Grep only the functions which are within the prefix group.
|
||||
list($first_prefix,) = explode('_', $prefix, 2);
|
||||
if (!isset($grouped_functions[$first_prefix])) {
|
||||
continue;
|
||||
}
|
||||
// Add the function and the name of the associated theme hook to the list
|
||||
// of preprocess functions grouped by suggestion specificity if a matching
|
||||
// base hook is found.
|
||||
foreach ($grouped_functions[$first_prefix] as $candidate) {
|
||||
if (preg_match("/^{$prefix}_preprocess_(((?:[^_]++|_(?!_))+)__.*)/", $candidate, $matches)) {
|
||||
if (isset($cache[$matches[2]])) {
|
||||
$level = substr_count($matches[1], '__');
|
||||
$suggestion_level[$level][$candidate] = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add missing variable preprocessors. This is needed for modules that do
|
||||
// not explicitly register the hook. For example, when a theme contains a
|
||||
// variable preprocess function but it does not implement a template, it
|
||||
// will go missing. This will add the expected function. It also allows
|
||||
// modules or themes to have a variable process function based on a pattern
|
||||
// even if the hook does not exist.
|
||||
ksort($suggestion_level);
|
||||
foreach ($suggestion_level as $level => $item) {
|
||||
foreach ($item as $preprocessor => $hook) {
|
||||
if (isset($cache[$hook]['preprocess functions']) && !in_array($hook, $cache[$hook]['preprocess functions'])) {
|
||||
// Add missing preprocessor to existing hook.
|
||||
$cache[$hook]['preprocess functions'][] = $preprocessor;
|
||||
}
|
||||
elseif (!isset($cache[$hook]) && strpos($hook, '__')) {
|
||||
// Process non-existing hook and register it.
|
||||
// Look for a previously defined hook that is either a less specific
|
||||
// suggestion hook or the base hook.
|
||||
$this->completeSuggestion($hook, $cache);
|
||||
$cache[$hook]['preprocess functions'][] = $preprocessor;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inherit all base hook variable preprocess functions into suggestion
|
||||
// hooks. This ensures that derivative hooks have a complete set of variable
|
||||
// preprocess functions.
|
||||
foreach ($cache as $hook => $info) {
|
||||
// The 'base hook' is only applied to derivative hooks already registered
|
||||
// from a pattern. This is typically set from
|
||||
// drupal_find_theme_functions() and drupal_find_theme_templates().
|
||||
if (isset($info['incomplete preprocess functions'])) {
|
||||
$this->completeSuggestion($hook, $cache);
|
||||
unset($cache[$hook]['incomplete preprocess functions']);
|
||||
}
|
||||
|
||||
// Optimize the registry.
|
||||
if (isset($cache[$hook]['preprocess functions']) && empty($cache[$hook]['preprocess functions'])) {
|
||||
unset($cache[$hook]['preprocess functions']);
|
||||
}
|
||||
// Ensure uniqueness.
|
||||
if (isset($cache[$hook]['preprocess functions'])) {
|
||||
$cache[$hook]['preprocess functions'] = array_unique($cache[$hook]['preprocess functions']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates theme registry caches.
|
||||
*
|
||||
|
@ -589,6 +734,25 @@ class Registry implements DestructableInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all user functions grouped by the word before the first underscore.
|
||||
*
|
||||
* @return array
|
||||
* Functions grouped by the first prefix.
|
||||
*/
|
||||
public function getPrefixGroupedUserFunctions() {
|
||||
$functions = get_defined_functions();
|
||||
|
||||
$grouped_functions = [];
|
||||
// Splitting user defined functions into groups by the first prefix.
|
||||
foreach ($functions['user'] as $function) {
|
||||
list($first_prefix,) = explode('_', $function, 2);
|
||||
$grouped_functions[$first_prefix][] = $function;
|
||||
}
|
||||
|
||||
return $grouped_functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps drupal_get_path().
|
||||
*
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Theme;
|
||||
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Routing\StackedRouteMatchInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
||||
/**
|
||||
* Provides the default implementation of a theme manager.
|
||||
|
@ -279,12 +280,10 @@ class ThemeManager implements ThemeManagerInterface {
|
|||
include_once $this->root . '/' . $include_file;
|
||||
}
|
||||
}
|
||||
// Replace the preprocess functions with those from the base hook.
|
||||
if (isset($base_hook_info['preprocess functions'])) {
|
||||
// Set a variable for the 'theme_hook_suggestion'. This is used to
|
||||
// maintain backwards compatibility with template engines.
|
||||
$theme_hook_suggestion = $hook;
|
||||
$info['preprocess functions'] = $base_hook_info['preprocess functions'];
|
||||
}
|
||||
}
|
||||
if (isset($info['preprocess functions'])) {
|
||||
|
@ -317,7 +316,10 @@ class ThemeManager implements ThemeManagerInterface {
|
|||
$output = '';
|
||||
if (isset($info['function'])) {
|
||||
if (function_exists($info['function'])) {
|
||||
$output = SafeMarkup::set($info['function']($variables));
|
||||
// Theme functions do not render via the theme engine, so the output is
|
||||
// not autoescaped. However, we can only presume that the theme function
|
||||
// has been written correctly and that the markup is safe.
|
||||
$output = SafeString::create($info['function']($variables));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -387,7 +389,7 @@ class ThemeManager implements ThemeManagerInterface {
|
|||
$output = $render_function($template_file, $variables);
|
||||
}
|
||||
|
||||
return (string) $output;
|
||||
return ($output instanceof SafeStringInterface) ? $output : (string) $output;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,8 +26,8 @@ interface ThemeManagerInterface {
|
|||
* @param array $variables
|
||||
* An associative array of theme variables.
|
||||
*
|
||||
* @return string
|
||||
* The rendered output.
|
||||
* @return string|\Drupal\Component\Utility\SafeStringInterface
|
||||
* The rendered output, or a SafeString object.
|
||||
*/
|
||||
public function render($hook, array $variables);
|
||||
|
||||
|
|
|
@ -14,9 +14,6 @@ use Drupal\Core\Routing\RouteMatchInterface;
|
|||
*
|
||||
* It therefore uses ThemeNegotiatorInterface objects which are passed in
|
||||
* using the 'theme_negotiator' tag.
|
||||
*
|
||||
* @see \Drupal\Core\Theme\ThemeNegotiatorPass
|
||||
* @see \Drupal\Core\Theme\ThemeNegotiatorInterface
|
||||
*/
|
||||
class ThemeNegotiator implements ThemeNegotiatorInterface {
|
||||
|
||||
|
|
Reference in a new issue