- Patch #1497230 by Rob Loach, pdrake, effulgentsia: Use Dependency Injection to handle object definitions.

8.0.x
Dries 2012-04-18 14:30:50 -04:00
parent 135c7866d4
commit 1f2622c8b8
12 changed files with 196 additions and 45 deletions

View File

@ -3,6 +3,7 @@
use Drupal\Core\Database\Database;
use Symfony\Component\ClassLoader\UniversalClassLoader;
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @file
@ -1353,12 +1354,11 @@ function drupal_unpack($obj, $field = 'data') {
* @ingroup sanitization
*/
function t($string, array $args = array(), array $options = array()) {
global $language_interface;
static $custom_strings;
// Merge in default.
if (empty($options['langcode'])) {
$options['langcode'] = isset($language_interface->langcode) ? $language_interface->langcode : LANGUAGE_SYSTEM;
$options['langcode'] = drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode;
}
if (empty($options['context'])) {
$options['context'] = '';
@ -2303,6 +2303,40 @@ function drupal_get_bootstrap_phase() {
return drupal_bootstrap();
}
/**
* Retrieves the Drupal Container to standardize object construction.
*
* Example:
* @code
* // Register the LANGUAGE_TYPE_INTERFACE definition. Registered definitions
* // do not necessarily need to be named by a constant.
* // See http://symfony.com/doc/current/components/dependency_injection.html
* // for usage examples of adding object initialization code after register().
* $container = drupal_container();
* $container->register(LANGUAGE_TYPE_INTERFACE, 'Drupal\\Core\\Language\\Language');
*
* // Retrieve the LANGUAGE_TYPE_INTERFACE object.
* $language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
* @endcode
*
* @param $reset
* TRUE or FALSE depending on whether the Container instance is to be reset.
*
* @return Symfony\Component\DependencyInjection\ContainerBuilder
* The instance of the Drupal Container used to set up and maintain object
* instances.
*/
function drupal_container($reset = FALSE) {
// We do not use drupal_static() here because we do not have a mechanism by
// which to reinitialize the stored objects, so a drupal_static_reset() call
// would leave Drupal in a nonfunctional state.
static $container = NULL;
if ($reset || !isset($container)) {
$container = new ContainerBuilder();
}
return $container;
}
/**
* Returns the test prefix if this is an internal request from SimpleTest.
*
@ -2445,27 +2479,44 @@ function get_t() {
/**
* Initializes all the defined language types.
*
* @see Drupal\Core\Language\Language
*/
function drupal_language_initialize() {
$types = language_types_get_all();
$container = drupal_container();
// Ensure the language is correctly returned, even without multilanguage
// support. Also make sure we have a $language fallback, in case a language
// negotiation callback needs to do a full bootstrap.
// Useful for eg. XML/HTML 'lang' attributes.
$default = language_default();
foreach ($types as $type) {
$GLOBALS[$type] = $default;
}
// Ensure a language object is registered for each language type, whether the
// site is multilingual or not.
if (language_multilingual()) {
include_once DRUPAL_ROOT . '/core/includes/language.inc';
foreach ($types as $type) {
$GLOBALS[$type] = language_types_initialize($type);
$language = language_types_initialize($type);
$container->set($type, NULL);
$container->register($type, 'Drupal\\Core\\Language\\Language')
->addMethodCall('extend', array($language));
}
// Allow modules to react on language system initialization in multilingual
// environments.
bootstrap_invoke_all('language_init');
}
else {
$default = language_default();
foreach ($types as $type) {
$container->set($type, NULL);
$container->register($type, 'Drupal\\Core\\Language\\Language')
->addMethodCall('extend', array($default));
}
}
// @todo Temporary backwards compatibility for code still using globals.
// Remove after these issues:
// - $language_interface: http://drupal.org/node/1510686
// - $language_url: http://drupal.org/node/1512310
// - $language_content: http://drupal.org/node/1512308
foreach ($types as $type) {
$GLOBALS[$type] = $container->get($type);
}
}
/**

View File

@ -1653,8 +1653,7 @@ function filter_xss_bad_protocol($string, $decode = TRUE) {
* Arbitrary elements may be added using the $args associative array.
*/
function format_rss_channel($title, $link, $description, $items, $langcode = NULL, $args = array()) {
global $language_content;
$langcode = $langcode ? $langcode : $language_content->langcode;
$langcode = $langcode ? $langcode : drupal_container()->get(LANGUAGE_TYPE_CONTENT)->langcode;
$output = "<channel>\n";
$output .= ' <title>' . check_plain($title) . "</title>\n";
@ -1955,10 +1954,8 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL
$timezones[$timezone] = timezone_open($timezone);
}
// Use the default langcode if none is set.
global $language_interface;
if (empty($langcode)) {
$langcode = isset($language_interface->langcode) ? $language_interface->langcode : LANGUAGE_SYSTEM;
$langcode = drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode;
}
switch ($type) {
@ -2398,7 +2395,6 @@ function drupal_attributes(array $attributes = array()) {
* An HTML string containing a link to the given path.
*/
function l($text, $path, array $options = array()) {
global $language_url;
static $use_theme = NULL;
// Merge in defaults.
@ -2409,7 +2405,7 @@ function l($text, $path, array $options = array()) {
// Append active class.
if (($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) &&
(empty($options['language']) || $options['language']->langcode == $language_url->langcode)) {
(empty($options['language']) || $options['language']->langcode == drupal_container()->get(LANGUAGE_TYPE_URL)->langcode)) {
$options['attributes']['class'][] = 'active';
}
@ -2565,9 +2561,7 @@ function drupal_deliver_html_page($page_callback_result) {
drupal_add_http_header('X-UA-Compatible', 'IE=edge,chrome=1');
}
// Send appropriate HTTP-Header for browsers and search engines.
global $language_interface;
drupal_add_http_header('Content-Language', $language_interface->langcode);
drupal_add_http_header('Content-Language', drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode);
// Menu status constants are integers; page content is a string or array.
if (is_int($page_callback_result)) {

View File

@ -25,6 +25,10 @@ function language_types_initialize($type) {
$negotiation = variable_get("language_negotiation_$type", array());
foreach ($negotiation as $method_id => $method) {
// Skip negotiation methods not appropriate for this type.
if (isset($method['types']) && !in_array($type, $method['types'])) {
continue;
}
$language = language_negotiation_method_invoke($method_id, $method);
if ($language) {
// Remember the method ID used to detect the language.

View File

@ -1096,10 +1096,12 @@ function menu_tree_output($tree) {
function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
$tree = &drupal_static(__FUNCTION__, array());
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
// Use $mlid as a flag for whether the data being loaded is for the whole tree.
$mlid = isset($link['mlid']) ? $link['mlid'] : 0;
// Generate a cache ID (cid) specific for this $menu_name, $link, $language, and depth.
$cid = 'links:' . $menu_name . ':all:' . $mlid . ':' . $GLOBALS['language_interface']->langcode . ':' . (int) $max_depth;
$cid = 'links:' . $menu_name . ':all:' . $mlid . ':' . $language_interface->langcode . ':' . (int) $max_depth;
if (!isset($tree[$cid])) {
// If the static variable doesn't have the data, check {cache_menu}.
@ -1205,6 +1207,8 @@ function menu_tree_get_path($menu_name) {
function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE) {
$tree = &drupal_static(__FUNCTION__, array());
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
// Check if the active trail has been overridden for this menu tree.
$active_path = menu_tree_get_path($menu_name);
// Load the menu item corresponding to the current page.
@ -1213,7 +1217,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
$max_depth = min($max_depth, MENU_MAX_DEPTH);
}
// Generate a cache ID (cid) specific for this page.
$cid = 'links:' . $menu_name . ':page:' . $item['href'] . ':' . $GLOBALS['language_interface']->langcode . ':' . (int) $item['access'] . ':' . (int) $max_depth;
$cid = 'links:' . $menu_name . ':page:' . $item['href'] . ':' . $language_interface->langcode . ':' . (int) $item['access'] . ':' . (int) $max_depth;
// If we are asked for the active trail only, and $menu_name has not been
// built and cached for this page yet, then this likely means that it
// won't be built anymore, as this function is invoked from
@ -1360,12 +1364,14 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
// Static cache of already built menu trees.
$trees = &drupal_static(__FUNCTION__, array());
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
// Build the cache id; sort parents to prevent duplicate storage and remove
// default parameter values.
if (isset($parameters['expanded'])) {
sort($parameters['expanded']);
}
$tree_cid = 'links:' . $menu_name . ':tree-data:' . $GLOBALS['language_interface']->langcode . ':' . hash('sha256', serialize($parameters));
$tree_cid = 'links:' . $menu_name . ':tree-data:' . $language_interface->langcode . ':' . hash('sha256', serialize($parameters));
// If we do not have this tree in the static cache, check {cache_menu}.
if (!isset($trees[$tree_cid])) {

View File

@ -43,7 +43,6 @@ function drupal_path_initialize() {
* found.
*/
function drupal_lookup_path($action, $path = '', $langcode = 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)) {
@ -74,7 +73,7 @@ function drupal_lookup_path($action, $path = '', $langcode = NULL) {
// 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.
$langcode = $langcode ? $langcode : $language_url->langcode;
$langcode = $langcode ? $langcode : drupal_container()->get(LANGUAGE_TYPE_URL)->langcode;
if ($action == 'wipe') {
$cache = array();

View File

@ -1684,7 +1684,7 @@ function theme_link($variables) {
* http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
*/
function theme_links($variables) {
global $language_url;
$language_url = drupal_container()->get(LANGUAGE_TYPE_URL);
$links = $variables['links'];
$attributes = $variables['attributes'];
@ -2466,6 +2466,8 @@ function template_process(&$variables, $hook) {
* @see html.tpl.php
*/
function template_preprocess_html(&$variables) {
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
// Compile a list of classes that are going to be applied to the body element.
// This allows advanced theming based on context (home page, node of certain type, etc.).
// Add a class that tells us whether we're on the front page or not.
@ -2509,8 +2511,8 @@ function template_preprocess_html(&$variables) {
$variables['body_attributes_array'] = array();
// HTML element attributes.
$variables['html_attributes_array']['lang'] = $GLOBALS['language_interface']->langcode;
$variables['html_attributes_array']['dir'] = $GLOBALS['language_interface']->direction ? 'rtl' : 'ltr';
$variables['html_attributes_array']['lang'] = $language_interface->langcode;
$variables['html_attributes_array']['dir'] = $language_interface->direction ? 'rtl' : 'ltr';
// Add favicon.
if (theme_get_setting('toggle_favicon')) {
@ -2559,6 +2561,8 @@ function template_preprocess_html(&$variables) {
* @see page.tpl.php
*/
function template_preprocess_page(&$variables) {
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
// Move some variables to the top level for themer convenience and template cleanliness.
$variables['show_messages'] = $variables['page']['#show_messages'];
@ -2580,8 +2584,8 @@ function template_preprocess_page(&$variables) {
$variables['base_path'] = base_path();
$variables['front_page'] = url();
$variables['feed_icons'] = drupal_get_feeds();
$variables['language'] = $GLOBALS['language_interface'];
$variables['language']->dir = $GLOBALS['language_interface']->direction ? 'rtl' : 'ltr';
$variables['language'] = $language_interface;
$variables['language']->dir = $language_interface->direction ? 'rtl' : 'ltr';
$variables['logo'] = theme_get_setting('logo');
$variables['main_menu'] = theme_get_setting('toggle_main_menu') ? menu_main_menu() : array();
$variables['secondary_menu'] = theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() : array();
@ -2782,8 +2786,7 @@ function template_preprocess_maintenance_page(&$variables) {
}
}
// set the default language if necessary
$language = isset($GLOBALS['language_interface']) ? $GLOBALS['language_interface'] : language_default();
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
$variables['head_title_array'] = $head_title;
$variables['head_title'] = implode(' | ', $head_title);
@ -2792,8 +2795,8 @@ function template_preprocess_maintenance_page(&$variables) {
$variables['breadcrumb'] = '';
$variables['feed_icons'] = '';
$variables['help'] = '';
$variables['language'] = $language;
$variables['language']->dir = $language->direction ? 'rtl' : 'ltr';
$variables['language'] = $language_interface;
$variables['language']->dir = $language_interface->direction ? 'rtl' : 'ltr';
$variables['logo'] = theme_get_setting('logo');
$variables['messages'] = $variables['show_messages'] ? theme('status_messages') : '';
$variables['main_menu'] = array();

View File

@ -52,8 +52,7 @@ const LANGUAGE_NEGOTIATION_URL_DOMAIN = 1;
* The current interface language code.
*/
function language_from_interface() {
global $language_interface;
return isset($language_interface->langcode) ? $language_interface->langcode : FALSE;
return drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode;
}
/**
@ -284,7 +283,7 @@ function language_url_fallback($language = NULL, $language_type = LANGUAGE_TYPE_
return $default->langcode;
}
else {
return $GLOBALS[$language_type]->langcode;
return drupal_container()->get($language_type)->langcode;
}
}
@ -361,7 +360,7 @@ function language_url_rewrite_url(&$path, &$options) {
// Language can be passed as an option, or we go for current URL language.
if (!isset($options['language'])) {
global $language_url;
$language_url = drupal_container()->get(LANGUAGE_TYPE_URL);
$options['language'] = $language_url;
}
// We allow only enabled languages here.

View File

@ -6,9 +6,9 @@
*
* The test file includes:
* - a functional test for the language configuration forms;
* - comparison of $GLOBALS default language against dependency injection;
*/
/**
* Functional tests for the language list configuration forms.
*/
@ -179,3 +179,90 @@ class LanguageListTest extends DrupalWebTestCase {
$this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The English language has been removed.'));
}
}
/**
* Test for dependency injected language object.
*/
class LanguageDependencyInjectionTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Language dependency injection',
'description' => 'Compares the default language from $GLOBALS against the dependency injected language object.',
'group' => 'Language',
);
}
function setUp() {
parent::setUp('language');
// Set up a new container to ensure we are building a new Language object
// for each test.
drupal_container(TRUE);
}
/**
* Test dependency injected Language against the GLOBAL language object.
*
* @todo Once the PHP global is gone, we won't need this test as the same
* test is done without the PHP global in the following test.
*/
function testDependencyInjectedLanguage() {
// Initialize the language system.
drupal_language_initialize();
$expected = $GLOBALS[LANGUAGE_TYPE_INTERFACE];
$result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
foreach ($expected as $property => $value) {
$this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the $GLOBAL language object %prop property.', array('%prop' => $property)));
}
}
/**
* Test dependency injected languages against a new Language object.
*
* @see Drupal\Core\Language\Language
*/
function testDependencyInjectedNewLanguage() {
// Initialize the language system.
drupal_language_initialize();
$expected = new Drupal\Core\Language\Language((array) language_default());
$result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
foreach ($expected as $property => $value) {
$this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the new Language object %prop property.', array('%prop' => $property)));
}
}
/**
* Test dependency injected Language object against a new default language
* object.
*
* @see Drupal\Core\Language\Language
*/
function testDependencyInjectedNewDefaultLanguage() {
// Change the language default object to different values.
$new_language_default = (object) array(
'langcode' => 'fr',
'name' => 'French',
'direction' => 0,
'enabled' => 1,
'weight' => 0,
'default' => TRUE,
);
variable_set('language_default', $new_language_default);
// Initialize the language system.
drupal_language_initialize();
// The langauge system creates a Language object which contains the
// same properties as the new default language object.
$expected = $new_language_default;
$result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
foreach ($expected as $property => $value) {
$this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the default language object %prop property.', array('%prop' => $property)));
}
// Delete the language_default variable we previously set.
variable_del('language_default');
}
}

View File

@ -1064,8 +1064,7 @@ function _locale_invalidate_js($langcode = NULL) {
*/
function _locale_rebuild_js($langcode = NULL) {
if (!isset($langcode)) {
global $language_interface;
$language = $language_interface;
$language = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
}
else {
// Get information about the locale.

View File

@ -24,9 +24,9 @@
* did not happen yet and thus they cannot rely on translated variables.
*/
function hook_language_init() {
global $language_interface, $conf;
global $conf;
switch ($language_interface->langcode) {
switch (drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode) {
case 'it':
$conf['site_name'] = 'Il mio sito Drupal';
break;

View File

@ -2438,7 +2438,9 @@ class CommonFormatDateTestCase extends DrupalWebTestCase {
* Tests for the format_date() function.
*/
function testFormatDate() {
global $user, $language_interface;
global $user;
$language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
$timestamp = strtotime('2007-03-26T00:00:00+00:00');
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', t('Test all parameters.'));

View File

@ -382,8 +382,15 @@ drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
// The interface language global has been renamed in D8, we must ensure that it
// contains a valid value while language settings are upgraded.
// @todo Remove this globals reference entirely: http://drupal.org/node/1510686
$GLOBALS[LANGUAGE_TYPE_INTERFACE] = language_default();
// Ensure the default language is properly registered within the Dependency
// Injection container during the upgrade process.
$default = language_default();
drupal_container()->register(LANGUAGE_TYPE_INTERFACE, 'Drupal\\Core\\Language\\Language')
->addMethodCall('extend', array($default));
// Only allow the requirements check to proceed if the current user has access
// to run updates (since it may expose sensitive information about the site's
// configuration).