Using core's utility.inc to resolve merge conflict
commit
ce43402969
|
@ -1,7 +0,0 @@
|
|||
# Ignore configuration files that may contain sensitive information.
|
||||
sites/*/settings*.php
|
||||
|
||||
# Ignore paths that contain user-generated content.
|
||||
sites/*/files
|
||||
sites/*/private
|
||||
|
|
@ -16,12 +16,6 @@ Options +FollowSymLinks
|
|||
# Make Drupal handle any 404 errors.
|
||||
ErrorDocument 404 /index.php
|
||||
|
||||
# Force simple error message for requests for non-existent favicon.ico.
|
||||
<Files favicon.ico>
|
||||
# There is no end quote below, for compatibility with Apache 1.3.
|
||||
ErrorDocument 404 "The requested file favicon.ico was not found.
|
||||
</Files>
|
||||
|
||||
# Set the default handler.
|
||||
DirectoryIndex index.php index.html index.htm
|
||||
|
||||
|
@ -129,7 +123,7 @@ DirectoryIndex index.php index.html index.htm
|
|||
|
||||
<FilesMatch "(\.js\.gz|\.css\.gz)$">
|
||||
# Serve correct encoding type.
|
||||
Header append Content-Encoding gzip
|
||||
Header set Content-Encoding gzip
|
||||
# Force proxies to cache gzipped & non-gzipped css/js files separately.
|
||||
Header append Vary Accept-Encoding
|
||||
</FilesMatch>
|
||||
|
|
|
@ -32,6 +32,7 @@ Batch system
|
|||
|
||||
Cache system
|
||||
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
|
||||
- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
|
||||
|
||||
Cron system
|
||||
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
|
||||
|
@ -158,7 +159,7 @@ Color module
|
|||
- ?
|
||||
|
||||
Comment module
|
||||
- ?
|
||||
- Dick Olsson 'dixon_' <http://drupal.org/user/239911>
|
||||
|
||||
Contact module
|
||||
- Dave Reid 'davereid' <http://drupal.org/user/53892>
|
||||
|
|
|
@ -35,7 +35,7 @@ define('DRUPAL_ROOT', getcwd());
|
|||
define('MAINTENANCE_MODE', 'update');
|
||||
|
||||
/**
|
||||
* Render a 403 access denied page for authorize.php
|
||||
* Renders a 403 access denied page for authorize.php.
|
||||
*/
|
||||
function authorize_access_denied_page() {
|
||||
drupal_add_http_header('Status', '403 Forbidden');
|
||||
|
@ -45,7 +45,7 @@ function authorize_access_denied_page() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user is allowed to run authorize.php.
|
||||
* Determines if the current user is allowed to run authorize.php.
|
||||
*
|
||||
* The killswitch in settings.php overrides all else, otherwise, the user must
|
||||
* have access to the 'administer software updates' permission.
|
||||
|
@ -145,7 +145,7 @@ if (authorize_access_allowed()) {
|
|||
l(t('Front page'), '<front>'),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$output .= theme('item_list', array('items' => $links, 'title' => t('Next steps')));
|
||||
}
|
||||
// If a batch is running, let it run.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# To use this file simply copy it to .gitignore, and it will cause files like
|
||||
# your settings.php and user-uploaded files to be excluded from git source
|
||||
# control. This is a common strategy to avoid accidentally including private
|
||||
# information in public repositories and patch files.
|
||||
#
|
||||
# A .gitignore file was included in Drupal core for versions 7.2 through 7.8.
|
||||
# As of Drupal 7.9, this is no longer the case, and any changes made to your
|
||||
# .gitignore file will no longer be overwritten by core updates.
|
||||
|
||||
# Ignore configuration files that may contain sensitive information.
|
||||
sites/*/settings*.php
|
||||
|
||||
# Ignore paths that contain user-generated content.
|
||||
sites/*/files
|
||||
sites/*/private
|
||||
|
||||
# If you prefer to store your .gitignore file in the sites/ folder, comment
|
||||
# or delete the previous settings and uncomment the following ones, instead.
|
||||
|
||||
# Ignore configuration files that may contain sensitive information.
|
||||
# */settings*.php
|
||||
|
||||
# Ignore paths that contain user-generated content.
|
||||
# */files
|
||||
# */private
|
|
@ -28,7 +28,7 @@ define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '32M');
|
|||
/**
|
||||
* Indicates that the item should never be removed unless explicitly selected.
|
||||
*
|
||||
* The item may be removed using cache_clear_all() with a cache ID.
|
||||
* The item may be removed using cache()->delete() with a cache ID.
|
||||
*/
|
||||
define('CACHE_PERMANENT', 0);
|
||||
|
||||
|
@ -285,12 +285,12 @@ require_once DRUPAL_ROOT . '/includes/config.inc';
|
|||
abstract class DrupalCacheArray implements ArrayAccess {
|
||||
|
||||
/**
|
||||
* A cid to pass to cache_set() and cache_get().
|
||||
* A cid to pass to cache()->set() and cache()->get().
|
||||
*/
|
||||
private $cid;
|
||||
|
||||
/**
|
||||
* A bin to pass to cache_set() and cache_get().
|
||||
* A bin to pass to cache()->set() and cache()->get().
|
||||
*/
|
||||
private $bin;
|
||||
|
||||
|
@ -316,7 +316,7 @@ abstract class DrupalCacheArray implements ArrayAccess {
|
|||
$this->cid = $cid;
|
||||
$this->bin = $bin;
|
||||
|
||||
if ($cached = cache_get($this->cid, $this->bin)) {
|
||||
if ($cached = cache($bin)->get($this->cid)) {
|
||||
$this->storage = $cached->data;
|
||||
}
|
||||
}
|
||||
|
@ -393,10 +393,10 @@ abstract class DrupalCacheArray implements ArrayAccess {
|
|||
// To implement locking for cache misses, override __construct().
|
||||
$lock_name = $cid . ':' . $bin;
|
||||
if (!$lock || lock_acquire($lock_name)) {
|
||||
if ($cached = cache_get($cid, $bin)) {
|
||||
if ($cached = cache($bin)->get($cid)) {
|
||||
$data = $cached->data + $data;
|
||||
}
|
||||
cache_set($cid, $data, $bin);
|
||||
cache($bin)->set($cid, $data);
|
||||
if ($lock) {
|
||||
lock_release($lock_name);
|
||||
}
|
||||
|
@ -491,22 +491,22 @@ function timer_stop($name) {
|
|||
* With a site located at http://www.example.com:8080/mysite/test/, the file,
|
||||
* settings.php, is searched for in the following directories:
|
||||
*
|
||||
* 1. $confdir/8080.www.example.com.mysite.test
|
||||
* 2. $confdir/www.example.com.mysite.test
|
||||
* 3. $confdir/example.com.mysite.test
|
||||
* 4. $confdir/com.mysite.test
|
||||
* - $confdir/8080.www.example.com.mysite.test
|
||||
* - $confdir/www.example.com.mysite.test
|
||||
* - $confdir/example.com.mysite.test
|
||||
* - $confdir/com.mysite.test
|
||||
*
|
||||
* 5. $confdir/8080.www.example.com.mysite
|
||||
* 6. $confdir/www.example.com.mysite
|
||||
* 7. $confdir/example.com.mysite
|
||||
* 8. $confdir/com.mysite
|
||||
* - $confdir/8080.www.example.com.mysite
|
||||
* - $confdir/www.example.com.mysite
|
||||
* - $confdir/example.com.mysite
|
||||
* - $confdir/com.mysite
|
||||
*
|
||||
* 9. $confdir/8080.www.example.com
|
||||
* 10. $confdir/www.example.com
|
||||
* 11. $confdir/example.com
|
||||
* 12. $confdir/com
|
||||
* - $confdir/8080.www.example.com
|
||||
* - $confdir/www.example.com
|
||||
* - $confdir/example.com
|
||||
* - $confdir/com
|
||||
*
|
||||
* 13. $confdir/default
|
||||
* - $confdir/default
|
||||
*
|
||||
* If a file named sites.php is present in the $confdir, it will be loaded
|
||||
* prior to scanning for directories. It should define an associative array
|
||||
|
@ -901,7 +901,7 @@ function drupal_get_filename($type, $name, $filename = NULL) {
|
|||
function variable_initialize($conf = array()) {
|
||||
// NOTE: caching the variables improves performance by 20% when serving
|
||||
// cached pages.
|
||||
if ($cached = cache_get('variables', 'cache_bootstrap')) {
|
||||
if ($cached = cache('bootstrap')->get('variables')) {
|
||||
$variables = $cached->data;
|
||||
}
|
||||
else {
|
||||
|
@ -916,7 +916,7 @@ function variable_initialize($conf = array()) {
|
|||
else {
|
||||
// Proceed with variable rebuild.
|
||||
$variables = array_map('unserialize', db_query('SELECT name, value FROM {variable}')->fetchAllKeyed());
|
||||
cache_set('variables', $variables, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('variables', $variables);
|
||||
lock_release($name);
|
||||
}
|
||||
}
|
||||
|
@ -973,7 +973,7 @@ function variable_set($name, $value) {
|
|||
|
||||
db_merge('variable')->key(array('name' => $name))->fields(array('value' => serialize($value)))->execute();
|
||||
|
||||
cache_clear_all('variables', 'cache_bootstrap');
|
||||
cache('bootstrap')->delete('variables');
|
||||
|
||||
$conf[$name] = $value;
|
||||
}
|
||||
|
@ -997,7 +997,7 @@ function variable_del($name) {
|
|||
db_delete('variable')
|
||||
->condition('name', $name)
|
||||
->execute();
|
||||
cache_clear_all('variables', 'cache_bootstrap');
|
||||
cache('bootstrap')->delete('variables');
|
||||
|
||||
unset($conf[$name]);
|
||||
}
|
||||
|
@ -1026,7 +1026,7 @@ function drupal_page_get_cache($check_only = FALSE) {
|
|||
}
|
||||
|
||||
if (drupal_page_is_cacheable()) {
|
||||
$cache = cache_get($base_root . request_uri(), 'cache_page');
|
||||
$cache = cache('page')->get($base_root . request_uri());
|
||||
if ($cache !== FALSE) {
|
||||
$cache_hit = TRUE;
|
||||
}
|
||||
|
@ -1393,10 +1393,11 @@ function drupal_unpack($obj, $field = 'data') {
|
|||
* The t() function serves two purposes. First, at run-time it translates
|
||||
* user-visible text into the appropriate language. Second, various mechanisms
|
||||
* that figure out what text needs to be translated work off t() -- the text
|
||||
* inside t() calls is added to the database of strings to be translated. So,
|
||||
* to enable a fully-translatable site, it is important that all human-readable
|
||||
* text that will be displayed on the site or sent to a user is passed through
|
||||
* the t() function, or a related function. See the
|
||||
* inside t() calls is added to the database of strings to be translated.
|
||||
* These strings are expected to be in English, so the first argument should
|
||||
* always be in English. To enable a fully-translatable site, it is important
|
||||
* that all human-readable text that will be displayed on the site or sent to
|
||||
* a user is passed through the t() function, or a related function. See the
|
||||
* @link http://drupal.org/node/322729 Localization API @endlink pages for
|
||||
* more information, including recommendations on how to break up or not
|
||||
* break up strings for translation.
|
||||
|
@ -1573,11 +1574,12 @@ function drupal_validate_utf8($text) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Since $_SERVER['REQUEST_URI'] is only available on Apache, we
|
||||
* generate an equivalent using other environment variables.
|
||||
* Returns the equivalent of Apache's $_SERVER['REQUEST_URI'] variable.
|
||||
*
|
||||
* Because $_SERVER['REQUEST_URI'] is only available on Apache, we generate an
|
||||
* equivalent using other environment variables.
|
||||
*/
|
||||
function request_uri() {
|
||||
|
||||
if (isset($_SERVER['REQUEST_URI'])) {
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
|
@ -2418,6 +2420,34 @@ function drupal_maintenance_theme() {
|
|||
_drupal_maintenance_theme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a simple 404 Not Found page.
|
||||
*
|
||||
* If fast 404 pages are enabled, and this is a matching page then print a
|
||||
* simple 404 page and exit.
|
||||
*
|
||||
* This function is called from drupal_deliver_html_page() at the time when a
|
||||
* a normal 404 page is generated, but it can also optionally be called directly
|
||||
* from settings.php to prevent a Drupal bootstrap on these pages. See
|
||||
* documentation in settings.php for the benefits and drawbacks of using this.
|
||||
*
|
||||
* Paths to dynamically-generated content, such as image styles, should also be
|
||||
* accounted for in this function.
|
||||
*/
|
||||
function drupal_fast_404() {
|
||||
$exclude_paths = variable_get('404_fast_paths_exclude', FALSE);
|
||||
if ($exclude_paths && !preg_match($exclude_paths, $_GET['q'])) {
|
||||
$fast_paths = variable_get('404_fast_paths', FALSE);
|
||||
if ($fast_paths && preg_match($fast_paths, $_GET['q'])) {
|
||||
drupal_add_http_header('Status', '404 Not Found');
|
||||
$fast_404_html = variable_get('404_fast_html', '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
|
||||
// Replace @path in the variable with the page path.
|
||||
print strtr($fast_404_html, array('@path' => check_plain(request_uri())));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if a Drupal installation is currently being attempted.
|
||||
*/
|
||||
|
@ -2560,14 +2590,28 @@ function language_list($field = 'language') {
|
|||
}
|
||||
|
||||
/**
|
||||
* Default language used on the site
|
||||
* Default language used on the site.
|
||||
*
|
||||
* @param $property
|
||||
* Optional property of the language object to return
|
||||
* @return
|
||||
* A language object.
|
||||
*/
|
||||
function language_default($property = NULL) {
|
||||
$language = variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => ''));
|
||||
return $property ? $language->$property : $language;
|
||||
function language_default() {
|
||||
return variable_get(
|
||||
'language_default',
|
||||
(object) array(
|
||||
'language' => 'en',
|
||||
'name' => 'English',
|
||||
'native' => 'English',
|
||||
'direction' => 0,
|
||||
'enabled' => 1,
|
||||
'plurals' => 0,
|
||||
'formula' => '',
|
||||
'domain' => '',
|
||||
'prefix' => '',
|
||||
'weight' => 0,
|
||||
'javascript' => ''
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2792,7 +2836,7 @@ function drupal_get_complete_schema($rebuild = FALSE) {
|
|||
|
||||
if (empty($schema) || $rebuild) {
|
||||
// Try to load the schema from cache.
|
||||
if (!$rebuild && $cached = cache_get('schema')) {
|
||||
if (!$rebuild && $cached = cache()->get('schema')) {
|
||||
$schema = $cached->data;
|
||||
}
|
||||
// Otherwise, rebuild the schema cache.
|
||||
|
@ -2818,7 +2862,7 @@ function drupal_get_complete_schema($rebuild = FALSE) {
|
|||
// That would break modules which use $schema further down the line.
|
||||
$current = (array) module_invoke($module, 'schema');
|
||||
// Set 'module' and 'name' keys for each table, and remove descriptions,
|
||||
// as they needlessly slow down cache_get() for every single request.
|
||||
// as they needlessly slow down cache()->get() for every single request.
|
||||
_drupal_schema_initialize($current, $module);
|
||||
$schema = array_merge($schema, $current);
|
||||
}
|
||||
|
@ -2827,10 +2871,10 @@ function drupal_get_complete_schema($rebuild = FALSE) {
|
|||
// If the schema is empty, avoid saving it: some database engines require
|
||||
// the schema to perform queries, and this could lead to infinite loops.
|
||||
if (!empty($schema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) {
|
||||
cache_set('schema', $schema);
|
||||
cache()->set('schema', $schema);
|
||||
}
|
||||
if ($rebuild) {
|
||||
cache_clear_all('schema:', 'cache', TRUE);
|
||||
cache()->deletePrefix('schema:');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2901,7 +2945,7 @@ function _registry_check_code($type, $name = NULL) {
|
|||
|
||||
if (!isset($lookup_cache)) {
|
||||
$lookup_cache = array();
|
||||
if ($cache = cache_get('lookup_cache', 'cache_bootstrap')) {
|
||||
if ($cache = cache('bootstrap')->get('lookup_cache')) {
|
||||
$lookup_cache = $cache->data;
|
||||
}
|
||||
}
|
||||
|
@ -2918,7 +2962,7 @@ function _registry_check_code($type, $name = NULL) {
|
|||
// changes to the lookup cache for this request.
|
||||
if ($type == REGISTRY_WRITE_LOOKUP_CACHE) {
|
||||
if ($cache_update_needed) {
|
||||
cache_set('lookup_cache', $lookup_cache, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('lookup_cache', $lookup_cache);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,16 @@ class DrupalFakeCache extends DrupalDatabaseCache implements DrupalCacheInterfac
|
|||
function set($cid, $data, $expire = CACHE_PERMANENT) {
|
||||
}
|
||||
|
||||
function deletePrefix($cid) {
|
||||
try {
|
||||
if (class_exists('Database')) {
|
||||
parent::deletePrefix($cid);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
function clear($cid = NULL, $wildcard = FALSE) {
|
||||
// If there is a database cache, attempt to clear it whenever possible. The
|
||||
// reason for doing this is that the database cache can accumulate data
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Get the cache object for a cache bin.
|
||||
* Factory for instantiating and statically caching the correct class for a cache bin.
|
||||
*
|
||||
* By default, this returns an instance of the DrupalDatabaseCache class.
|
||||
* Classes implementing DrupalCacheInterface can register themselves both as a
|
||||
|
@ -10,11 +10,16 @@
|
|||
* @see DrupalCacheInterface
|
||||
*
|
||||
* @param $bin
|
||||
* The cache bin for which the cache object should be returned.
|
||||
* The cache bin for which the cache object should be returned, defaults to
|
||||
* 'cache'.
|
||||
* @return DrupalCacheInterface
|
||||
* The cache object associated with the specified bin.
|
||||
*/
|
||||
function _cache_get_object($bin) {
|
||||
function cache($bin = 'cache') {
|
||||
// Temporary backwards compatibiltiy layer, allow old style prefixed cache
|
||||
// bin names to be passed as arguments.
|
||||
$bin = str_replace('cache_', '', $bin);
|
||||
|
||||
// We do not use drupal_static() here because we do not want to change the
|
||||
// storage of a cache bin mid-request.
|
||||
static $cache_objects;
|
||||
|
@ -46,7 +51,7 @@ function _cache_get_object($bin) {
|
|||
* The cache or FALSE on failure.
|
||||
*/
|
||||
function cache_get($cid, $bin = 'cache') {
|
||||
return _cache_get_object($bin)->get($cid);
|
||||
return cache($bin)->get($cid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,7 +66,7 @@ function cache_get($cid, $bin = 'cache') {
|
|||
* An array of the items successfully returned from cache indexed by cid.
|
||||
*/
|
||||
function cache_get_multiple(array &$cids, $bin = 'cache') {
|
||||
return _cache_get_object($bin)->getMultiple($cids);
|
||||
return cache($bin)->getMultiple($cids);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,7 +139,7 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
|
|||
* the given time, after which it behaves like CACHE_TEMPORARY.
|
||||
*/
|
||||
function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
|
||||
return _cache_get_object($bin)->set($cid, $data, $expire);
|
||||
return cache($bin)->set($cid, $data, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,12 +166,12 @@ function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) {
|
|||
// Clear the block cache first, so stale data will
|
||||
// not end up in the page cache.
|
||||
if (module_exists('block')) {
|
||||
cache_clear_all(NULL, 'cache_block');
|
||||
cache('block')->expire();
|
||||
}
|
||||
cache_clear_all(NULL, 'cache_page');
|
||||
cache('page')->expire();
|
||||
return;
|
||||
}
|
||||
return _cache_get_object($bin)->clear($cid, $wildcard);
|
||||
return cache($bin)->clear($cid, $wildcard);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +186,7 @@ function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) {
|
|||
* TRUE if the cache bin specified is empty.
|
||||
*/
|
||||
function cache_is_empty($bin) {
|
||||
return _cache_get_object($bin)->isEmpty();
|
||||
return cache($bin)->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,7 +223,7 @@ function cache_is_empty($bin) {
|
|||
* cache_get($cid, 'custom_bin');
|
||||
* @endcode
|
||||
*
|
||||
* @see _cache_get_object()
|
||||
* @see cache()
|
||||
* @see DrupalDatabaseCache
|
||||
*/
|
||||
interface DrupalCacheInterface {
|
||||
|
@ -274,6 +279,44 @@ interface DrupalCacheInterface {
|
|||
*/
|
||||
function set($cid, $data, $expire = CACHE_PERMANENT);
|
||||
|
||||
/**
|
||||
* Delete an item from the cache.
|
||||
*
|
||||
* @param $cid
|
||||
* The cache ID to delete.
|
||||
*/
|
||||
function delete($cid);
|
||||
|
||||
/**
|
||||
* Delete multiple items from the cache.
|
||||
*
|
||||
* @param $cids
|
||||
* An array of $cids to delete.
|
||||
*/
|
||||
function deleteMultiple(Array $cids);
|
||||
|
||||
/**
|
||||
* Delete items from the cache using a wildcard prefix.
|
||||
*
|
||||
* @param $prefix
|
||||
* A wildcard prefix.
|
||||
*/
|
||||
function deletePrefix($prefix);
|
||||
|
||||
/**
|
||||
* Flush all cache items in a bin.
|
||||
*/
|
||||
function flush();
|
||||
|
||||
/**
|
||||
* Expire temporary items from cache.
|
||||
*/
|
||||
function expire();
|
||||
|
||||
/**
|
||||
* Perform garbage collection on a cache bin.
|
||||
*/
|
||||
function garbageCollection();
|
||||
|
||||
/**
|
||||
* Expire data from the cache. If called without arguments, expirable
|
||||
|
@ -286,6 +329,9 @@ interface DrupalCacheInterface {
|
|||
* If set to TRUE, the $cid is treated as a substring
|
||||
* to match rather than a complete ID. The match is a right hand
|
||||
* match. If '*' is given as $cid, the bin $bin will be emptied.
|
||||
*
|
||||
* @todo: this method is deprecated, as it's functionality is covered by
|
||||
* more targetted methods in the interface.
|
||||
*/
|
||||
function clear($cid = NULL, $wildcard = FALSE);
|
||||
|
||||
|
@ -311,6 +357,11 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
|
|||
protected $bin;
|
||||
|
||||
function __construct($bin) {
|
||||
// All cache tables should be prefixed with 'cache_', apart from the
|
||||
// default 'cache' bin, which would look silly.
|
||||
if ($bin != 'cache') {
|
||||
$bin = 'cache_' . $bin;
|
||||
}
|
||||
$this->bin = $bin;
|
||||
}
|
||||
|
||||
|
@ -350,28 +401,6 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collection for get() and getMultiple().
|
||||
*
|
||||
* @param $bin
|
||||
* The bin being requested.
|
||||
*/
|
||||
protected function garbageCollection() {
|
||||
global $user;
|
||||
|
||||
// Garbage collection necessary when enforcing a minimum cache lifetime.
|
||||
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
|
||||
if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
|
||||
// Reset the variable immediately to prevent a meltdown in heavy load situations.
|
||||
variable_set('cache_flush_' . $this->bin, 0);
|
||||
// Time to flush old cache data
|
||||
db_delete($this->bin)
|
||||
->condition('expire', CACHE_PERMANENT, '<>')
|
||||
->condition('expire', $cache_flush, '<=')
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a cached item.
|
||||
*
|
||||
|
@ -434,64 +463,101 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
|
|||
}
|
||||
}
|
||||
|
||||
function clear($cid = NULL, $wildcard = FALSE) {
|
||||
global $user;
|
||||
function delete($cid) {
|
||||
db_delete($this->bin)
|
||||
->condition('cid', $cid)
|
||||
->execute();
|
||||
}
|
||||
|
||||
if (empty($cid)) {
|
||||
if (variable_get('cache_lifetime', 0)) {
|
||||
// We store the time in the current user's $user->cache variable which
|
||||
// will be saved into the sessions bin by _drupal_session_write(). We then
|
||||
// simulate that the cache was flushed for this user by not returning
|
||||
// cached data that was cached before the timestamp.
|
||||
$user->cache = REQUEST_TIME;
|
||||
function deleteMultiple(Array $cids) {
|
||||
// Delete in chunks when a large array is passed.
|
||||
do {
|
||||
db_delete($this->bin)
|
||||
->condition('cid', array_splice($cids, 0, 1000), 'IN')
|
||||
->execute();
|
||||
}
|
||||
while (count($cids));
|
||||
}
|
||||
|
||||
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
|
||||
if ($cache_flush == 0) {
|
||||
// This is the first request to clear the cache, start a timer.
|
||||
variable_set('cache_flush_' . $this->bin, REQUEST_TIME);
|
||||
}
|
||||
elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
|
||||
// Clear the cache for everyone, cache_lifetime seconds have
|
||||
// passed since the first request to clear the cache.
|
||||
db_delete($this->bin)
|
||||
->condition('expire', CACHE_PERMANENT, '<>')
|
||||
->condition('expire', REQUEST_TIME, '<')
|
||||
->execute();
|
||||
variable_set('cache_flush_' . $this->bin, 0);
|
||||
}
|
||||
function deletePrefix($prefix) {
|
||||
db_delete($this->bin)
|
||||
->condition('cid', db_like($prefix) . '%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
|
||||
function flush() {
|
||||
db_truncate($this->bin)->execute();
|
||||
}
|
||||
|
||||
function expire() {
|
||||
if (variable_get('cache_lifetime', 0)) {
|
||||
// We store the time in the current user's $user->cache variable which
|
||||
// will be saved into the sessions bin by _drupal_session_write(). We then
|
||||
// simulate that the cache was flushed for this user by not returning
|
||||
// cached data that was cached before the timestamp.
|
||||
$GLOBALS['user']->cache = REQUEST_TIME;
|
||||
|
||||
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
|
||||
if ($cache_flush == 0) {
|
||||
// This is the first request to clear the cache, start a timer.
|
||||
variable_set('cache_flush_' . $this->bin, REQUEST_TIME);
|
||||
}
|
||||
else {
|
||||
// No minimum cache lifetime, flush all temporary cache entries now.
|
||||
elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
|
||||
// Clear the cache for everyone, cache_lifetime seconds have
|
||||
// passed since the first request to clear the cache.
|
||||
db_delete($this->bin)
|
||||
->condition('expire', CACHE_PERMANENT, '<>')
|
||||
->condition('expire', REQUEST_TIME, '<')
|
||||
->execute();
|
||||
variable_set('cache_flush_' . $this->bin, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No minimum cache lifetime, flush all temporary cache entries now.
|
||||
db_delete($this->bin)
|
||||
->condition('expire', CACHE_PERMANENT, '<>')
|
||||
->condition('expire', REQUEST_TIME, '<')
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
function garbageCollection() {
|
||||
global $user;
|
||||
|
||||
// When cache lifetime is in force, avoid running garbage collection too
|
||||
// often since this will remove temporary cache items indiscriminately.
|
||||
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
|
||||
if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
|
||||
// Reset the variable immediately to prevent a meltdown in heavy load situations.
|
||||
variable_set('cache_flush_' . $this->bin, 0);
|
||||
// Time to flush old cache data
|
||||
db_delete($this->bin)
|
||||
->condition('expire', CACHE_PERMANENT, '<>')
|
||||
->condition('expire', $cache_flush, '<=')
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
function clear($cid = NULL, $wildcard = FALSE) {
|
||||
global $user;
|
||||
|
||||
if (empty($cid)) {
|
||||
$this->expire();
|
||||
}
|
||||
else {
|
||||
if ($wildcard) {
|
||||
if ($cid == '*') {
|
||||
db_truncate($this->bin)->execute();
|
||||
$this->flush();
|
||||
}
|
||||
else {
|
||||
db_delete($this->bin)
|
||||
->condition('cid', db_like($cid) . '%', 'LIKE')
|
||||
->execute();
|
||||
$this->deletePrefix($cid);
|
||||
}
|
||||
}
|
||||
elseif (is_array($cid)) {
|
||||
// Delete in chunks when a large array is passed.
|
||||
do {
|
||||
db_delete($this->bin)
|
||||
->condition('cid', array_splice($cid, 0, 1000), 'IN')
|
||||
->execute();
|
||||
}
|
||||
while (count($cid));
|
||||
$this->deleteMultiple($cid);
|
||||
}
|
||||
else {
|
||||
db_delete($this->bin)
|
||||
->condition('cid', $cid)
|
||||
->execute();
|
||||
$this->delete($cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2476,6 +2476,9 @@ function drupal_deliver_html_page($page_callback_result) {
|
|||
|
||||
watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
|
||||
|
||||
// Check for and return a fast 404 page if configured.
|
||||
drupal_fast_404();
|
||||
|
||||
// Keep old path for reference, and to allow forms to redirect to it.
|
||||
if (!isset($_GET['destination'])) {
|
||||
$_GET['destination'] = $_GET['q'];
|
||||
|
@ -2492,7 +2495,7 @@ function drupal_deliver_html_page($page_callback_result) {
|
|||
if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
|
||||
// Standard 404 handler.
|
||||
drupal_set_title(t('Page not found'));
|
||||
$return = t('The requested page could not be found.');
|
||||
$return = t('The requested page "@path" could not be found.', array('@path' => request_uri()));
|
||||
}
|
||||
|
||||
drupal_set_page_content($return);
|
||||
|
@ -4992,7 +4995,7 @@ function drupal_page_set_cache() {
|
|||
if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
|
||||
$cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP);
|
||||
}
|
||||
cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire);
|
||||
cache('page')->set($cache->cid, $cache->data, $cache->expire);
|
||||
}
|
||||
return $cache;
|
||||
}
|
||||
|
@ -5813,7 +5816,7 @@ function drupal_render_cache_get($elements) {
|
|||
}
|
||||
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
|
||||
|
||||
if (!empty($cid) && $cache = cache_get($cid, $bin)) {
|
||||
if (!empty($cid) && $cache = cache($bin)->get($cid)) {
|
||||
// Add additional libraries, JavaScript, CSS and other data attached
|
||||
// to this element.
|
||||
if (isset($cache->data['#attached'])) {
|
||||
|
@ -5858,7 +5861,7 @@ function drupal_render_cache_set(&$markup, $elements) {
|
|||
}
|
||||
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
|
||||
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CACHE_PERMANENT;
|
||||
cache_set($cid, $data, $bin, $expire);
|
||||
cache($bin)->set($cid, $data, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6164,7 +6167,7 @@ function element_children(&$elements, $sort = FALSE) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the visibile children of an element.
|
||||
* Returns the visible children of an element.
|
||||
*
|
||||
* @param $elements
|
||||
* The parent element.
|
||||
|
@ -7146,10 +7149,10 @@ function drupal_flush_all_caches() {
|
|||
|
||||
// Don't clear cache_form - in-progress form submissions may break.
|
||||
// Ordered so clearing the page cache will always be the last action.
|
||||
$core = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
|
||||
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
|
||||
foreach ($cache_tables as $table) {
|
||||
cache_clear_all('*', $table, TRUE);
|
||||
$core = array('cache', 'path', 'filter', 'bootstrap', 'page');
|
||||
$cache_bins = array_merge(module_invoke_all('flush_caches'), $core);
|
||||
foreach ($cache_bins as $bin) {
|
||||
cache($bin)->flush();
|
||||
}
|
||||
|
||||
// Rebuild the bootstrap module list. We do this here so that developers
|
||||
|
@ -7274,427 +7277,6 @@ function drupal_check_incompatibility($v, $current_version) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity info array of an entity type.
|
||||
*
|
||||
* @see hook_entity_info()
|
||||
* @see hook_entity_info_alter()
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type, e.g. node, for which the info shall be returned, or NULL
|
||||
* to return an array with info about all types.
|
||||
*/
|
||||
function entity_get_info($entity_type = NULL) {
|
||||
global $language;
|
||||
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['entity_info'] = &drupal_static(__FUNCTION__);
|
||||
}
|
||||
$entity_info = &$drupal_static_fast['entity_info'];
|
||||
|
||||
// hook_entity_info() includes translated strings, so each language is cached
|
||||
// separately.
|
||||
$langcode = $language->language;
|
||||
|
||||
if (empty($entity_info)) {
|
||||
if ($cache = cache_get("entity_info:$langcode")) {
|
||||
$entity_info = $cache->data;
|
||||
}
|
||||
else {
|
||||
$entity_info = module_invoke_all('entity_info');
|
||||
// Merge in default values.
|
||||
foreach ($entity_info as $name => $data) {
|
||||
$entity_info[$name] += array(
|
||||
'fieldable' => FALSE,
|
||||
'controller class' => 'DrupalDefaultEntityController',
|
||||
'static cache' => TRUE,
|
||||
'field cache' => TRUE,
|
||||
'load hook' => $name . '_load',
|
||||
'bundles' => array(),
|
||||
'view modes' => array(),
|
||||
'entity keys' => array(),
|
||||
'translation' => array(),
|
||||
);
|
||||
$entity_info[$name]['entity keys'] += array(
|
||||
'revision' => '',
|
||||
'bundle' => '',
|
||||
);
|
||||
foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) {
|
||||
$entity_info[$name]['view modes'][$view_mode] += array(
|
||||
'custom settings' => FALSE,
|
||||
);
|
||||
}
|
||||
// If no bundle key is provided, assume a single bundle, named after
|
||||
// the entity type.
|
||||
if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) {
|
||||
$entity_info[$name]['bundles'] = array($name => array('label' => $entity_info[$name]['label']));
|
||||
}
|
||||
// Prepare entity schema fields SQL info for
|
||||
// DrupalEntityControllerInterface::buildQuery().
|
||||
if (isset($entity_info[$name]['base table'])) {
|
||||
$entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
|
||||
if (isset($entity_info[$name]['revision table'])) {
|
||||
$entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Let other modules alter the entity info.
|
||||
drupal_alter('entity_info', $entity_info);
|
||||
cache_set("entity_info:$langcode", $entity_info);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($entity_type)) {
|
||||
return $entity_info;
|
||||
}
|
||||
elseif (isset($entity_info[$entity_type])) {
|
||||
return $entity_info[$entity_type];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the cached information about entity types.
|
||||
*/
|
||||
function entity_info_cache_clear() {
|
||||
drupal_static_reset('entity_get_info');
|
||||
// Clear all languages.
|
||||
cache_clear_all('entity_info:', 'cache', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to extract id, vid, and bundle name from an entity.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g. 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The entity from which to extract values.
|
||||
* @return
|
||||
* A numerically indexed array (not a hash table) containing these
|
||||
* elements:
|
||||
* 0: primary id of the entity
|
||||
* 1: revision id of the entity, or NULL if $entity_type is not versioned
|
||||
* 2: bundle name of the entity
|
||||
*/
|
||||
function entity_extract_ids($entity_type, $entity) {
|
||||
$info = entity_get_info($entity_type);
|
||||
|
||||
// Objects being created might not have id/vid yet.
|
||||
$id = isset($entity->{$info['entity keys']['id']}) ? $entity->{$info['entity keys']['id']} : NULL;
|
||||
$vid = ($info['entity keys']['revision'] && isset($entity->{$info['entity keys']['revision']})) ? $entity->{$info['entity keys']['revision']} : NULL;
|
||||
|
||||
if (!empty($info['entity keys']['bundle'])) {
|
||||
// Explicitly fail for malformed entities missing the bundle property.
|
||||
if (!isset($entity->{$info['entity keys']['bundle']}) || $entity->{$info['entity keys']['bundle']} === '') {
|
||||
throw new EntityMalformedException(t('Missing bundle property on entity of type @entity_type.', array('@entity_type' => $entity_type)));
|
||||
}
|
||||
$bundle = $entity->{$info['entity keys']['bundle']};
|
||||
}
|
||||
else {
|
||||
// The entity type provides no bundle key: assume a single bundle, named
|
||||
// after the entity type.
|
||||
$bundle = $entity_type;
|
||||
}
|
||||
|
||||
return array($id, $vid, $bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to assemble an object structure with initial ids.
|
||||
*
|
||||
* This function can be seen as reciprocal to entity_extract_ids().
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g. 'node' or 'user'.
|
||||
* @param $ids
|
||||
* A numerically indexed array, as returned by entity_extract_ids(),
|
||||
* containing these elements:
|
||||
* 0: primary id of the entity
|
||||
* 1: revision id of the entity, or NULL if $entity_type is not versioned
|
||||
* 2: bundle name of the entity, or NULL if $entity_type has no bundles
|
||||
* @return
|
||||
* An entity structure, initialized with the ids provided.
|
||||
*/
|
||||
function entity_create_stub_entity($entity_type, $ids) {
|
||||
$entity = new stdClass();
|
||||
$info = entity_get_info($entity_type);
|
||||
$entity->{$info['entity keys']['id']} = $ids[0];
|
||||
if (!empty($info['entity keys']['revision']) && isset($ids[1])) {
|
||||
$entity->{$info['entity keys']['revision']} = $ids[1];
|
||||
}
|
||||
if (!empty($info['entity keys']['bundle']) && isset($ids[2])) {
|
||||
$entity->{$info['entity keys']['bundle']} = $ids[2];
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load entities from the database.
|
||||
*
|
||||
* The entities are stored in a static memory cache, and will not require
|
||||
* database access if loaded again during the same page request.
|
||||
*
|
||||
* The actual loading is done through a class that has to implement the
|
||||
* DrupalEntityControllerInterface interface. By default,
|
||||
* DrupalDefaultEntityController is used. Entity types can specify that a
|
||||
* different class should be used by setting the 'controller class' key in
|
||||
* hook_entity_info(). These classes can either implement the
|
||||
* DrupalEntityControllerInterface interface, or, most commonly, extend the
|
||||
* DrupalDefaultEntityController class. See node_entity_info() and the
|
||||
* NodeController in node.module as an example.
|
||||
*
|
||||
* @see hook_entity_info()
|
||||
* @see DrupalEntityControllerInterface
|
||||
* @see DrupalDefaultEntityController
|
||||
* @see EntityFieldQuery
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type to load, e.g. node or user.
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* (deprecated) An associative array of conditions on the base table, where
|
||||
* the keys are the database fields and the values are the values those
|
||||
* fields must have. Instead, it is preferable to use EntityFieldQuery to
|
||||
* retrieve a list of entity IDs loadable by this function.
|
||||
* @param $reset
|
||||
* Whether to reset the internal cache for the requested entity type.
|
||||
*
|
||||
* @return
|
||||
* An array of entity objects indexed by their ids. When no results are
|
||||
* found, an empty array is returned.
|
||||
*
|
||||
* @todo Remove $conditions in Drupal 8.
|
||||
*/
|
||||
function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) {
|
||||
if ($reset) {
|
||||
entity_get_controller($entity_type)->resetCache();
|
||||
}
|
||||
return entity_get_controller($entity_type)->load($ids, $conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the unchanged, i.e. not modified, entity from the database.
|
||||
*
|
||||
* Unlike entity_load() this function ensures the entity is directly loaded from
|
||||
* the database, thus bypassing any static cache. In particular, this function
|
||||
* is useful to determine changes by comparing the entity being saved to the
|
||||
* stored entity.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type to load, e.g. node or user.
|
||||
* @param $id
|
||||
* The id of the entity to load.
|
||||
*
|
||||
* @return
|
||||
* The unchanged entity, or FALSE if the entity cannot be loaded.
|
||||
*/
|
||||
function entity_load_unchanged($entity_type, $id) {
|
||||
entity_get_controller($entity_type)->resetCache(array($id));
|
||||
$result = entity_get_controller($entity_type)->load(array($id));
|
||||
return reset($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity controller class for an entity type.
|
||||
*/
|
||||
function entity_get_controller($entity_type) {
|
||||
$controllers = &drupal_static(__FUNCTION__, array());
|
||||
if (!isset($controllers[$entity_type])) {
|
||||
$type_info = entity_get_info($entity_type);
|
||||
$class = $type_info['controller class'];
|
||||
$controllers[$entity_type] = new $class($entity_type);
|
||||
}
|
||||
return $controllers[$entity_type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke hook_entity_prepare_view().
|
||||
*
|
||||
* If adding a new entity similar to nodes, comments or users, you should
|
||||
* invoke this function during the ENTITY_build_content() or
|
||||
* ENTITY_view_multiple() phases of rendering to allow other modules to alter
|
||||
* the objects during this phase. This is needed for situations where
|
||||
* information needs to be loaded outside of ENTITY_load() - particularly
|
||||
* when loading entities into one another - i.e. a user object into a node, due
|
||||
* to the potential for unwanted side-effects such as caching and infinite
|
||||
* recursion. By convention, entity_prepare_view() is called after
|
||||
* field_attach_prepare_view() to allow entity level hooks to act on content
|
||||
* loaded by field API.
|
||||
* @see hook_entity_prepare_view()
|
||||
*
|
||||
* @param $entity_type
|
||||
* The type of entity, i.e. 'node', 'user'.
|
||||
* @param $entities
|
||||
* The entity objects which are being prepared for view, keyed by object ID.
|
||||
* @param $langcode
|
||||
* (optional) A language code to be used for rendering. Defaults to the global
|
||||
* content language of the current request.
|
||||
*/
|
||||
function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
|
||||
if (!isset($langcode)) {
|
||||
$langcode = $GLOBALS['language_content']->language;
|
||||
}
|
||||
|
||||
// To ensure hooks are only run once per entity, check for an
|
||||
// entity_view_prepared flag and only process items without it.
|
||||
// @todo: resolve this more generally for both entity and field level hooks.
|
||||
$prepare = array();
|
||||
foreach ($entities as $id => $entity) {
|
||||
if (empty($entity->entity_view_prepared)) {
|
||||
// Add this entity to the items to be prepared.
|
||||
$prepare[$id] = $entity;
|
||||
|
||||
// Mark this item as prepared.
|
||||
$entity->entity_view_prepared = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($prepare)) {
|
||||
module_invoke_all('entity_prepare_view', $prepare, $entity_type, $langcode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uri elements of an entity.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g. 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The entity for which to generate a path.
|
||||
* @return
|
||||
* An array containing the 'path' and 'options' keys used to build the uri of
|
||||
* the entity, and matching the signature of url(). NULL if the entity has no
|
||||
* uri of its own.
|
||||
*/
|
||||
function entity_uri($entity_type, $entity) {
|
||||
// This check enables the URI of an entity to be easily overridden from what
|
||||
// the callback for the entity type or bundle would return, and it helps
|
||||
// minimize performance overhead when entity_uri() is called multiple times
|
||||
// for the same entity.
|
||||
if (!isset($entity->uri)) {
|
||||
$info = entity_get_info($entity_type);
|
||||
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
|
||||
// A bundle-specific callback takes precedence over the generic one for the
|
||||
// entity type.
|
||||
if (isset($info['bundles'][$bundle]['uri callback'])) {
|
||||
$uri_callback = $info['bundles'][$bundle]['uri callback'];
|
||||
}
|
||||
elseif (isset($info['uri callback'])) {
|
||||
$uri_callback = $info['uri callback'];
|
||||
}
|
||||
else {
|
||||
$uri_callback = NULL;
|
||||
}
|
||||
|
||||
// Invoke the callback to get the URI. If there is no callback, set the
|
||||
// entity's 'uri' property to FALSE to indicate that it is known to not have
|
||||
// a URI.
|
||||
if (isset($uri_callback) && function_exists($uri_callback)) {
|
||||
$entity->uri = $uri_callback($entity);
|
||||
if (!isset($entity->uri['options'])) {
|
||||
$entity->uri['options'] = array();
|
||||
}
|
||||
// Pass the entity data to url() so that alter functions do not need to
|
||||
// lookup this entity again.
|
||||
$entity->uri['options']['entity_type'] = $entity_type;
|
||||
$entity->uri['options']['entity'] = $entity;
|
||||
}
|
||||
else {
|
||||
$entity->uri = FALSE;
|
||||
}
|
||||
}
|
||||
return $entity->uri ? $entity->uri : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of an entity.
|
||||
*
|
||||
* See the 'label callback' component of the hook_entity_info() return value
|
||||
* for more information.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g., 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The entity for which to generate the label.
|
||||
*
|
||||
* @return
|
||||
* The entity label, or FALSE if not found.
|
||||
*/
|
||||
function entity_label($entity_type, $entity) {
|
||||
$label = FALSE;
|
||||
$info = entity_get_info($entity_type);
|
||||
if (isset($info['label callback']) && function_exists($info['label callback'])) {
|
||||
$label = $info['label callback']($entity_type, $entity);
|
||||
}
|
||||
elseif (!empty($info['entity keys']['label']) && isset($entity->{$info['entity keys']['label']})) {
|
||||
$label = $entity->{$info['entity keys']['label']};
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for attaching field API validation to entity forms.
|
||||
*/
|
||||
function entity_form_field_validate($entity_type, $form, &$form_state) {
|
||||
// All field attach API functions act on an entity object, but during form
|
||||
// validation, we don't have one. $form_state contains the entity as it was
|
||||
// prior to processing the current form submission, and we must not update it
|
||||
// until we have fully validated the submitted input. Therefore, for
|
||||
// validation, act on a pseudo entity created out of the form values.
|
||||
$pseudo_entity = (object) $form_state['values'];
|
||||
field_attach_form_validate($entity_type, $pseudo_entity, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for copying submitted values to entity properties for simple entity forms.
|
||||
*
|
||||
* During the submission handling of an entity form's "Save", "Preview", and
|
||||
* possibly other buttons, the form state's entity needs to be updated with the
|
||||
* submitted form values. Each entity form implements its own builder function
|
||||
* for doing this, appropriate for the particular entity and form, whereas
|
||||
* modules may specify additional builder functions in $form['#entity_builders']
|
||||
* for copying the form values of added form elements to entity properties.
|
||||
* Many of the main entity builder functions can call this helper function to
|
||||
* re-use its logic of copying $form_state['values'][PROPERTY] values to
|
||||
* $entity->PROPERTY for all entries in $form_state['values'] that are not field
|
||||
* data, and calling field_attach_submit() to copy field data. Apart from that
|
||||
* this helper invokes any additional builder functions that have been specified
|
||||
* in $form['#entity_builders'].
|
||||
*
|
||||
* For some entity forms (e.g., forms with complex non-field data and forms that
|
||||
* simultaneously edit multiple entities), this behavior may be inappropriate,
|
||||
* so the builder function for such forms needs to implement the required
|
||||
* functionality instead of calling this function.
|
||||
*/
|
||||
function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state) {
|
||||
$info = entity_get_info($entity_type);
|
||||
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
|
||||
// Copy top-level form values that are not for fields to entity properties,
|
||||
// without changing existing entity properties that are not being edited by
|
||||
// this form. Copying field values must be done using field_attach_submit().
|
||||
$values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $bundle)) : $form_state['values'];
|
||||
foreach ($values_excluding_fields as $key => $value) {
|
||||
$entity->$key = $value;
|
||||
}
|
||||
|
||||
// Invoke all specified builders for copying form values to entity properties.
|
||||
if (isset($form['#entity_builders'])) {
|
||||
foreach ($form['#entity_builders'] as $function) {
|
||||
$function($entity_type, $entity, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy field values to the entity.
|
||||
if ($info['fieldable']) {
|
||||
field_attach_submit($entity_type, $entity, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs one or more XML-RPC request(s).
|
||||
*
|
||||
|
@ -7738,13 +7320,13 @@ function archiver_get_info() {
|
|||
$archiver_info = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
if (empty($archiver_info)) {
|
||||
$cache = cache_get('archiver_info');
|
||||
$cache = cache()->get('archiver_info');
|
||||
if ($cache === FALSE) {
|
||||
// Rebuild the cache and save it.
|
||||
$archiver_info = module_invoke_all('archiver_info');
|
||||
drupal_alter('archiver_info', $archiver_info);
|
||||
uasort($archiver_info, 'drupal_sort_weight');
|
||||
cache_set('archiver_info', $archiver_info);
|
||||
cache()->set('archiver_info', $archiver_info);
|
||||
}
|
||||
else {
|
||||
$archiver_info = $cache->data;
|
||||
|
|
|
@ -370,7 +370,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface
|
|||
}
|
||||
}
|
||||
|
||||
public function fetchField($index = 0) {
|
||||
public function fetchColumn($index = 0) {
|
||||
if (isset($this->currentRow) && isset($this->columnNames[$index])) {
|
||||
// We grab the value directly from $this->data, and format it.
|
||||
$return = $this->currentRow[$this->columnNames[$index]];
|
||||
|
@ -382,6 +382,10 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface
|
|||
}
|
||||
}
|
||||
|
||||
public function fetchField($index = 0) {
|
||||
return $this->fetchColumn($index);
|
||||
}
|
||||
|
||||
public function fetchObject($class_name = NULL, $constructor_args = array()) {
|
||||
if (isset($this->currentRow)) {
|
||||
if (!isset($class_name)) {
|
||||
|
|
|
@ -672,9 +672,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
|||
// Don't add the prefix, $table_expression already includes the prefix.
|
||||
$info = $this->getPrefixInfo($table_expression, FALSE);
|
||||
|
||||
// Can't use query placeholders because the query would have to be
|
||||
// :prefixsqlite_master, which does not work.
|
||||
$result = db_query("SELECT name FROM " . $info['schema'] . ".sqlite_master WHERE name LIKE :table_name", array(
|
||||
// Can't use query placeholders for the schema because the query would have
|
||||
// to be :prefixsqlite_master, which does not work.
|
||||
$result = db_query("SELECT name FROM " . $info['schema'] . ".sqlite_master WHERE type = :type AND name LIKE :table_name", array(
|
||||
':type' => 'table',
|
||||
':table_name' => $info['table'],
|
||||
));
|
||||
return $result->fetchAllKeyed(0, 0);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
/**
|
||||
* @file
|
||||
* Base FileTransfer class.
|
||||
*
|
||||
* Classes extending this class perform file operations on directories not
|
||||
|
@ -61,7 +62,7 @@ abstract class FileTransfer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Connect to the server.
|
||||
* Connects to the server.
|
||||
*/
|
||||
abstract protected function connect();
|
||||
|
||||
|
@ -280,7 +281,7 @@ abstract class FileTransfer {
|
|||
abstract public function isFile($path);
|
||||
|
||||
/**
|
||||
* Return the chroot property for this connection.
|
||||
* Returns the chroot property for this connection.
|
||||
*
|
||||
* It does this by moving up the tree until it finds itself. If successful,
|
||||
* it will return the chroot, otherwise FALSE.
|
||||
|
@ -304,7 +305,7 @@ abstract class FileTransfer {
|
|||
$check = implode($parts, '/');
|
||||
if ($this->isFile($check . '/' . basename(__FILE__))) {
|
||||
// Remove the trailing slash.
|
||||
return substr($chroot,0,-1);
|
||||
return substr($chroot, 0, -1);
|
||||
}
|
||||
$chroot .= array_shift($parts) . '/';
|
||||
}
|
||||
|
|
|
@ -472,12 +472,12 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
|
|||
* Fetch a form from cache.
|
||||
*/
|
||||
function form_get_cache($form_build_id, &$form_state) {
|
||||
if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) {
|
||||
if ($cached = cache('form')->get('form_' . $form_build_id)) {
|
||||
$form = $cached->data;
|
||||
|
||||
global $user;
|
||||
if ((isset($form['#cache_token']) && drupal_valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid)) {
|
||||
if ($cached = cache_get('form_state_' . $form_build_id, 'cache_form')) {
|
||||
if ($cached = cache('form')->get('form_state_' . $form_build_id)) {
|
||||
// Re-populate $form_state for subsequent rebuilds.
|
||||
$form_state = $cached->data + $form_state;
|
||||
|
||||
|
@ -511,12 +511,12 @@ function form_set_cache($form_build_id, $form, $form_state) {
|
|||
if ($GLOBALS['user']->uid) {
|
||||
$form['#cache_token'] = drupal_get_token();
|
||||
}
|
||||
cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire);
|
||||
cache('form')->set('form_' . $form_build_id, $form, REQUEST_TIME + $expire);
|
||||
}
|
||||
|
||||
// Cache form state.
|
||||
if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) {
|
||||
cache_set('form_state_' . $form_build_id, $data, 'cache_form', REQUEST_TIME + $expire);
|
||||
cache('form')->set('form_state_' . $form_build_id, $data, REQUEST_TIME + $expire);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,8 +835,8 @@ function drupal_process_form($form_id, &$form, &$form_state) {
|
|||
// here, as we've finished with them. The in-memory copies are still
|
||||
// here, though.
|
||||
if (!variable_get('cache', 0) && !empty($form_state['values']['form_build_id'])) {
|
||||
cache_clear_all('form_' . $form_state['values']['form_build_id'], 'cache_form');
|
||||
cache_clear_all('form_state_' . $form_state['values']['form_build_id'], 'cache_form');
|
||||
cache('form')->delete('form_' . $form_state['values']['form_build_id']);
|
||||
cache('form')->delete('form_state_' . $form_state['values']['form_build_id']);
|
||||
}
|
||||
|
||||
// If batches were set in the submit handlers, we process them now,
|
||||
|
@ -1082,8 +1082,12 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
|
|||
// matches the current user's session.
|
||||
if (isset($form['#token'])) {
|
||||
if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) {
|
||||
$path = current_path();
|
||||
$query = drupal_get_query_parameters();
|
||||
$url = url($path, array('query' => $query));
|
||||
|
||||
// Setting this error will cause the form to fail validation.
|
||||
form_set_error('form_token', t('This form is outdated. Reload the page and try again. Contact the site administrator if the problem persists.'));
|
||||
form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2796,7 +2800,17 @@ function password_confirm_validate($element, &$element_state) {
|
|||
*/
|
||||
function theme_date($variables) {
|
||||
$element = $variables['element'];
|
||||
return '<div class="container-inline">' . drupal_render_children($element) . '</div>';
|
||||
|
||||
$attributes = array();
|
||||
if (isset($element['#id'])) {
|
||||
$attributes['id'] = $element['#id'];
|
||||
}
|
||||
if (!empty($element['#attributes']['class'])) {
|
||||
$attributes['class'] = (array) $element['#attributes']['class'];
|
||||
}
|
||||
$attributes['class'][] = 'container-inline';
|
||||
|
||||
return '<div' . drupal_attributes($attributes) . '>' . drupal_render_children($element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,7 +53,7 @@ function _locale_import_po($file, $langcode, $mode) {
|
|||
|
||||
// Clear cache and force refresh of JavaScript translations.
|
||||
_locale_invalidate_js($langcode);
|
||||
cache_clear_all('locale:', 'cache', TRUE);
|
||||
cache()->deletePrefix('locale:');
|
||||
|
||||
// Rebuild the menu, strings may have changed.
|
||||
menu_rebuild();
|
||||
|
|
|
@ -253,12 +253,13 @@ function install_begin_request(&$install_state) {
|
|||
// Set up $language, so t() caller functions will still work.
|
||||
drupal_language_initialize();
|
||||
|
||||
include_once DRUPAL_ROOT . '/includes/entity.inc';
|
||||
require_once DRUPAL_ROOT . '/includes/ajax.inc';
|
||||
$module_list['system']['filename'] = 'modules/system/system.module';
|
||||
$module_list['user']['filename'] = 'modules/user/user.module';
|
||||
$module_list['entity']['filename'] = 'modules/entity/entity.module';
|
||||
$module_list['user']['filename'] = 'modules/user/user.module';
|
||||
module_list(TRUE, FALSE, FALSE, $module_list);
|
||||
drupal_load('module', 'system');
|
||||
drupal_load('module', 'entity');
|
||||
drupal_load('module', 'user');
|
||||
|
||||
// Load the cache infrastructure using a "fake" cache implementation that
|
||||
|
@ -1246,8 +1247,8 @@ function install_select_locale(&$install_state) {
|
|||
* Form API array definition for language selection.
|
||||
*/
|
||||
function install_select_locale_form($form, &$form_state, $locales, $profilename) {
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$languages = _locale_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$languages = standard_language_list();
|
||||
foreach ($locales as $locale) {
|
||||
$name = $locale->langcode;
|
||||
if (isset($languages[$name])) {
|
||||
|
@ -1388,8 +1389,8 @@ function install_import_locales(&$install_state) {
|
|||
include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
|
||||
$install_locale = $install_state['parameters']['locale'];
|
||||
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$predefined = _locale_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$predefined = standard_language_list();
|
||||
if (!isset($predefined[$install_locale])) {
|
||||
// Drupal does not know about this language, so we prefill its values with
|
||||
// our best guess. The user will be able to edit afterwards.
|
||||
|
|
|
@ -299,8 +299,9 @@ function language_negotiation_info() {
|
|||
$language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array(
|
||||
'callbacks' => array('language' => 'language_from_default'),
|
||||
'weight' => 10,
|
||||
'name' => t('Default'),
|
||||
'name' => t('Default language'),
|
||||
'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)),
|
||||
'config' => 'admin/config/regional/language',
|
||||
);
|
||||
|
||||
// Let other modules alter the list of language providers.
|
||||
|
|
|
@ -207,10 +207,16 @@ function locale_language_from_url($languages) {
|
|||
|
||||
case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN:
|
||||
foreach ($languages as $language) {
|
||||
$host = parse_url($language->domain, PHP_URL_HOST);
|
||||
if ($host && ($_SERVER['HTTP_HOST'] == $host)) {
|
||||
$language_url = $language->language;
|
||||
break;
|
||||
// Skip check if the language doesn't have a domain.
|
||||
if ($language->domain) {
|
||||
// Only compare the domains not the protocols or ports.
|
||||
// Remove protocol and add http:// so parse_url works
|
||||
$host = 'http://' . str_replace(array('http://', 'https://'), '', $language->domain);
|
||||
$host = parse_url($host, PHP_URL_HOST);
|
||||
if ($_SERVER['HTTP_HOST'] == $host) {
|
||||
$language_url = $language->language;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -460,8 +466,8 @@ function locale_add_language($langcode, $name = NULL, $native = NULL, $direction
|
|||
|
||||
// If name was not set, we add a predefined language.
|
||||
if (!isset($name)) {
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$predefined = _locale_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$predefined = standard_language_list();
|
||||
$name = $predefined[$langcode][0];
|
||||
$native = isset($predefined[$langcode][1]) ? $predefined[$langcode][1] : $predefined[$langcode][0];
|
||||
$direction = isset($predefined[$langcode][2]) ? $predefined[$langcode][2] : LANGUAGE_LTR;
|
||||
|
@ -703,7 +709,7 @@ function _locale_rebuild_js($langcode = NULL) {
|
|||
// Update the default language variable if the default language has been altered.
|
||||
// This is necessary to keep the variable consistent with the database
|
||||
// version of the language and to prevent checking against an outdated hash.
|
||||
$default_langcode = language_default('language');
|
||||
$default_langcode = language_default()->language;
|
||||
if ($default_langcode == $language->language) {
|
||||
$default = db_query("SELECT * FROM {languages} WHERE language = :language", array(':language' => $default_langcode))->fetchObject();
|
||||
variable_set('language_default', $default);
|
||||
|
@ -744,9 +750,9 @@ function _locale_rebuild_js($langcode = NULL) {
|
|||
* Prepares the language code list for a select form item with only the unsupported ones
|
||||
*/
|
||||
function _locale_prepare_predefined_list() {
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$languages = language_list();
|
||||
$predefined = _locale_get_predefined_list();
|
||||
$predefined = standard_language_list();
|
||||
foreach ($predefined as $key => $value) {
|
||||
if (isset($languages[$key])) {
|
||||
unset($predefined[$key]);
|
||||
|
@ -776,8 +782,8 @@ function _locale_prepare_predefined_list() {
|
|||
* An array of all country code => country name pairs.
|
||||
*/
|
||||
function country_get_list() {
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$countries = _country_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$countries = standard_country_list();
|
||||
// Allow other modules to modify the country list.
|
||||
drupal_alter('countries', $countries);
|
||||
return $countries;
|
||||
|
|
|
@ -441,14 +441,14 @@ function menu_get_item($path = NULL, $router_item = NULL) {
|
|||
// Since there is no limit to the length of $path, use a hash to keep it
|
||||
// short yet unique.
|
||||
$cid = 'menu_item:' . hash('sha256', $path);
|
||||
if ($cached = cache_get($cid, 'cache_menu')) {
|
||||
if ($cached = cache('menu')->get($cid)) {
|
||||
$router_item = $cached->data;
|
||||
}
|
||||
else {
|
||||
$parts = array_slice($original_map, 0, MENU_MAX_PARTS);
|
||||
$ancestors = menu_get_ancestors($parts);
|
||||
$router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' => $ancestors))->fetchAssoc();
|
||||
cache_set($cid, $router_item, 'cache_menu');
|
||||
cache('menu')->set($cid, $router_item);
|
||||
}
|
||||
if ($router_item) {
|
||||
// Allow modules to alter the router item before it is translated and
|
||||
|
@ -1095,7 +1095,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
|
|||
|
||||
if (!isset($tree[$cid])) {
|
||||
// If the static variable doesn't have the data, check {cache_menu}.
|
||||
$cache = cache_get($cid, 'cache_menu');
|
||||
$cache = cache('menu')->get($cid);
|
||||
if ($cache && isset($cache->data)) {
|
||||
// If the cache entry exists, it contains the parameters for
|
||||
// menu_build_tree().
|
||||
|
@ -1122,7 +1122,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
|
|||
}
|
||||
|
||||
// Cache the tree building parameters using the page-specific cid.
|
||||
cache_set($cid, $tree_parameters, 'cache_menu');
|
||||
cache('menu')->set($cid, $tree_parameters);
|
||||
}
|
||||
|
||||
// Build the tree using the parameters; the resulting tree will be cached
|
||||
|
@ -1179,7 +1179,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
|
|||
|
||||
if (!isset($tree[$cid])) {
|
||||
// If the static variable doesn't have the data, check {cache_menu}.
|
||||
$cache = cache_get($cid, 'cache_menu');
|
||||
$cache = cache('menu')->get($cid);
|
||||
if ($cache && isset($cache->data)) {
|
||||
// If the cache entry exists, it contains the parameters for
|
||||
// menu_build_tree().
|
||||
|
@ -1251,7 +1251,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
|
|||
$tree_parameters['active_trail'] = $active_trail;
|
||||
}
|
||||
// Cache the tree building parameters using the page-specific cid.
|
||||
cache_set($cid, $tree_parameters, 'cache_menu');
|
||||
cache('menu')->set($cid, $tree_parameters);
|
||||
}
|
||||
|
||||
// Build the tree using the parameters; the resulting tree will be cached
|
||||
|
@ -1317,7 +1317,7 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
|
|||
|
||||
// If we do not have this tree in the static cache, check {cache_menu}.
|
||||
if (!isset($trees[$tree_cid])) {
|
||||
$cache = cache_get($tree_cid, 'cache_menu');
|
||||
$cache = cache('menu')->get($tree_cid);
|
||||
if ($cache && isset($cache->data)) {
|
||||
$trees[$tree_cid] = $cache->data;
|
||||
}
|
||||
|
@ -1378,7 +1378,7 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
|
|||
menu_tree_collect_node_links($data['tree'], $data['node_links']);
|
||||
|
||||
// Cache the data, if it is not already in the cache.
|
||||
cache_set($tree_cid, $data, 'cache_menu');
|
||||
cache('menu')->set($tree_cid, $data);
|
||||
$trees[$tree_cid] = $data;
|
||||
}
|
||||
|
||||
|
@ -2512,7 +2512,7 @@ function menu_cache_clear($menu_name = 'navigation') {
|
|||
$cache_cleared = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
if (empty($cache_cleared[$menu_name])) {
|
||||
cache_clear_all('links:' . $menu_name . ':', 'cache_menu', TRUE);
|
||||
cache('menu')->deletePrefix('links:' . $menu_name . ':');
|
||||
$cache_cleared[$menu_name] = 1;
|
||||
}
|
||||
elseif ($cache_cleared[$menu_name] == 1) {
|
||||
|
@ -2529,7 +2529,7 @@ function menu_cache_clear($menu_name = 'navigation') {
|
|||
* might have been made to the router items or menu links.
|
||||
*/
|
||||
function menu_cache_clear_all() {
|
||||
cache_clear_all('*', 'cache_menu', TRUE);
|
||||
cache('menu')->flush();
|
||||
menu_reset_static_cache();
|
||||
}
|
||||
|
||||
|
|
|
@ -129,12 +129,12 @@ function system_list($type) {
|
|||
if (isset($lists['bootstrap'])) {
|
||||
return $lists['bootstrap'];
|
||||
}
|
||||
if ($cached = cache_get('bootstrap_modules', 'cache_bootstrap')) {
|
||||
if ($cached = cache('bootstrap')->get('bootstrap_modules')) {
|
||||
$bootstrap_list = $cached->data;
|
||||
}
|
||||
else {
|
||||
$bootstrap_list = db_query("SELECT name, filename FROM {system} WHERE status = 1 AND bootstrap = 1 AND type = 'module' ORDER BY weight ASC, name ASC")->fetchAllAssoc('name');
|
||||
cache_set('bootstrap_modules', $bootstrap_list, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('bootstrap_modules', $bootstrap_list);
|
||||
}
|
||||
// To avoid a separate database lookup for the filepath, prime the
|
||||
// drupal_get_filename() static cache for bootstrap modules only.
|
||||
|
@ -148,7 +148,7 @@ function system_list($type) {
|
|||
}
|
||||
// Otherwise build the list for enabled modules and themes.
|
||||
elseif (!isset($lists['module_enabled'])) {
|
||||
if ($cached = cache_get('system_list', 'cache_bootstrap')) {
|
||||
if ($cached = cache('bootstrap')->get('system_list')) {
|
||||
$lists = $cached->data;
|
||||
}
|
||||
else {
|
||||
|
@ -178,7 +178,7 @@ function system_list($type) {
|
|||
$lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename);
|
||||
}
|
||||
}
|
||||
cache_set('system_list', $lists, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('system_list', $lists);
|
||||
}
|
||||
// To avoid a separate database lookup for the filepath, prime the
|
||||
// drupal_get_filename() static cache with all enabled modules and themes.
|
||||
|
@ -197,8 +197,7 @@ function system_list_reset() {
|
|||
drupal_static_reset('system_list');
|
||||
drupal_static_reset('system_rebuild_module_data');
|
||||
drupal_static_reset('list_themes');
|
||||
cache_clear_all('bootstrap_modules', 'cache_bootstrap');
|
||||
cache_clear_all('system_list', 'cache_bootstrap');
|
||||
cache('bootstrap')->deleteMultiple(array('bootstrap_modules', 'system_list'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,8 +424,9 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
|
|||
registry_update();
|
||||
// Refresh the schema to include it.
|
||||
drupal_get_schema(NULL, TRUE);
|
||||
// Clear entity cache.
|
||||
entity_info_cache_clear();
|
||||
|
||||
// Allow modules to react prior to the installation of a module.
|
||||
module_invoke_all('modules_preinstall', array($module));
|
||||
|
||||
// Now install the module if necessary.
|
||||
if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) {
|
||||
|
@ -451,6 +451,9 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
|
|||
watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
|
||||
}
|
||||
|
||||
// Allow modules to react prior to the enabling of a module.
|
||||
module_invoke_all('modules_preenable', array($module));
|
||||
|
||||
// Enable the module.
|
||||
module_invoke($module, 'enable');
|
||||
|
||||
|
@ -648,16 +651,16 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
|
|||
// per request.
|
||||
if ($reset) {
|
||||
$implementations = array();
|
||||
cache_set('module_implements', array(), 'cache_bootstrap');
|
||||
cache('bootstrap')->set('module_implements', array());
|
||||
drupal_static_reset('module_hook_info');
|
||||
drupal_static_reset('drupal_alter');
|
||||
cache_clear_all('hook_info', 'cache_bootstrap');
|
||||
cache('bootstrap')->delete('hook_info');
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch implementations from cache.
|
||||
if (empty($implementations)) {
|
||||
$implementations = cache_get('module_implements', 'cache_bootstrap');
|
||||
$implementations = cache('bootstrap')->get('module_implements');
|
||||
if ($implementations === FALSE) {
|
||||
$implementations = array();
|
||||
}
|
||||
|
@ -726,7 +729,7 @@ function module_hook_info() {
|
|||
|
||||
if (!isset($hook_info)) {
|
||||
$hook_info = array();
|
||||
$cache = cache_get('hook_info', 'cache_bootstrap');
|
||||
$cache = cache('bootstrap')->get('hook_info');
|
||||
if ($cache === FALSE) {
|
||||
// Rebuild the cache and save it.
|
||||
// We can't use module_invoke_all() here or it would cause an infinite
|
||||
|
@ -747,7 +750,7 @@ function module_hook_info() {
|
|||
$function($hook_info);
|
||||
}
|
||||
}
|
||||
cache_set('hook_info', $hook_info, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('hook_info', $hook_info);
|
||||
}
|
||||
else {
|
||||
$hook_info = $cache->data;
|
||||
|
@ -769,7 +772,7 @@ function module_implements_write_cache() {
|
|||
// optimized as tightly, and not doing so keeps the cache entry smaller.
|
||||
if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
|
||||
unset($implementations['#write_cache']);
|
||||
cache_set('module_implements', $implementations, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('module_implements', $implementations);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) {
|
|||
$cache['map'][$path_language] = array();
|
||||
// Load system paths from cache.
|
||||
$cid = current_path();
|
||||
if ($cached = cache_get($cid, 'cache_path')) {
|
||||
if ($cached = cache('path')->get($cid)) {
|
||||
$cache['system_paths'] = $cached->data;
|
||||
// Now fetch the aliases corresponding to these system paths.
|
||||
$args = array(
|
||||
|
@ -212,7 +212,7 @@ function drupal_cache_system_paths() {
|
|||
if ($paths = current($cache['map'])) {
|
||||
$data = array_keys($paths);
|
||||
$expire = REQUEST_TIME + (60 * 60 * 24);
|
||||
cache_set($cid, $data, 'cache_path', $expire);
|
||||
cache('path')->set($cid, $data, $expire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ function _registry_update() {
|
|||
|
||||
$unchanged_resources = array();
|
||||
$lookup_cache = array();
|
||||
if ($cache = cache_get('lookup_cache', 'cache_bootstrap')) {
|
||||
if ($cache = cache('bootstrap')->get('lookup_cache')) {
|
||||
$lookup_cache = $cache->data;
|
||||
}
|
||||
foreach ($lookup_cache as $key => $file) {
|
||||
|
@ -105,7 +105,7 @@ function _registry_update() {
|
|||
// We have some unchanged resources, warm up the cache - no need to pay
|
||||
// for looking them up again.
|
||||
if (count($unchanged_resources) > 0) {
|
||||
cache_set('lookup_cache', $unchanged_resources, 'cache_bootstrap');
|
||||
cache('bootstrap')->set('lookup_cache', $unchanged_resources);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,20 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Provides a list of countries and languages based on ISO standards.
|
||||
* Provides a list of countries and languages based on web standards.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get an array of all country code => country name pairs.
|
||||
*
|
||||
* Get an array of all country code => country name pairs as laid out
|
||||
* in ISO 3166-1 alpha-2.
|
||||
* Grabbed from location project (http://drupal.org/project/location).
|
||||
* in ISO 3166-1 alpha-2. Originally from the location project
|
||||
* (http://drupal.org/project/location).
|
||||
*
|
||||
* @return
|
||||
* An array of all country code => country name pairs.
|
||||
* An array of country code => country name pairs.
|
||||
*/
|
||||
function _country_get_predefined_list() {
|
||||
function standard_country_list() {
|
||||
static $countries;
|
||||
|
||||
if (isset($countries)) {
|
||||
|
@ -278,16 +279,18 @@ function _country_get_predefined_list() {
|
|||
}
|
||||
|
||||
/**
|
||||
* @ingroup locale-api-predefined List of predefined languages
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Some of the common languages with their English and native names
|
||||
* Some common languages with their English and native names.
|
||||
*
|
||||
* Based on ISO 639 and http://people.w3.org/rishida/names/languages.html
|
||||
* Language codes are defined by the W3C language tags document for
|
||||
* interoperability. Language codes typically have a language and optionally,
|
||||
* a script or regional variant name. See
|
||||
* http://www.w3.org/International/articles/language-tags/ for more information.
|
||||
*
|
||||
* @return
|
||||
* An array of language code to language name information.
|
||||
* Language name information itself is an array of English and native names.
|
||||
*/
|
||||
function _locale_get_predefined_list() {
|
||||
function standard_language_list() {
|
||||
return array(
|
||||
'aa' => array('Afar'),
|
||||
'ab' => array('Abkhazian', 'аҧсуа бызшәа'),
|
||||
|
@ -477,6 +480,3 @@ function _locale_get_predefined_list() {
|
|||
'zu' => array('Zulu', 'isiZulu'),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @} End of "locale-api-languages-predefined"
|
||||
*/
|
|
@ -280,7 +280,7 @@ function _theme_registry_callback($callback = NULL, array $arguments = array())
|
|||
*/
|
||||
function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
|
||||
// Check the theme registry cache; if it exists, use it.
|
||||
$cache = cache_get("theme_registry:$theme->name", 'cache');
|
||||
$cache = cache()->get("theme_registry:$theme->name");
|
||||
if (isset($cache->data)) {
|
||||
$registry = $cache->data;
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL)
|
|||
* Write the theme_registry cache into the database.
|
||||
*/
|
||||
function _theme_save_registry($theme, $registry) {
|
||||
cache_set("theme_registry:$theme->name", $registry);
|
||||
cache()->set("theme_registry:$theme->name", $registry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -309,7 +309,7 @@ function _theme_save_registry($theme, $registry) {
|
|||
* to add more theme hooks.
|
||||
*/
|
||||
function drupal_theme_rebuild() {
|
||||
cache_clear_all('theme_registry', 'cache', TRUE);
|
||||
cache()->deletePrefix('theme_registry');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1902,11 +1902,12 @@ function theme_feed_icon($variables) {
|
|||
*/
|
||||
function theme_html_tag($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = isset($element['#attributes']) ? drupal_attributes($element['#attributes']) : '';
|
||||
if (!isset($element['#value'])) {
|
||||
return '<' . $element['#tag'] . drupal_attributes($element['#attributes']) . " />\n";
|
||||
return '<' . $element['#tag'] . $attributes . " />\n";
|
||||
}
|
||||
else {
|
||||
$output = '<' . $element['#tag'] . drupal_attributes($element['#attributes']) . '>';
|
||||
$output = '<' . $element['#tag'] . $attributes . '>';
|
||||
if (isset($element['#value_prefix'])) {
|
||||
$output .= $element['#value_prefix'];
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ function update_prepare_d8_bootstrap() {
|
|||
// Allow the database system to work even if the registry has not been
|
||||
// created yet.
|
||||
include_once DRUPAL_ROOT . '/includes/install.inc';
|
||||
include_once DRUPAL_ROOT . '/modules/entity/entity.controller.inc';
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
|
||||
|
||||
// If the site has not updated to Drupal 8 yet, check to make sure that it is
|
||||
|
@ -120,6 +121,35 @@ function update_fix_d8_requirements() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to install a new module in Drupal 8 via hook_update_N().
|
||||
*/
|
||||
function update_module_enable(array $modules) {
|
||||
foreach ($modules as $module) {
|
||||
// Check for initial schema and install it. The schema version of a newly
|
||||
// installed module is always 0. Using 8000 here would be inconsistent
|
||||
// since $module_update_8000() may involve a schema change, and we want
|
||||
// to install the schema as it was before any updates were added.
|
||||
$function = $module . '_schema_0';
|
||||
if (function_exists($function)) {
|
||||
$schema = $function();
|
||||
foreach ($schema as $table => $spec) {
|
||||
db_create_table($table, $spec);
|
||||
}
|
||||
}
|
||||
// Change the schema version from SCHEMA_UNINSTALLED to 0, so any module
|
||||
// updates since the module's inception are executed in a core upgrade.
|
||||
db_update('system')
|
||||
->condition('type', 'module')
|
||||
->condition('name', $module)
|
||||
->fields(array('schema_version' => 0))
|
||||
->execute();
|
||||
|
||||
system_list_reset();
|
||||
// @todo: figure out what to do about hook_install() and hook_enable().
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform one update and store the results for display on finished page.
|
||||
*
|
||||
|
|
|
@ -46,8 +46,12 @@ function drupal_var_export($var, $prefix = '') {
|
|||
$output = "'" . $var . "'";
|
||||
}
|
||||
}
|
||||
elseif (is_object($var) && get_class($var) === 'stdClass') {
|
||||
$output = '(object) ' . var_export((array) $var, TRUE);
|
||||
else if (is_object($var) && get_class($var) === 'stdClass') {
|
||||
// var_export() will export stdClass objects using an undefined
|
||||
// magic method __set_state() leaving the export broken. This
|
||||
// workaround avoids this by casting the object as an array for
|
||||
// export and casting it back to an object when evaluated.
|
||||
$output .= '(object) ' . drupal_var_export((array) $var, $prefix);
|
||||
}
|
||||
else {
|
||||
$output = var_export($var, TRUE);
|
||||
|
|
BIN
misc/favicon.ico
BIN
misc/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -301,11 +301,6 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
|
|||
$(self.oldRowElement).removeClass('drag-previous');
|
||||
}
|
||||
|
||||
// Hack for IE6 that flickers uncontrollably if select lists are moved.
|
||||
if (navigator.userAgent.indexOf('MSIE 6.') != -1) {
|
||||
$('select', this.table).css('display', 'none');
|
||||
}
|
||||
|
||||
// Hack for Konqueror, prevent the blur handler from firing.
|
||||
// Konqueror always gives links focus, even after returning false on mousedown.
|
||||
self.safeBlur = false;
|
||||
|
@ -559,11 +554,6 @@ Drupal.tableDrag.prototype.dropRow = function (event, self) {
|
|||
self.dragObject = null;
|
||||
$('body').removeClass('drag');
|
||||
clearInterval(self.scrollInterval);
|
||||
|
||||
// Hack for IE6 that flickers uncontrollably if select lists are moved.
|
||||
if (navigator.userAgent.indexOf('MSIE 6.') != -1) {
|
||||
$('select', this.table).css('display', 'block');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
div.vertical-tabs {
|
||||
margin: 1em 0 1em 15em; /* LTR */
|
||||
border: 1px solid #ccc;
|
||||
position: relative; /* IE6/7 */
|
||||
position: relative; /* IE7 */
|
||||
}
|
||||
.vertical-tabs ul.vertical-tabs-list {
|
||||
width: 15em;
|
||||
list-style: none;
|
||||
list-style-image: none; /* IE6 */
|
||||
list-style-image: none; /* IE7 */
|
||||
border-top: 1px solid #ccc;
|
||||
padding: 0;
|
||||
position: relative; /* IE6 */
|
||||
margin: -1px 0 -1px -15em; /* LTR */
|
||||
float: left; /* LTR */
|
||||
}
|
||||
|
@ -71,7 +70,3 @@ div.vertical-tabs {
|
|||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
* html .vertical-tabs .form-type-textfield,
|
||||
* html .vertical-tabs .form-textarea-wrapper {
|
||||
width: 95%; /* IE6 */
|
||||
}
|
||||
|
|
|
@ -24,19 +24,19 @@
|
|||
</h3>
|
||||
|
||||
<div class="feed-item-meta">
|
||||
<?php if ($source_url) : ?>
|
||||
<?php if ($source_url): ?>
|
||||
<a href="<?php print $source_url; ?>" class="feed-item-source"><?php print $source_title; ?></a> -
|
||||
<?php endif; ?>
|
||||
<span class="feed-item-date"><?php print $source_date; ?></span>
|
||||
</div>
|
||||
|
||||
<?php if ($content) : ?>
|
||||
<?php if ($content): ?>
|
||||
<div class="feed-item-body">
|
||||
<?php print $content; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($categories) : ?>
|
||||
<?php if ($categories): ?>
|
||||
<div class="feed-item-categories">
|
||||
<?php print t('Categories'); ?>: <?php print implode(', ', $categories); ?>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
#aggregator .feed-source .feed-icon {
|
||||
float: left;
|
||||
}
|
|
@ -18,6 +18,6 @@
|
|||
<a href="<?php print $feed_url; ?>"><?php print $feed_title; ?></a>
|
||||
<span class="age"><?php print $feed_age; ?></span>
|
||||
|
||||
<?php if ($source_url) : ?>,
|
||||
<span class="source"><a href="<?php print $source_url; ?>"><?php print $source_title; ?></a></span>
|
||||
<?php if ($source_url): ?>,
|
||||
<span class="source"><a href="<?php print $source_url; ?>"><?php print $source_title; ?></a></span>
|
||||
<?php endif; ?>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* @see template_preprocess_aggregator_wrapper()
|
||||
*/
|
||||
?>
|
||||
<div id="aggregator">
|
||||
<div class="aggregator">
|
||||
<?php print $content; ?>
|
||||
<?php print $pager; ?>
|
||||
</div>
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
#aggregator .feed-source .feed-title {
|
||||
margin-top: 0;
|
||||
}
|
||||
#aggregator .feed-source .feed-image img {
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
#aggregator .feed-source .feed-icon {
|
||||
float: right; /* LTR */
|
||||
display: block;
|
||||
}
|
||||
#aggregator .feed-item {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
#aggregator .feed-item-title {
|
||||
margin-bottom: 0;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
#aggregator .feed-item-meta,
|
||||
#aggregator .feed-item-body {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
#aggregator .feed-item-categories {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
#aggregator td {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
#aggregator td.categorize-item {
|
||||
white-space: nowrap;
|
||||
}
|
||||
#aggregator .categorize-item .news-item .body {
|
||||
margin-top: 0;
|
||||
}
|
||||
#aggregator .categorize-item h3 {
|
||||
margin-bottom: 1em;
|
||||
margin-top: 0;
|
||||
}
|
|
@ -5,4 +5,4 @@ version = VERSION
|
|||
core = 8.x
|
||||
files[] = aggregator.test
|
||||
configure = admin/config/services/aggregator/settings
|
||||
stylesheets[all][] = aggregator.css
|
||||
stylesheets[all][] = aggregator.theme.css
|
||||
|
|
|
@ -226,10 +226,9 @@ function aggregator_schema() {
|
|||
'description' => 'The {aggregator_feed}.fid to which this item belongs.',
|
||||
),
|
||||
'title' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'type' => 'text',
|
||||
'size' => 'normal',
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Title of the feed item.',
|
||||
),
|
||||
'link' => array(
|
||||
|
|
|
@ -478,6 +478,8 @@ function aggregator_save_category($edit) {
|
|||
*
|
||||
* @param $edit
|
||||
* An associative array describing the feed to be added/edited/deleted.
|
||||
* @return
|
||||
* The ID of the feed.
|
||||
*/
|
||||
function aggregator_save_feed($edit) {
|
||||
if (!empty($edit['fid'])) {
|
||||
|
@ -544,6 +546,8 @@ function aggregator_save_feed($edit) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $edit['fid'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
function aggregator_page_last() {
|
||||
drupal_add_feed('aggregator/rss', variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
|
||||
|
||||
$items = aggregator_feed_items_load('sum');
|
||||
$items = aggregator_load_feed_items('sum');
|
||||
|
||||
return _aggregator_page_list($items, arg(1));
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ function aggregator_page_source($feed) {
|
|||
$feed_source = theme('aggregator_feed_source', array('feed' => $feed));
|
||||
|
||||
// It is safe to include the fid in the query because it's loaded from the
|
||||
// database by aggregator_feed_load.
|
||||
$items = aggregator_feed_items_load('source', $feed);
|
||||
// database by aggregator_feed_load().
|
||||
$items = aggregator_load_feed_items('source', $feed);
|
||||
|
||||
return _aggregator_page_list($items, arg(3), $feed_source);
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ function aggregator_page_category($category) {
|
|||
drupal_add_feed('aggregator/rss/' . $category['cid'], variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
|
||||
|
||||
// It is safe to include the cid in the query because it's loaded from the
|
||||
// database by aggregator_category_load.
|
||||
$items = aggregator_feed_items_load('category', $category);
|
||||
// database by aggregator_category_load().
|
||||
$items = aggregator_load_feed_items('category', $category);
|
||||
|
||||
return _aggregator_page_list($items, arg(3));
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ function aggregator_page_category_form($form, $form_state, $category) {
|
|||
* @return
|
||||
* An array of the feed items.
|
||||
*/
|
||||
function aggregator_feed_items_load($type, $data = NULL) {
|
||||
function aggregator_load_feed_items($type, $data = NULL) {
|
||||
$items = array();
|
||||
$range_limit = 20;
|
||||
switch ($type) {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.aggregator .feed-icon {
|
||||
float: left;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
.aggregator .feed-icon {
|
||||
float: right; /* LTR */
|
||||
display: block;
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
<description>First example feed item description.</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Second example feed item title</title>
|
||||
<title>Second example feed item title. This title is extremely long so that it exceeds the 255 character limit for titles in feed item storage. In fact it's so long that this sentence isn't long enough so I'm rambling a bit to make it longer, nearly there now. Ah now it's long enough so I'll shut up.</title>
|
||||
<link>http://example.com/example-turns-two</link>
|
||||
<description>Second example feed item description.</description>
|
||||
</item>
|
||||
|
|
|
@ -77,7 +77,7 @@ function block_admin_display_prepare_blocks($theme) {
|
|||
*/
|
||||
function block_admin_display_form($form, &$form_state, $blocks, $theme, $block_regions = NULL) {
|
||||
|
||||
drupal_add_css(drupal_get_path('module', 'block') . '/block.admin.css');
|
||||
$form['#attached']['css'] = array(drupal_get_path('module', 'block') . '/block.admin.css');
|
||||
|
||||
// Get a list of block regions if one was not provided.
|
||||
if (!isset($block_regions)) {
|
||||
|
@ -276,7 +276,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
|
|||
'#maxlength' => 64,
|
||||
'#description' => $block->module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <em>!placeholder</em> to display no title, or leave blank to use the default block title.', array('!placeholder' => '<none>')),
|
||||
'#default_value' => isset($block->title) ? $block->title : '',
|
||||
'#weight' => -18,
|
||||
'#weight' => -19,
|
||||
);
|
||||
|
||||
// Module-specific block configuration.
|
||||
|
|
|
@ -500,7 +500,7 @@ function block_custom_block_form($edit = array()) {
|
|||
'#maxlength' => 64,
|
||||
'#description' => t('A brief description of your block. Used on the <a href="@overview">Blocks administration page</a>.', array('@overview' => url('admin/structure/block'))),
|
||||
'#required' => TRUE,
|
||||
'#weight' => -19,
|
||||
'#weight' => -18,
|
||||
);
|
||||
$form['body_field']['#weight'] = -17;
|
||||
$form['body_field']['body'] = array(
|
||||
|
@ -668,7 +668,7 @@ function block_list($region) {
|
|||
* Name of the module that implements the block to load.
|
||||
* @param $delta
|
||||
* Unique ID of the block within the context of $module. Pass NULL to return
|
||||
* an empty $block object for $module.
|
||||
* an empty block object for $module.
|
||||
*
|
||||
* @return
|
||||
* A block object.
|
||||
|
@ -827,7 +827,7 @@ function _block_render_blocks($region_blocks) {
|
|||
// with node_access modules. We also preserve the submission of forms in
|
||||
// blocks, by fetching from cache only if the request method is 'GET'
|
||||
// (or 'HEAD').
|
||||
if (!count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
|
||||
if (!count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache = cache('block')->get($cid))) {
|
||||
$array = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -838,7 +838,7 @@ function _block_render_blocks($region_blocks) {
|
|||
drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
|
||||
|
||||
if (isset($cid)) {
|
||||
cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
|
||||
cache('block')->set($cid, $array, CACHE_TEMPORARY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -912,7 +912,7 @@ function block_flush_caches() {
|
|||
_block_rehash($theme->name);
|
||||
}
|
||||
|
||||
return array('cache_block');
|
||||
return array('block');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,7 +83,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
|||
$this->assertTrue(array_key_exists('subject', $data) && empty($data['subject']), t('block_block_view() provides an empty block subject, since custom blocks do not have default titles.'));
|
||||
$this->assertEqual(check_markup($custom_block['body[value]'], $format), $data['content'], t('block_block_view() provides correct block content.'));
|
||||
|
||||
// Check if the block can be moved to all availble regions.
|
||||
// Check whether the block can be moved to all available regions.
|
||||
$custom_block['module'] = 'block';
|
||||
$custom_block['delta'] = $bid;
|
||||
foreach ($this->regions as $region) {
|
||||
|
@ -307,7 +307,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
|||
// Check to see if the block was created by checking that it's in the database.
|
||||
$this->assertNotNull($bid, t('Block found in database'));
|
||||
|
||||
// Check if the block can be moved to all availble regions.
|
||||
// Check whether the block can be moved to all available regions.
|
||||
foreach ($this->regions as $region) {
|
||||
$this->moveBlockToRegion($block, $region);
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
|||
$this->assertText(t('The block settings have been updated.'), t('Block successfully move to disabled region.'));
|
||||
$this->assertNoText(t($block['title']), t('Block no longer appears on page.'));
|
||||
|
||||
// Confirm that the regions xpath is not availble
|
||||
// Confirm that the region's xpath is not available.
|
||||
$xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-block-' . $bid));
|
||||
$this->assertNoFieldByXPath($xpath, FALSE, t('Custom block found in no regions.'));
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
* render() on each to print it as an unordered list.
|
||||
*/
|
||||
?>
|
||||
<?php foreach ($book_menus as $book_id => $menu) : ?>
|
||||
<div id="book-block-menu-<?php print $book_id; ?>" class="book-block-menu">
|
||||
<?php print render($menu); ?>
|
||||
</div>
|
||||
<?php foreach ($book_menus as $book_id => $menu): ?>
|
||||
<div id="book-block-menu-<?php print $book_id; ?>" class="book-block-menu">
|
||||
<?php print render($menu); ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
*/
|
||||
$div_close = '';
|
||||
?>
|
||||
<?php for ($i = 1; $i < $depth; $i++) : ?>
|
||||
<?php for ($i = 1; $i < $depth; $i++): ?>
|
||||
<div class="section-<?php print $i; ?>">
|
||||
<?php $div_close .= '</div>'; ?>
|
||||
<?php endfor; ?>
|
||||
|
|
|
@ -35,13 +35,13 @@
|
|||
|
||||
<?php if ($has_links): ?>
|
||||
<div class="page-links clearfix">
|
||||
<?php if ($prev_url) : ?>
|
||||
<?php if ($prev_url): ?>
|
||||
<a href="<?php print $prev_url; ?>" class="page-previous" title="<?php print t('Go to previous page'); ?>"><?php print t('‹ ') . $prev_title; ?></a>
|
||||
<?php endif; ?>
|
||||
<?php if ($parent_url) : ?>
|
||||
<?php if ($parent_url): ?>
|
||||
<a href="<?php print $parent_url; ?>" class="page-up" title="<?php print t('Go to parent page'); ?>"><?php print t('up'); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php if ($next_url) : ?>
|
||||
<?php if ($next_url): ?>
|
||||
<a href="<?php print $next_url; ?>" class="page-next" title="<?php print t('Go to next page'); ?>"><?php print $next_title . t(' ›'); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
|
|
@ -1262,12 +1262,12 @@ function book_menu_subtree_data($link) {
|
|||
$cid = 'links:' . $link['menu_name'] . ':subtree-cid:' . $link['mlid'];
|
||||
|
||||
if (!isset($tree[$cid])) {
|
||||
$cache = cache_get($cid, 'cache_menu');
|
||||
$cache = cache('menu')->get($cid);
|
||||
|
||||
if ($cache && isset($cache->data)) {
|
||||
// If the cache entry exists, it will just be the cid for the actual data.
|
||||
// This avoids duplication of large amounts of data.
|
||||
$cache = cache_get($cache->data, 'cache_menu');
|
||||
$cache = cache('menu')->get($cache->data);
|
||||
|
||||
if ($cache && isset($cache->data)) {
|
||||
$data = $cache->data;
|
||||
|
@ -1300,11 +1300,11 @@ function book_menu_subtree_data($link) {
|
|||
$tree_cid = 'links:' . $item['menu_name'] . ':subtree-data:' . hash('sha256', serialize($data));
|
||||
// Cache the data, if it is not already in the cache.
|
||||
|
||||
if (!cache_get($tree_cid, 'cache_menu')) {
|
||||
cache_set($tree_cid, $data, 'cache_menu');
|
||||
if (!cache('menu')->get($tree_cid)) {
|
||||
cache('menu')->set($tree_cid, $data);
|
||||
}
|
||||
// Cache the cid of the (shared) data using the menu and item-specific cid.
|
||||
cache_set($cid, $tree_cid, 'cache_menu');
|
||||
cache('menu')->set($cid, $tree_cid);
|
||||
}
|
||||
// Check access for the current user to each item in the tree.
|
||||
menu_tree_check_access($data['tree'], $data['node_links']);
|
||||
|
|
|
@ -43,14 +43,6 @@ Drupal.behaviors.color = {
|
|||
}
|
||||
}
|
||||
|
||||
// Fix preview background in IE6.
|
||||
if (navigator.appVersion.match(/MSIE [0-6]\./)) {
|
||||
var e = $('#preview #img')[0];
|
||||
var image = e.currentStyle.backgroundImage;
|
||||
e.style.backgroundImage = 'none';
|
||||
e.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image.substring(5, image.length - 2) + "')";
|
||||
}
|
||||
|
||||
// Set up colorScheme selector.
|
||||
$('#edit-scheme', form).change(function () {
|
||||
var schemes = settings.color.schemes, colorScheme = this.options[this.selectedIndex].value;
|
||||
|
|
|
@ -189,7 +189,7 @@ function color_scheme_form($complete_form, &$form_state, $theme) {
|
|||
),
|
||||
// Add custom CSS.
|
||||
'css' => array(
|
||||
$base . '/color.css' => array(),
|
||||
$base . '/color.admin.css' => array(),
|
||||
),
|
||||
// Add custom JavaScript.
|
||||
'js' => array(
|
||||
|
|
|
@ -4,6 +4,7 @@ package = Core
|
|||
version = VERSION
|
||||
core = 8.x
|
||||
dependencies[] = text
|
||||
dependencies[] = entity
|
||||
files[] = comment.module
|
||||
files[] = comment.test
|
||||
configure = admin/content/comment
|
||||
|
|
|
@ -92,7 +92,7 @@ function comment_help($path, $arg) {
|
|||
* Implements hook_entity_info().
|
||||
*/
|
||||
function comment_entity_info() {
|
||||
$return = array(
|
||||
$return = array(
|
||||
'comment' => array(
|
||||
'label' => t('Comment'),
|
||||
'base table' => 'comment',
|
||||
|
@ -542,7 +542,7 @@ function comment_new_page_count($num_comments, $new_replies, $node) {
|
|||
elseif ($flat) {
|
||||
// Flat comments.
|
||||
$count = $num_comments - $new_replies;
|
||||
$pageno = $count / $comments_per_page;
|
||||
$pageno = $count / $comments_per_page;
|
||||
}
|
||||
else {
|
||||
// Threaded comments: we build a query with a subquery to find the first
|
||||
|
@ -575,7 +575,7 @@ function comment_new_page_count($num_comments, $new_replies, $node) {
|
|||
':thread' => $first_thread,
|
||||
))->fetchField();
|
||||
|
||||
$pageno = $count / $comments_per_page;
|
||||
$pageno = $count / $comments_per_page;
|
||||
}
|
||||
|
||||
if ($pageno >= 1) {
|
||||
|
@ -655,7 +655,7 @@ function comment_node_view($node, $view_mode) {
|
|||
);
|
||||
}
|
||||
else {
|
||||
$links['comment_forbidden'] = array(
|
||||
$links['comment-forbidden'] = array(
|
||||
'title' => theme('comment_post_forbidden', array('node' => $node)),
|
||||
'html' => TRUE,
|
||||
);
|
||||
|
@ -685,7 +685,7 @@ function comment_node_view($node, $view_mode) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
$links['comment_forbidden'] = array(
|
||||
$links['comment-forbidden'] = array(
|
||||
'title' => theme('comment_post_forbidden', array('node' => $node)),
|
||||
'html' => TRUE,
|
||||
);
|
||||
|
@ -1066,8 +1066,8 @@ function comment_links($comment, $node) {
|
|||
);
|
||||
}
|
||||
else {
|
||||
$links['comment_forbidden']['title'] = theme('comment_post_forbidden', array('node' => $node));
|
||||
$links['comment_forbidden']['html'] = TRUE;
|
||||
$links['comment-forbidden']['title'] = theme('comment_post_forbidden', array('node' => $node));
|
||||
$links['comment-forbidden']['html'] = TRUE;
|
||||
}
|
||||
}
|
||||
return $links;
|
||||
|
@ -1439,7 +1439,7 @@ function comment_save($comment) {
|
|||
|
||||
$transaction = db_transaction();
|
||||
try {
|
||||
$defaults = array(
|
||||
$defaults = array(
|
||||
'mail' => '',
|
||||
'homepage' => '',
|
||||
'name' => '',
|
||||
|
@ -1711,7 +1711,7 @@ function comment_num_new($nid, $timestamp = 0) {
|
|||
$timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT);
|
||||
|
||||
// Use the timestamp to retrieve the number of new comments.
|
||||
return db_query('SELECT COUNT(cid) FROM {comment} WHERE nid = :nid AND created > :timestamp AND status = :status', array(
|
||||
return db_query('SELECT COUNT(cid) FROM {comment} WHERE nid = :nid AND created > :timestamp AND status = :status', array(
|
||||
':nid' => $nid,
|
||||
':timestamp' => $timestamp,
|
||||
':status' => COMMENT_PUBLISHED,
|
||||
|
@ -2279,10 +2279,10 @@ function template_preprocess_comment(&$variables) {
|
|||
|
||||
// Set status to a string representation of comment->status.
|
||||
if (isset($comment->in_preview)) {
|
||||
$variables['status'] = 'comment-preview';
|
||||
$variables['status'] = 'comment-preview';
|
||||
}
|
||||
else {
|
||||
$variables['status'] = ($comment->status == COMMENT_NOT_PUBLISHED) ? 'comment-unpublished' : 'comment-published';
|
||||
$variables['status'] = ($comment->status == COMMENT_NOT_PUBLISHED) ? 'comment-unpublished' : 'comment-published';
|
||||
}
|
||||
// Gather comment classes.
|
||||
if ($comment->uid === 0) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
.form-item-type,
|
||||
.form-item-severity {
|
||||
float: left; /* LTR */
|
||||
|
@ -52,7 +51,9 @@ table#admin-dblog td.icon {
|
|||
table#admin-dblog tr.dblog-warning td.icon {
|
||||
background-image: url(../../misc/message-16-warning.png);
|
||||
}
|
||||
table#admin-dblog tr.dblog-error td.icon {
|
||||
table#admin-dblog tr.dblog-error td.icon,
|
||||
table#admin-dblog tr.dblog-critical td.icon,
|
||||
table#admin-dblog tr.dblog-alert td.icon,
|
||||
table#admin-dblog tr.dblog-emerg td.icon {
|
||||
background-image: url(../../misc/message-16-error.png);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,414 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided the Entity module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Inform the base system and the Field API about one or more entity types.
|
||||
*
|
||||
* Inform the system about one or more entity types (i.e., object types that
|
||||
* can be loaded via entity_load() and, optionally, to which fields can be
|
||||
* attached).
|
||||
*
|
||||
* @return
|
||||
* An array whose keys are entity type names and whose values identify
|
||||
* properties of those types that the system needs to know about:
|
||||
* - label: The human-readable name of the type.
|
||||
* - controller class: The name of the class that is used to load the objects.
|
||||
* The class has to implement the DrupalEntityControllerInterface interface.
|
||||
* Leave blank to use the DrupalDefaultEntityController implementation.
|
||||
* - base table: (used by DrupalDefaultEntityController) The name of the
|
||||
* entity type's base table.
|
||||
* - static cache: (used by DrupalDefaultEntityController) FALSE to disable
|
||||
* static caching of entities during a page request. Defaults to TRUE.
|
||||
* - field cache: (used by Field API loading and saving of field data) FALSE
|
||||
* to disable Field API's persistent cache of field data. Only recommended
|
||||
* if a higher level persistent cache is available for the entity type.
|
||||
* Defaults to TRUE.
|
||||
* - load hook: The name of the hook which should be invoked by
|
||||
* DrupalDefaultEntityController:attachLoad(), for example 'node_load'.
|
||||
* - uri callback: A function taking an entity as argument and returning the
|
||||
* uri elements of the entity, e.g. 'path' and 'options'. The actual entity
|
||||
* uri can be constructed by passing these elements to url().
|
||||
* - label callback: (optional) A function taking an entity as argument and
|
||||
* returning the label of the entity. The entity label is the main string
|
||||
* associated with an entity; for example, the title of a node or the
|
||||
* subject of a comment. If there is an entity object property that defines
|
||||
* the label, use the 'label' element of the 'entity keys' return
|
||||
* value component to provide this information (see below). If more complex
|
||||
* logic is needed to determine the label of an entity, you can instead
|
||||
* specify a callback function here, which will be called to determine the
|
||||
* entity label. See also the entity_label() function, which implements this
|
||||
* logic.
|
||||
* - fieldable: Set to TRUE if you want your entity type to be fieldable.
|
||||
* - translation: An associative array of modules registered as field
|
||||
* translation handlers. Array keys are the module names, array values
|
||||
* can be any data structure the module uses to provide field translation.
|
||||
* Any empty value disallows the module to appear as a translation handler.
|
||||
* - entity keys: An array describing how the Field API can extract the
|
||||
* information it needs from the objects of the type. Elements:
|
||||
* - id: The name of the property that contains the primary id of the
|
||||
* entity. Every entity object passed to the Field API must have this
|
||||
* property and its value must be numeric.
|
||||
* - revision: The name of the property that contains the revision id of
|
||||
* the entity. The Field API assumes that all revision ids are unique
|
||||
* across all entities of a type. This entry can be omitted if the
|
||||
* entities of this type are not versionable.
|
||||
* - bundle: The name of the property that contains the bundle name for the
|
||||
* entity. The bundle name defines which set of fields are attached to
|
||||
* the entity (e.g. what nodes call "content type"). This entry can be
|
||||
* omitted if this entity type exposes a single bundle (all entities have
|
||||
* the same collection of fields). The name of this single bundle will be
|
||||
* the same as the entity type.
|
||||
* - label: The name of the property that contains the entity label. For
|
||||
* example, if the entity's label is located in $entity->subject, then
|
||||
* 'subject' should be specified here. If complex logic is required to
|
||||
* build the label, a 'label callback' should be defined instead (see
|
||||
* the 'label callback' section above for details).
|
||||
* - bundle keys: An array describing how the Field API can extract the
|
||||
* information it needs from the bundle objects for this type (e.g
|
||||
* $vocabulary objects for terms; not applicable for nodes). This entry can
|
||||
* be omitted if this type's bundles do not exist as standalone objects.
|
||||
* Elements:
|
||||
* - bundle: The name of the property that contains the name of the bundle
|
||||
* object.
|
||||
* - bundles: An array describing all bundles for this object type. Keys are
|
||||
* bundles machine names, as found in the objects' 'bundle' property
|
||||
* (defined in the 'entity keys' entry above). Elements:
|
||||
* - label: The human-readable name of the bundle.
|
||||
* - uri callback: Same as the 'uri callback' key documented above for the
|
||||
* entity type, but for the bundle only. When determining the URI of an
|
||||
* entity, if a 'uri callback' is defined for both the entity type and
|
||||
* the bundle, the one for the bundle is used.
|
||||
* - admin: An array of information that allows Field UI pages to attach
|
||||
* themselves to the existing administration pages for the bundle.
|
||||
* Elements:
|
||||
* - path: the path of the bundle's main administration page, as defined
|
||||
* in hook_menu(). If the path includes a placeholder for the bundle,
|
||||
* the 'bundle argument', 'bundle helper' and 'real path' keys below
|
||||
* are required.
|
||||
* - bundle argument: The position of the placeholder in 'path', if any.
|
||||
* - real path: The actual path (no placeholder) of the bundle's main
|
||||
* administration page. This will be used to generate links.
|
||||
* - access callback: As in hook_menu(). 'user_access' will be assumed if
|
||||
* no value is provided.
|
||||
* - access arguments: As in hook_menu().
|
||||
* - view modes: An array describing the view modes for the entity type. View
|
||||
* modes let entities be displayed differently depending on the context.
|
||||
* For instance, a node can be displayed differently on its own page
|
||||
* ('full' mode), on the home page or taxonomy listings ('teaser' mode), or
|
||||
* in an RSS feed ('rss' mode). Modules taking part in the display of the
|
||||
* entity (notably the Field API) can adjust their behavior depending on
|
||||
* the requested view mode. An additional 'default' view mode is available
|
||||
* for all entity types. This view mode is not intended for actual entity
|
||||
* display, but holds default display settings. For each available view
|
||||
* mode, administrators can configure whether it should use its own set of
|
||||
* field display settings, or just replicate the settings of the 'default'
|
||||
* view mode, thus reducing the amount of display configurations to keep
|
||||
* track of. Keys of the array are view mode names. Each view mode is
|
||||
* described by an array with the following key/value pairs:
|
||||
* - label: The human-readable name of the view mode
|
||||
* - custom settings: A boolean specifying whether the view mode should by
|
||||
* default use its own custom field display settings. If FALSE, entities
|
||||
* displayed in this view mode will reuse the 'default' display settings
|
||||
* by default (e.g. right after the module exposing the view mode is
|
||||
* enabled), but administrators can later use the Field UI to apply custom
|
||||
* display settings specific to the view mode.
|
||||
*
|
||||
* @see entity_load()
|
||||
* @see hook_entity_info_alter()
|
||||
*/
|
||||
function hook_entity_info() {
|
||||
$return = array(
|
||||
'node' => array(
|
||||
'label' => t('Node'),
|
||||
'controller class' => 'NodeController',
|
||||
'base table' => 'node',
|
||||
'revision table' => 'node_revision',
|
||||
'uri callback' => 'node_uri',
|
||||
'fieldable' => TRUE,
|
||||
'translation' => array(
|
||||
'locale' => TRUE,
|
||||
),
|
||||
'entity keys' => array(
|
||||
'id' => 'nid',
|
||||
'revision' => 'vid',
|
||||
'bundle' => 'type',
|
||||
),
|
||||
'bundle keys' => array(
|
||||
'bundle' => 'type',
|
||||
),
|
||||
'bundles' => array(),
|
||||
'view modes' => array(
|
||||
'full' => array(
|
||||
'label' => t('Full content'),
|
||||
'custom settings' => FALSE,
|
||||
),
|
||||
'teaser' => array(
|
||||
'label' => t('Teaser'),
|
||||
'custom settings' => TRUE,
|
||||
),
|
||||
'rss' => array(
|
||||
'label' => t('RSS'),
|
||||
'custom settings' => FALSE,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Search integration is provided by node.module, so search-related
|
||||
// view modes for nodes are defined here and not in search.module.
|
||||
if (module_exists('search')) {
|
||||
$return['node']['view modes'] += array(
|
||||
'search_index' => array(
|
||||
'label' => t('Search index'),
|
||||
'custom settings' => FALSE,
|
||||
),
|
||||
'search_result' => array(
|
||||
'label' => t('Search result'),
|
||||
'custom settings' => FALSE,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Bundles must provide a human readable name so we can create help and error
|
||||
// messages, and the path to attach Field admin pages to.
|
||||
foreach (node_type_get_names() as $type => $name) {
|
||||
$return['node']['bundles'][$type] = array(
|
||||
'label' => $name,
|
||||
'admin' => array(
|
||||
'path' => 'admin/structure/types/manage/%node_type',
|
||||
'real path' => 'admin/structure/types/manage/' . str_replace('_', '-', $type),
|
||||
'bundle argument' => 4,
|
||||
'access arguments' => array('administer content types'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the entity info.
|
||||
*
|
||||
* Modules may implement this hook to alter the information that defines an
|
||||
* entity. All properties that are available in hook_entity_info() can be
|
||||
* altered here.
|
||||
*
|
||||
* @param $entity_info
|
||||
* The entity info array, keyed by entity name.
|
||||
*
|
||||
* @see hook_entity_info()
|
||||
*/
|
||||
function hook_entity_info_alter(&$entity_info) {
|
||||
// Set the controller class for nodes to an alternate implementation of the
|
||||
// DrupalEntityController interface.
|
||||
$entity_info['node']['controller class'] = 'MyCustomNodeController';
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entities when loaded.
|
||||
*
|
||||
* This is a generic load hook called for all entity types loaded via the
|
||||
* entity API.
|
||||
*
|
||||
* @param $entities
|
||||
* The entities keyed by entity ID.
|
||||
* @param $type
|
||||
* The type of entities being loaded (i.e. node, user, comment).
|
||||
*/
|
||||
function hook_entity_load($entities, $type) {
|
||||
foreach ($entities as $entity) {
|
||||
$entity->foo = mymodule_add_something($entity, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on an entity before it is about to be created or updated.
|
||||
*
|
||||
* @param $entity
|
||||
* The entity object.
|
||||
* @param $type
|
||||
* The type of entity being saved (i.e. node, user, comment).
|
||||
*/
|
||||
function hook_entity_presave($entity, $type) {
|
||||
$entity->changed = REQUEST_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entities when inserted.
|
||||
*
|
||||
* @param $entity
|
||||
* The entity object.
|
||||
* @param $type
|
||||
* The type of entity being inserted (i.e. node, user, comment).
|
||||
*/
|
||||
function hook_entity_insert($entity, $type) {
|
||||
// Insert the new entity into a fictional table of all entities.
|
||||
$info = entity_get_info($type);
|
||||
list($id) = entity_extract_ids($type, $entity);
|
||||
db_insert('example_entity')
|
||||
->fields(array(
|
||||
'type' => $type,
|
||||
'id' => $id,
|
||||
'created' => REQUEST_TIME,
|
||||
'updated' => REQUEST_TIME,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entities when updated.
|
||||
*
|
||||
* @param $entity
|
||||
* The entity object.
|
||||
* @param $type
|
||||
* The type of entity being updated (i.e. node, user, comment).
|
||||
*/
|
||||
function hook_entity_update($entity, $type) {
|
||||
// Update the entity's entry in a fictional table of all entities.
|
||||
$info = entity_get_info($type);
|
||||
list($id) = entity_extract_ids($type, $entity);
|
||||
db_update('example_entity')
|
||||
->fields(array(
|
||||
'updated' => REQUEST_TIME,
|
||||
))
|
||||
->condition('type', $type)
|
||||
->condition('id', $id)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entities when deleted.
|
||||
*
|
||||
* @param $entity
|
||||
* The entity object.
|
||||
* @param $type
|
||||
* The type of entity being deleted (i.e. node, user, comment).
|
||||
*/
|
||||
function hook_entity_delete($entity, $type) {
|
||||
// Delete the entity's entry from a fictional table of all entities.
|
||||
$info = entity_get_info($type);
|
||||
list($id) = entity_extract_ids($type, $entity);
|
||||
db_delete('example_entity')
|
||||
->condition('type', $type)
|
||||
->condition('id', $id)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter or execute an EntityFieldQuery.
|
||||
*
|
||||
* @param EntityFieldQuery $query
|
||||
* An EntityFieldQuery. One of the most important properties to be changed is
|
||||
* EntityFieldQuery::executeCallback. If this is set to an existing function,
|
||||
* this function will get the query as its single argument and its result
|
||||
* will be the returned as the result of EntityFieldQuery::execute(). This can
|
||||
* be used to change the behavior of EntityFieldQuery entirely. For example,
|
||||
* the default implementation can only deal with one field storage engine, but
|
||||
* it is possible to write a module that can query across field storage
|
||||
* engines. Also, the default implementation presumes entities are stored in
|
||||
* SQL, but the execute callback could instead query any other entity storage,
|
||||
* local or remote.
|
||||
*
|
||||
* Note the $query->altered attribute which is TRUE in case the query has
|
||||
* already been altered once. This happens with cloned queries.
|
||||
* If there is a pager, then such a cloned query will be executed to count
|
||||
* all elements. This query can be detected by checking for
|
||||
* ($query->pager && $query->count), allowing the driver to return 0 from
|
||||
* the count query and disable the pager.
|
||||
*/
|
||||
function hook_entity_query_alter($query) {
|
||||
$query->executeCallback = 'my_module_query_callback';
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entities being assembled before rendering.
|
||||
*
|
||||
* @param $entity
|
||||
* The entity object.
|
||||
* @param $type
|
||||
* The type of entity being rendered (i.e. node, user, comment).
|
||||
* @param $view_mode
|
||||
* The view mode the entity is rendered in.
|
||||
* @param $langcode
|
||||
* The language code used for rendering.
|
||||
*
|
||||
* The module may add elements to $entity->content prior to rendering. The
|
||||
* structure of $entity->content is a renderable array as expected by
|
||||
* drupal_render().
|
||||
*
|
||||
* @see hook_entity_view_alter()
|
||||
* @see hook_comment_view()
|
||||
* @see hook_node_view()
|
||||
* @see hook_user_view()
|
||||
*/
|
||||
function hook_entity_view($entity, $type, $view_mode, $langcode) {
|
||||
$entity->content['my_additional_field'] = array(
|
||||
'#markup' => $additional_field,
|
||||
'#weight' => 10,
|
||||
'#theme' => 'mymodule_my_additional_field',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the results of ENTITY_view().
|
||||
*
|
||||
* This hook is called after the content has been assembled in a structured
|
||||
* array and may be used for doing processing which requires that the complete
|
||||
* entity content structure has been built.
|
||||
*
|
||||
* If a module wishes to act on the rendered HTML of the entity rather than the
|
||||
* structured content array, it may use this hook to add a #post_render
|
||||
* callback. Alternatively, it could also implement hook_preprocess_ENTITY().
|
||||
* See drupal_render() and theme() for details.
|
||||
*
|
||||
* @param $build
|
||||
* A renderable array representing the entity content.
|
||||
* @param $type
|
||||
* The type of entity being rendered (i.e. node, user, comment).
|
||||
*
|
||||
* @see hook_entity_view()
|
||||
* @see hook_comment_view_alter()
|
||||
* @see hook_node_view_alter()
|
||||
* @see hook_taxonomy_term_view_alter()
|
||||
* @see hook_user_view_alter()
|
||||
*/
|
||||
function hook_entity_view_alter(&$build, $type) {
|
||||
if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
|
||||
// Change its weight.
|
||||
$build['an_additional_field']['#weight'] = -10;
|
||||
|
||||
// Add a #post_render callback to act on the rendered HTML of the entity.
|
||||
$build['#post_render'][] = 'my_module_node_post_render';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entities as they are being prepared for view.
|
||||
*
|
||||
* Allows you to operate on multiple entities as they are being prepared for
|
||||
* view. Only use this if attaching the data during the entity_load() phase
|
||||
* is not appropriate, for example when attaching other 'entity' style objects.
|
||||
*
|
||||
* @param $entities
|
||||
* The entities keyed by entity ID.
|
||||
* @param $type
|
||||
* The type of entities being loaded (i.e. node, user, comment).
|
||||
*/
|
||||
function hook_entity_prepare_view($entities, $type) {
|
||||
// Load a specific node into the user object for later theming.
|
||||
if ($type == 'user') {
|
||||
$nodes = mymodule_get_user_nodes(array_keys($entities));
|
||||
foreach ($entities as $uid => $entity) {
|
||||
$entity->user_node = $nodes[$uid];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,390 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Entity API controller classes and interface.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for entity controller classes.
|
||||
*
|
||||
* All entity controller classes specified via the 'controller class' key
|
||||
* returned by hook_entity_info() or hook_entity_info_alter() have to implement
|
||||
* this interface.
|
||||
*
|
||||
* Most simple, SQL-based entity controllers will do better by extending
|
||||
* DrupalDefaultEntityController instead of implementing this interface
|
||||
* directly.
|
||||
*/
|
||||
interface DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param $entityType
|
||||
* The entity type for which the instance is created.
|
||||
*/
|
||||
public function __construct($entityType);
|
||||
|
||||
/**
|
||||
* Resets the internal, static entity cache.
|
||||
*
|
||||
* @param $ids
|
||||
* (optional) If specified, the cache is reset for the entities with the
|
||||
* given ids only.
|
||||
*/
|
||||
public function resetCache(array $ids = NULL);
|
||||
|
||||
/**
|
||||
* Loads one or more entities.
|
||||
*
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* An array of conditions in the form 'field' => $value.
|
||||
*
|
||||
* @return
|
||||
* An array of entity objects indexed by their ids.
|
||||
*/
|
||||
public function load($ids = array(), $conditions = array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of DrupalEntityControllerInterface.
|
||||
*
|
||||
* This class can be used as-is by most simple entity types. Entity types
|
||||
* requiring special handling can extend the class.
|
||||
*/
|
||||
class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Static cache of entities.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $entityCache;
|
||||
|
||||
/**
|
||||
* Entity type for this controller instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* Array of information about the entity.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see entity_get_info()
|
||||
*/
|
||||
protected $entityInfo;
|
||||
|
||||
/**
|
||||
* Additional arguments to pass to hook_TYPE_load().
|
||||
*
|
||||
* Set before calling DrupalDefaultEntityController::attachLoad().
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hookLoadArguments;
|
||||
|
||||
/**
|
||||
* Name of the entity's ID field in the entity database table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $idKey;
|
||||
|
||||
/**
|
||||
* Name of entity's revision database table field, if it supports revisions.
|
||||
*
|
||||
* Has the value FALSE if this entity does not use revisions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $revisionKey;
|
||||
|
||||
/**
|
||||
* The table that stores revisions, if the entity supports revisions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $revisionTable;
|
||||
|
||||
/**
|
||||
* Whether this entity type should use the static cache.
|
||||
*
|
||||
* Set by entity info.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Constructor: sets basic variables.
|
||||
*/
|
||||
public function __construct($entityType) {
|
||||
$this->entityType = $entityType;
|
||||
$this->entityInfo = entity_get_info($entityType);
|
||||
$this->entityCache = array();
|
||||
$this->hookLoadArguments = array();
|
||||
$this->idKey = $this->entityInfo['entity keys']['id'];
|
||||
|
||||
// Check if the entity type supports revisions.
|
||||
if (!empty($this->entityInfo['entity keys']['revision'])) {
|
||||
$this->revisionKey = $this->entityInfo['entity keys']['revision'];
|
||||
$this->revisionTable = $this->entityInfo['revision table'];
|
||||
}
|
||||
else {
|
||||
$this->revisionKey = FALSE;
|
||||
}
|
||||
|
||||
// Check if the entity type supports static caching of loaded entities.
|
||||
$this->cache = !empty($this->entityInfo['static cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements DrupalEntityControllerInterface::resetCache().
|
||||
*/
|
||||
public function resetCache(array $ids = NULL) {
|
||||
if (isset($ids)) {
|
||||
foreach ($ids as $id) {
|
||||
unset($this->entityCache[$id]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->entityCache = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements DrupalEntityControllerInterface::load().
|
||||
*/
|
||||
public function load($ids = array(), $conditions = array()) {
|
||||
$entities = array();
|
||||
|
||||
// Revisions are not statically cached, and require a different query to
|
||||
// other conditions, so separate the revision id into its own variable.
|
||||
if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
|
||||
$revision_id = $conditions[$this->revisionKey];
|
||||
unset($conditions[$this->revisionKey]);
|
||||
}
|
||||
else {
|
||||
$revision_id = FALSE;
|
||||
}
|
||||
|
||||
// Create a new variable which is either a prepared version of the $ids
|
||||
// array for later comparison with the entity cache, or FALSE if no $ids
|
||||
// were passed. The $ids array is reduced as items are loaded from cache,
|
||||
// and we need to know if it's empty for this reason to avoid querying the
|
||||
// database when all requested entities are loaded from cache.
|
||||
$passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
|
||||
// Try to load entities from the static cache, if the entity type supports
|
||||
// static caching.
|
||||
if ($this->cache && !$revision_id) {
|
||||
$entities += $this->cacheGet($ids, $conditions);
|
||||
// If any entities were loaded, remove them from the ids still to load.
|
||||
if ($passed_ids) {
|
||||
$ids = array_keys(array_diff_key($passed_ids, $entities));
|
||||
}
|
||||
}
|
||||
|
||||
// Load any remaining entities from the database. This is the case if $ids
|
||||
// is set to FALSE (so we load all entities), if there are any ids left to
|
||||
// load, if loading a revision, or if $conditions was passed without $ids.
|
||||
if ($ids === FALSE || $ids || $revision_id || ($conditions && !$passed_ids)) {
|
||||
// Build the query.
|
||||
$query = $this->buildQuery($ids, $conditions, $revision_id);
|
||||
$queried_entities = $query
|
||||
->execute()
|
||||
->fetchAllAssoc($this->idKey);
|
||||
}
|
||||
|
||||
// Pass all entities loaded from the database through $this->attachLoad(),
|
||||
// which attaches fields (if supported by the entity type) and calls the
|
||||
// entity type specific load callback, for example hook_node_load().
|
||||
if (!empty($queried_entities)) {
|
||||
$this->attachLoad($queried_entities, $revision_id);
|
||||
$entities += $queried_entities;
|
||||
}
|
||||
|
||||
if ($this->cache) {
|
||||
// Add entities to the cache if we are not loading a revision.
|
||||
if (!empty($queried_entities) && !$revision_id) {
|
||||
$this->cacheSet($queried_entities);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the returned array is ordered the same as the original
|
||||
// $ids array if this was passed in and remove any invalid ids.
|
||||
if ($passed_ids) {
|
||||
// Remove any invalid ids from the array.
|
||||
$passed_ids = array_intersect_key($passed_ids, $entities);
|
||||
foreach ($entities as $entity) {
|
||||
$passed_ids[$entity->{$this->idKey}] = $entity;
|
||||
}
|
||||
$entities = $passed_ids;
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the query to load the entity.
|
||||
*
|
||||
* This has full revision support. For entities requiring special queries,
|
||||
* the class can be extended, and the default query can be constructed by
|
||||
* calling parent::buildQuery(). This is usually necessary when the object
|
||||
* being loaded needs to be augmented with additional data from another
|
||||
* table, such as loading node type into comments or vocabulary machine name
|
||||
* into terms, however it can also support $conditions on different tables.
|
||||
* See CommentController::buildQuery() or TaxonomyTermController::buildQuery()
|
||||
* for examples.
|
||||
*
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* An array of conditions in the form 'field' => $value.
|
||||
* @param $revision_id
|
||||
* The ID of the revision to load, or FALSE if this query is asking for the
|
||||
* most current revision(s).
|
||||
*
|
||||
* @return SelectQuery
|
||||
* A SelectQuery object for loading the entity.
|
||||
*/
|
||||
protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
|
||||
$query = db_select($this->entityInfo['base table'], 'base');
|
||||
|
||||
$query->addTag($this->entityType . '_load_multiple');
|
||||
|
||||
if ($revision_id) {
|
||||
$query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
|
||||
}
|
||||
elseif ($this->revisionKey) {
|
||||
$query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
|
||||
}
|
||||
|
||||
// Add fields from the {entity} table.
|
||||
$entity_fields = $this->entityInfo['schema_fields_sql']['base table'];
|
||||
|
||||
if ($this->revisionKey) {
|
||||
// Add all fields from the {entity_revision} table.
|
||||
$entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision table']);
|
||||
// The id field is provided by entity, so remove it.
|
||||
unset($entity_revision_fields[$this->idKey]);
|
||||
|
||||
// Remove all fields from the base table that are also fields by the same
|
||||
// name in the revision table.
|
||||
$entity_field_keys = array_flip($entity_fields);
|
||||
foreach ($entity_revision_fields as $key => $name) {
|
||||
if (isset($entity_field_keys[$name])) {
|
||||
unset($entity_fields[$entity_field_keys[$name]]);
|
||||
}
|
||||
}
|
||||
$query->fields('revision', $entity_revision_fields);
|
||||
}
|
||||
|
||||
$query->fields('base', $entity_fields);
|
||||
|
||||
if ($ids) {
|
||||
$query->condition("base.{$this->idKey}", $ids, 'IN');
|
||||
}
|
||||
if ($conditions) {
|
||||
foreach ($conditions as $field => $value) {
|
||||
$query->condition('base.' . $field, $value);
|
||||
}
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches data to entities upon loading.
|
||||
*
|
||||
* This will attach fields, if the entity is fieldable. It calls
|
||||
* hook_entity_load() for modules which need to add data to all entities.
|
||||
* It also calls hook_TYPE_load() on the loaded entities. For example
|
||||
* hook_node_load() or hook_user_load(). If your hook_TYPE_load()
|
||||
* expects special parameters apart from the queried entities, you can set
|
||||
* $this->hookLoadArguments prior to calling the method.
|
||||
* See NodeController::attachLoad() for an example.
|
||||
*
|
||||
* @param $queried_entities
|
||||
* Associative array of query results, keyed on the entity ID.
|
||||
* @param $revision_id
|
||||
* ID of the revision that was loaded, or FALSE if teh most current revision
|
||||
* was loaded.
|
||||
*/
|
||||
protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
|
||||
// Attach fields.
|
||||
if ($this->entityInfo['fieldable']) {
|
||||
if ($revision_id) {
|
||||
field_attach_load_revision($this->entityType, $queried_entities);
|
||||
}
|
||||
else {
|
||||
field_attach_load($this->entityType, $queried_entities);
|
||||
}
|
||||
}
|
||||
|
||||
// Call hook_entity_load().
|
||||
foreach (module_implements('entity_load') as $module) {
|
||||
$function = $module . '_entity_load';
|
||||
$function($queried_entities, $this->entityType);
|
||||
}
|
||||
// Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
|
||||
// always the queried entities, followed by additional arguments set in
|
||||
// $this->hookLoadArguments.
|
||||
$args = array_merge(array($queried_entities), $this->hookLoadArguments);
|
||||
foreach (module_implements($this->entityInfo['load hook']) as $module) {
|
||||
call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets entities from the static cache.
|
||||
*
|
||||
* @param $ids
|
||||
* If not empty, return entities that match these IDs.
|
||||
* @param $conditions
|
||||
* If set, return entities that match all of these conditions.
|
||||
*
|
||||
* @return
|
||||
* Array of entities from the entity cache.
|
||||
*/
|
||||
protected function cacheGet($ids, $conditions = array()) {
|
||||
$entities = array();
|
||||
// Load any available entities from the internal cache.
|
||||
if (!empty($this->entityCache)) {
|
||||
if ($ids) {
|
||||
$entities += array_intersect_key($this->entityCache, array_flip($ids));
|
||||
}
|
||||
// If loading entities only by conditions, fetch all available entities
|
||||
// from the cache. Entities which don't match are removed later.
|
||||
elseif ($conditions) {
|
||||
$entities = $this->entityCache;
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude any entities loaded from cache if they don't match $conditions.
|
||||
// This ensures the same behavior whether loading from memory or database.
|
||||
if ($conditions) {
|
||||
foreach ($entities as $entity) {
|
||||
$entity_values = (array) $entity;
|
||||
if (array_diff_assoc($conditions, $entity_values)) {
|
||||
unset($entities[$entity->{$this->idKey}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores entities in the static entity cache.
|
||||
*
|
||||
* @param $entities
|
||||
* Entities to store in the cache.
|
||||
*/
|
||||
protected function cacheSet($entities) {
|
||||
$this->entityCache += $entities;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
name = Entity
|
||||
description = API for managing entities like nodes and users.
|
||||
package = Core
|
||||
version = VERSION
|
||||
core = 8.x
|
||||
required = TRUE
|
||||
files[] = entity.query.inc
|
||||
files[] = entity.controller.inc
|
|
@ -0,0 +1,442 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Entity API for handling entities like nodes or users.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function entity_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#entity':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Entity module provides an API for managing entities like nodes and users, i.e. an API for loading and identifying entities. For more information, see the online handbook entry for <a href="!url">Entity module</a>', array('!url' => 'http://drupal.org/handbook/modules/entity')) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_preenable().
|
||||
*/
|
||||
function entity_modules_preenable() {
|
||||
entity_info_cache_clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_disabled().
|
||||
*/
|
||||
function entity_modules_disabled() {
|
||||
entity_info_cache_clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity info array of an entity type.
|
||||
*
|
||||
* @see hook_entity_info()
|
||||
* @see hook_entity_info_alter()
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type, e.g. node, for which the info shall be returned, or NULL
|
||||
* to return an array with info about all types.
|
||||
*/
|
||||
function entity_get_info($entity_type = NULL) {
|
||||
global $language;
|
||||
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['entity_info'] = &drupal_static(__FUNCTION__);
|
||||
}
|
||||
$entity_info = &$drupal_static_fast['entity_info'];
|
||||
|
||||
// hook_entity_info() includes translated strings, so each language is cached
|
||||
// separately.
|
||||
$langcode = $language->language;
|
||||
|
||||
if (empty($entity_info)) {
|
||||
if ($cache = cache()->get("entity_info:$langcode")) {
|
||||
$entity_info = $cache->data;
|
||||
}
|
||||
else {
|
||||
$entity_info = module_invoke_all('entity_info');
|
||||
// Merge in default values.
|
||||
foreach ($entity_info as $name => $data) {
|
||||
$entity_info[$name] += array(
|
||||
'fieldable' => FALSE,
|
||||
'controller class' => 'DrupalDefaultEntityController',
|
||||
'static cache' => TRUE,
|
||||
'field cache' => TRUE,
|
||||
'load hook' => $name . '_load',
|
||||
'bundles' => array(),
|
||||
'view modes' => array(),
|
||||
'entity keys' => array(),
|
||||
'translation' => array(),
|
||||
);
|
||||
$entity_info[$name]['entity keys'] += array(
|
||||
'revision' => '',
|
||||
'bundle' => '',
|
||||
);
|
||||
foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) {
|
||||
$entity_info[$name]['view modes'][$view_mode] += array(
|
||||
'custom settings' => FALSE,
|
||||
);
|
||||
}
|
||||
// If no bundle key is provided, assume a single bundle, named after
|
||||
// the entity type.
|
||||
if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) {
|
||||
$entity_info[$name]['bundles'] = array($name => array('label' => $entity_info[$name]['label']));
|
||||
}
|
||||
// Prepare entity schema fields SQL info for
|
||||
// DrupalEntityControllerInterface::buildQuery().
|
||||
if (isset($entity_info[$name]['base table'])) {
|
||||
$entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
|
||||
if (isset($entity_info[$name]['revision table'])) {
|
||||
$entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Let other modules alter the entity info.
|
||||
drupal_alter('entity_info', $entity_info);
|
||||
cache()->set("entity_info:$langcode", $entity_info);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($entity_type)) {
|
||||
return $entity_info;
|
||||
}
|
||||
elseif (isset($entity_info[$entity_type])) {
|
||||
return $entity_info[$entity_type];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the cached information about entity types.
|
||||
*/
|
||||
function entity_info_cache_clear() {
|
||||
drupal_static_reset('entity_get_info');
|
||||
// Clear all languages.
|
||||
cache()->deletePrefix('entity_info:');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to extract id, vid, and bundle name from an entity.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g. 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The entity from which to extract values.
|
||||
* @return
|
||||
* A numerically indexed array (not a hash table) containing these
|
||||
* elements:
|
||||
* 0: primary id of the entity
|
||||
* 1: revision id of the entity, or NULL if $entity_type is not versioned
|
||||
* 2: bundle name of the entity
|
||||
*/
|
||||
function entity_extract_ids($entity_type, $entity) {
|
||||
$info = entity_get_info($entity_type);
|
||||
|
||||
// Objects being created might not have id/vid yet.
|
||||
$id = isset($entity->{$info['entity keys']['id']}) ? $entity->{$info['entity keys']['id']} : NULL;
|
||||
$vid = ($info['entity keys']['revision'] && isset($entity->{$info['entity keys']['revision']})) ? $entity->{$info['entity keys']['revision']} : NULL;
|
||||
|
||||
if (!empty($info['entity keys']['bundle'])) {
|
||||
// Explicitly fail for malformed entities missing the bundle property.
|
||||
if (!isset($entity->{$info['entity keys']['bundle']}) || $entity->{$info['entity keys']['bundle']} === '') {
|
||||
throw new EntityMalformedException(t('Missing bundle property on entity of type @entity_type.', array('@entity_type' => $entity_type)));
|
||||
}
|
||||
$bundle = $entity->{$info['entity keys']['bundle']};
|
||||
}
|
||||
else {
|
||||
// The entity type provides no bundle key: assume a single bundle, named
|
||||
// after the entity type.
|
||||
$bundle = $entity_type;
|
||||
}
|
||||
|
||||
return array($id, $vid, $bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to assemble an object structure with initial ids.
|
||||
*
|
||||
* This function can be seen as reciprocal to entity_extract_ids().
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g. 'node' or 'user'.
|
||||
* @param $ids
|
||||
* A numerically indexed array, as returned by entity_extract_ids(),
|
||||
* containing these elements:
|
||||
* 0: primary id of the entity
|
||||
* 1: revision id of the entity, or NULL if $entity_type is not versioned
|
||||
* 2: bundle name of the entity, or NULL if $entity_type has no bundles
|
||||
*
|
||||
* @return
|
||||
* An entity structure, initialized with the ids provided.
|
||||
*/
|
||||
function entity_create_stub_entity($entity_type, $ids) {
|
||||
$entity = new stdClass();
|
||||
$info = entity_get_info($entity_type);
|
||||
$entity->{$info['entity keys']['id']} = $ids[0];
|
||||
if (!empty($info['entity keys']['revision']) && isset($ids[1])) {
|
||||
$entity->{$info['entity keys']['revision']} = $ids[1];
|
||||
}
|
||||
if (!empty($info['entity keys']['bundle']) && isset($ids[2])) {
|
||||
$entity->{$info['entity keys']['bundle']} = $ids[2];
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads entities from the database.
|
||||
*
|
||||
* This function should be used whenever you need to load more than one entity
|
||||
* from the database. The entities are loaded into memory and will not require
|
||||
* database access if loaded again during the same page request.
|
||||
*
|
||||
* The actual loading is done through a class that has to implement the
|
||||
* DrupalEntityControllerInterface interface. By default,
|
||||
* DrupalDefaultEntityController is used. Entity types can specify that a
|
||||
* different class should be used by setting the 'controller class' key in
|
||||
* hook_entity_info(). These classes can either implement the
|
||||
* DrupalEntityControllerInterface interface, or, most commonly, extend the
|
||||
* DrupalDefaultEntityController class. See node_entity_info() and the
|
||||
* NodeController in node.module as an example.
|
||||
*
|
||||
* @see hook_entity_info()
|
||||
* @see DrupalEntityControllerInterface
|
||||
* @see DrupalDefaultEntityController
|
||||
* @see EntityFieldQuery
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type to load, e.g. node or user.
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* (deprecated) An associative array of conditions on the base table, where
|
||||
* the keys are the database fields and the values are the values those
|
||||
* fields must have. Instead, it is preferable to use EntityFieldQuery to
|
||||
* retrieve a list of entity IDs loadable by this function.
|
||||
* @param $reset
|
||||
* Whether to reset the internal cache for the requested entity type.
|
||||
*
|
||||
* @return
|
||||
* An array of entity objects indexed by their ids.
|
||||
*
|
||||
* @todo Remove $conditions in Drupal 8.
|
||||
*/
|
||||
function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) {
|
||||
if ($reset) {
|
||||
entity_get_controller($entity_type)->resetCache();
|
||||
}
|
||||
return entity_get_controller($entity_type)->load($ids, $conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the unchanged, i.e. not modified, entity from the database.
|
||||
*
|
||||
* Unlike entity_load() this function ensures the entity is directly loaded from
|
||||
* the database, thus bypassing any static cache. In particular, this function
|
||||
* is useful to determine changes by comparing the entity being saved to the
|
||||
* stored entity.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type to load, e.g. node or user.
|
||||
* @param $id
|
||||
* The id of the entity to load.
|
||||
*
|
||||
* @return
|
||||
* The unchanged entity, or FALSE if the entity cannot be loaded.
|
||||
*/
|
||||
function entity_load_unchanged($entity_type, $id) {
|
||||
entity_get_controller($entity_type)->resetCache(array($id));
|
||||
$result = entity_get_controller($entity_type)->load(array($id));
|
||||
return reset($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity controller class for an entity type.
|
||||
*/
|
||||
function entity_get_controller($entity_type) {
|
||||
$controllers = &drupal_static(__FUNCTION__, array());
|
||||
if (!isset($controllers[$entity_type])) {
|
||||
$type_info = entity_get_info($entity_type);
|
||||
$class = $type_info['controller class'];
|
||||
$controllers[$entity_type] = new $class($entity_type);
|
||||
}
|
||||
return $controllers[$entity_type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes hook_entity_prepare_view().
|
||||
*
|
||||
* If adding a new entity similar to nodes, comments or users, you should
|
||||
* invoke this function during the ENTITY_build_content() or
|
||||
* ENTITY_view_multiple() phases of rendering to allow other modules to alter
|
||||
* the objects during this phase. This is needed for situations where
|
||||
* information needs to be loaded outside of ENTITY_load() - particularly
|
||||
* when loading entities into one another - i.e. a user object into a node, due
|
||||
* to the potential for unwanted side-effects such as caching and infinite
|
||||
* recursion. By convention, entity_prepare_view() is called after
|
||||
* field_attach_prepare_view() to allow entity level hooks to act on content
|
||||
* loaded by field API.
|
||||
*
|
||||
* @see hook_entity_prepare_view()
|
||||
*
|
||||
* @param $entity_type
|
||||
* The type of entity, i.e. 'node', 'user'.
|
||||
* @param $entities
|
||||
* The entity objects which are being prepared for view, keyed by object ID.
|
||||
*/
|
||||
function entity_prepare_view($entity_type, $entities) {
|
||||
// To ensure hooks are only run once per entity, check for an
|
||||
// entity_view_prepared flag and only process items without it.
|
||||
// @todo: resolve this more generally for both entity and field level hooks.
|
||||
$prepare = array();
|
||||
foreach ($entities as $id => $entity) {
|
||||
if (empty($entity->entity_view_prepared)) {
|
||||
// Add this entity to the items to be prepared.
|
||||
$prepare[$id] = $entity;
|
||||
|
||||
// Mark this item as prepared.
|
||||
$entity->entity_view_prepared = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($prepare)) {
|
||||
module_invoke_all('entity_prepare_view', $prepare, $entity_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uri elements of an entity.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g. 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The entity for which to generate a path.
|
||||
*
|
||||
* @return
|
||||
* An array containing the 'path' and 'options' keys used to build the uri of
|
||||
* the entity, and matching the signature of url(). NULL if the entity has no
|
||||
* uri of its own.
|
||||
*/
|
||||
function entity_uri($entity_type, $entity) {
|
||||
$info = entity_get_info($entity_type);
|
||||
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
|
||||
// A bundle-specific callback takes precedence over the generic one for the
|
||||
// entity type.
|
||||
if (isset($info['bundles'][$bundle]['uri callback'])) {
|
||||
$uri_callback = $info['bundles'][$bundle]['uri callback'];
|
||||
}
|
||||
elseif (isset($info['uri callback'])) {
|
||||
$uri_callback = $info['uri callback'];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Invoke the callback to get the URI. If there is no callback, return NULL.
|
||||
if (isset($uri_callback) && function_exists($uri_callback)) {
|
||||
$uri = $uri_callback($entity);
|
||||
// Pass the entity data to url() so that alter functions do not need to
|
||||
// lookup this entity again.
|
||||
$uri['options']['entity_type'] = $entity_type;
|
||||
$uri['options']['entity'] = $entity;
|
||||
return $uri;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of an entity.
|
||||
*
|
||||
* See the 'label callback' component of the hook_entity_info() return value
|
||||
* for more information.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type; e.g., 'node' or 'user'.
|
||||
* @param $entity
|
||||
* The entity for which to generate the label.
|
||||
*
|
||||
* @return
|
||||
* The entity label, or FALSE if not found.
|
||||
*/
|
||||
function entity_label($entity_type, $entity) {
|
||||
$label = FALSE;
|
||||
$info = entity_get_info($entity_type);
|
||||
if (isset($info['label callback']) && function_exists($info['label callback'])) {
|
||||
$label = $info['label callback']($entity_type, $entity);
|
||||
}
|
||||
elseif (!empty($info['entity keys']['label']) && isset($entity->{$info['entity keys']['label']})) {
|
||||
$label = $entity->{$info['entity keys']['label']};
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for attaching field API validation to entity forms.
|
||||
*/
|
||||
function entity_form_field_validate($entity_type, $form, &$form_state) {
|
||||
// All field attach API functions act on an entity object, but during form
|
||||
// validation, we don't have one. $form_state contains the entity as it was
|
||||
// prior to processing the current form submission, and we must not update it
|
||||
// until we have fully validated the submitted input. Therefore, for
|
||||
// validation, act on a pseudo entity created out of the form values.
|
||||
$pseudo_entity = (object) $form_state['values'];
|
||||
field_attach_form_validate($entity_type, $pseudo_entity, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for copying submitted values to entity properties for simple entity forms.
|
||||
*
|
||||
* During the submission handling of an entity form's "Save", "Preview", and
|
||||
* possibly other buttons, the form state's entity needs to be updated with the
|
||||
* submitted form values. Each entity form implements its own builder function
|
||||
* for doing this, appropriate for the particular entity and form, whereas
|
||||
* modules may specify additional builder functions in $form['#entity_builders']
|
||||
* for copying the form values of added form elements to entity properties.
|
||||
* Many of the main entity builder functions can call this helper function to
|
||||
* re-use its logic of copying $form_state['values'][PROPERTY] values to
|
||||
* $entity->PROPERTY for all entries in $form_state['values'] that are not field
|
||||
* data, and calling field_attach_submit() to copy field data. Apart from that
|
||||
* this helper invokes any additional builder functions that have been specified
|
||||
* in $form['#entity_builders'].
|
||||
*
|
||||
* For some entity forms (e.g., forms with complex non-field data and forms that
|
||||
* simultaneously edit multiple entities), this behavior may be inappropriate,
|
||||
* so the builder function for such forms needs to implement the required
|
||||
* functionality instead of calling this function.
|
||||
*/
|
||||
function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state) {
|
||||
$info = entity_get_info($entity_type);
|
||||
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
|
||||
|
||||
// Copy top-level form values that are not for fields to entity properties,
|
||||
// without changing existing entity properties that are not being edited by
|
||||
// this form. Copying field values must be done using field_attach_submit().
|
||||
$values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $bundle)) : $form_state['values'];
|
||||
foreach ($values_excluding_fields as $key => $value) {
|
||||
$entity->$key = $value;
|
||||
}
|
||||
|
||||
// Invoke all specified builders for copying form values to entity properties.
|
||||
if (isset($form['#entity_builders'])) {
|
||||
foreach ($form['#entity_builders'] as $function) {
|
||||
$function($entity_type, $entity, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy field values to the entity.
|
||||
if ($info['fieldable']) {
|
||||
field_attach_submit($entity_type, $entity, $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when a malformed entity is passed.
|
||||
*/
|
||||
class EntityMalformedException extends Exception { }
|
||||
|
|
@ -1,388 +1,9 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Interface for entity controller classes.
|
||||
*
|
||||
* All entity controller classes specified via the 'controller class' key
|
||||
* returned by hook_entity_info() or hook_entity_info_alter() have to implement
|
||||
* this interface.
|
||||
*
|
||||
* Most simple, SQL-based entity controllers will do better by extending
|
||||
* DrupalDefaultEntityController instead of implementing this interface
|
||||
* directly.
|
||||
* @file
|
||||
* Entity query API.
|
||||
*/
|
||||
interface DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param $entityType
|
||||
* The entity type for which the instance is created.
|
||||
*/
|
||||
public function __construct($entityType);
|
||||
|
||||
/**
|
||||
* Resets the internal, static entity cache.
|
||||
*
|
||||
* @param $ids
|
||||
* (optional) If specified, the cache is reset for the entities with the
|
||||
* given ids only.
|
||||
*/
|
||||
public function resetCache(array $ids = NULL);
|
||||
|
||||
/**
|
||||
* Loads one or more entities.
|
||||
*
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* An array of conditions in the form 'field' => $value.
|
||||
*
|
||||
* @return
|
||||
* An array of entity objects indexed by their ids. When no results are
|
||||
* found, an empty array is returned.
|
||||
*/
|
||||
public function load($ids = array(), $conditions = array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of DrupalEntityControllerInterface.
|
||||
*
|
||||
* This class can be used as-is by most simple entity types. Entity types
|
||||
* requiring special handling can extend the class.
|
||||
*/
|
||||
class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Static cache of entities.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $entityCache;
|
||||
|
||||
/**
|
||||
* Entity type for this controller instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* Array of information about the entity.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see entity_get_info()
|
||||
*/
|
||||
protected $entityInfo;
|
||||
|
||||
/**
|
||||
* Additional arguments to pass to hook_TYPE_load().
|
||||
*
|
||||
* Set before calling DrupalDefaultEntityController::attachLoad().
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hookLoadArguments;
|
||||
|
||||
/**
|
||||
* Name of the entity's ID field in the entity database table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $idKey;
|
||||
|
||||
/**
|
||||
* Name of entity's revision database table field, if it supports revisions.
|
||||
*
|
||||
* Has the value FALSE if this entity does not use revisions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $revisionKey;
|
||||
|
||||
/**
|
||||
* The table that stores revisions, if the entity supports revisions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $revisionTable;
|
||||
|
||||
/**
|
||||
* Whether this entity type should use the static cache.
|
||||
*
|
||||
* Set by entity info.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Constructor: sets basic variables.
|
||||
*/
|
||||
public function __construct($entityType) {
|
||||
$this->entityType = $entityType;
|
||||
$this->entityInfo = entity_get_info($entityType);
|
||||
$this->entityCache = array();
|
||||
$this->hookLoadArguments = array();
|
||||
$this->idKey = $this->entityInfo['entity keys']['id'];
|
||||
|
||||
// Check if the entity type supports revisions.
|
||||
if (!empty($this->entityInfo['entity keys']['revision'])) {
|
||||
$this->revisionKey = $this->entityInfo['entity keys']['revision'];
|
||||
$this->revisionTable = $this->entityInfo['revision table'];
|
||||
}
|
||||
else {
|
||||
$this->revisionKey = FALSE;
|
||||
}
|
||||
|
||||
// Check if the entity type supports static caching of loaded entities.
|
||||
$this->cache = !empty($this->entityInfo['static cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements DrupalEntityControllerInterface::resetCache().
|
||||
*/
|
||||
public function resetCache(array $ids = NULL) {
|
||||
if (isset($ids)) {
|
||||
foreach ($ids as $id) {
|
||||
unset($this->entityCache[$id]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->entityCache = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements DrupalEntityControllerInterface::load().
|
||||
*/
|
||||
public function load($ids = array(), $conditions = array()) {
|
||||
$entities = array();
|
||||
|
||||
// Revisions are not statically cached, and require a different query to
|
||||
// other conditions, so separate the revision id into its own variable.
|
||||
if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
|
||||
$revision_id = $conditions[$this->revisionKey];
|
||||
unset($conditions[$this->revisionKey]);
|
||||
}
|
||||
else {
|
||||
$revision_id = FALSE;
|
||||
}
|
||||
|
||||
// Create a new variable which is either a prepared version of the $ids
|
||||
// array for later comparison with the entity cache, or FALSE if no $ids
|
||||
// were passed. The $ids array is reduced as items are loaded from cache,
|
||||
// and we need to know if it's empty for this reason to avoid querying the
|
||||
// database when all requested entities are loaded from cache.
|
||||
$passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
|
||||
// Try to load entities from the static cache, if the entity type supports
|
||||
// static caching.
|
||||
if ($this->cache && !$revision_id) {
|
||||
$entities += $this->cacheGet($ids, $conditions);
|
||||
// If any entities were loaded, remove them from the ids still to load.
|
||||
if ($passed_ids) {
|
||||
$ids = array_keys(array_diff_key($passed_ids, $entities));
|
||||
}
|
||||
}
|
||||
|
||||
// Load any remaining entities from the database. This is the case if $ids
|
||||
// is set to FALSE (so we load all entities), if there are any ids left to
|
||||
// load, if loading a revision, or if $conditions was passed without $ids.
|
||||
if ($ids === FALSE || $ids || $revision_id || ($conditions && !$passed_ids)) {
|
||||
// Build the query.
|
||||
$query = $this->buildQuery($ids, $conditions, $revision_id);
|
||||
$queried_entities = $query
|
||||
->execute()
|
||||
->fetchAllAssoc($this->idKey);
|
||||
}
|
||||
|
||||
// Pass all entities loaded from the database through $this->attachLoad(),
|
||||
// which attaches fields (if supported by the entity type) and calls the
|
||||
// entity type specific load callback, for example hook_node_load().
|
||||
if (!empty($queried_entities)) {
|
||||
$this->attachLoad($queried_entities, $revision_id);
|
||||
$entities += $queried_entities;
|
||||
}
|
||||
|
||||
if ($this->cache) {
|
||||
// Add entities to the cache if we are not loading a revision.
|
||||
if (!empty($queried_entities) && !$revision_id) {
|
||||
$this->cacheSet($queried_entities);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the returned array is ordered the same as the original
|
||||
// $ids array if this was passed in and remove any invalid ids.
|
||||
if ($passed_ids) {
|
||||
// Remove any invalid ids from the array.
|
||||
$passed_ids = array_intersect_key($passed_ids, $entities);
|
||||
foreach ($entities as $entity) {
|
||||
$passed_ids[$entity->{$this->idKey}] = $entity;
|
||||
}
|
||||
$entities = $passed_ids;
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the query to load the entity.
|
||||
*
|
||||
* This has full revision support. For entities requiring special queries,
|
||||
* the class can be extended, and the default query can be constructed by
|
||||
* calling parent::buildQuery(). This is usually necessary when the object
|
||||
* being loaded needs to be augmented with additional data from another
|
||||
* table, such as loading node type into comments or vocabulary machine name
|
||||
* into terms, however it can also support $conditions on different tables.
|
||||
* See CommentController::buildQuery() or TaxonomyTermController::buildQuery()
|
||||
* for examples.
|
||||
*
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* An array of conditions in the form 'field' => $value.
|
||||
* @param $revision_id
|
||||
* The ID of the revision to load, or FALSE if this query is asking for the
|
||||
* most current revision(s).
|
||||
*
|
||||
* @return SelectQuery
|
||||
* A SelectQuery object for loading the entity.
|
||||
*/
|
||||
protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
|
||||
$query = db_select($this->entityInfo['base table'], 'base');
|
||||
|
||||
$query->addTag($this->entityType . '_load_multiple');
|
||||
|
||||
if ($revision_id) {
|
||||
$query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
|
||||
}
|
||||
elseif ($this->revisionKey) {
|
||||
$query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
|
||||
}
|
||||
|
||||
// Add fields from the {entity} table.
|
||||
$entity_fields = $this->entityInfo['schema_fields_sql']['base table'];
|
||||
|
||||
if ($this->revisionKey) {
|
||||
// Add all fields from the {entity_revision} table.
|
||||
$entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision table']);
|
||||
// The id field is provided by entity, so remove it.
|
||||
unset($entity_revision_fields[$this->idKey]);
|
||||
|
||||
// Remove all fields from the base table that are also fields by the same
|
||||
// name in the revision table.
|
||||
$entity_field_keys = array_flip($entity_fields);
|
||||
foreach ($entity_revision_fields as $key => $name) {
|
||||
if (isset($entity_field_keys[$name])) {
|
||||
unset($entity_fields[$entity_field_keys[$name]]);
|
||||
}
|
||||
}
|
||||
$query->fields('revision', $entity_revision_fields);
|
||||
}
|
||||
|
||||
$query->fields('base', $entity_fields);
|
||||
|
||||
if ($ids) {
|
||||
$query->condition("base.{$this->idKey}", $ids, 'IN');
|
||||
}
|
||||
if ($conditions) {
|
||||
foreach ($conditions as $field => $value) {
|
||||
$query->condition('base.' . $field, $value);
|
||||
}
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches data to entities upon loading.
|
||||
* This will attach fields, if the entity is fieldable. It calls
|
||||
* hook_entity_load() for modules which need to add data to all entities.
|
||||
* It also calls hook_TYPE_load() on the loaded entities. For example
|
||||
* hook_node_load() or hook_user_load(). If your hook_TYPE_load()
|
||||
* expects special parameters apart from the queried entities, you can set
|
||||
* $this->hookLoadArguments prior to calling the method.
|
||||
* See NodeController::attachLoad() for an example.
|
||||
*
|
||||
* @param $queried_entities
|
||||
* Associative array of query results, keyed on the entity ID.
|
||||
* @param $revision_id
|
||||
* ID of the revision that was loaded, or FALSE if teh most current revision
|
||||
* was loaded.
|
||||
*/
|
||||
protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
|
||||
// Attach fields.
|
||||
if ($this->entityInfo['fieldable']) {
|
||||
if ($revision_id) {
|
||||
field_attach_load_revision($this->entityType, $queried_entities);
|
||||
}
|
||||
else {
|
||||
field_attach_load($this->entityType, $queried_entities);
|
||||
}
|
||||
}
|
||||
|
||||
// Call hook_entity_load().
|
||||
foreach (module_implements('entity_load') as $module) {
|
||||
$function = $module . '_entity_load';
|
||||
$function($queried_entities, $this->entityType);
|
||||
}
|
||||
// Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
|
||||
// always the queried entities, followed by additional arguments set in
|
||||
// $this->hookLoadArguments.
|
||||
$args = array_merge(array($queried_entities), $this->hookLoadArguments);
|
||||
foreach (module_implements($this->entityInfo['load hook']) as $module) {
|
||||
call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets entities from the static cache.
|
||||
*
|
||||
* @param $ids
|
||||
* If not empty, return entities that match these IDs.
|
||||
* @param $conditions
|
||||
* If set, return entities that match all of these conditions.
|
||||
*
|
||||
* @return
|
||||
* Array of entities from the entity cache.
|
||||
*/
|
||||
protected function cacheGet($ids, $conditions = array()) {
|
||||
$entities = array();
|
||||
// Load any available entities from the internal cache.
|
||||
if (!empty($this->entityCache)) {
|
||||
if ($ids) {
|
||||
$entities += array_intersect_key($this->entityCache, array_flip($ids));
|
||||
}
|
||||
// If loading entities only by conditions, fetch all available entities
|
||||
// from the cache. Entities which don't match are removed later.
|
||||
elseif ($conditions) {
|
||||
$entities = $this->entityCache;
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude any entities loaded from cache if they don't match $conditions.
|
||||
// This ensures the same behavior whether loading from memory or database.
|
||||
if ($conditions) {
|
||||
foreach ($entities as $entity) {
|
||||
$entity_values = (array) $entity;
|
||||
if (array_diff_assoc($conditions, $entity_values)) {
|
||||
unset($entities[$entity->{$this->idKey}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores entities in the static entity cache.
|
||||
*
|
||||
* @param $entities
|
||||
* Entities to store in the cache.
|
||||
*/
|
||||
protected function cacheSet($entities) {
|
||||
$this->entityCache += $entities;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown by EntityFieldQuery() on unsupported query syntax.
|
||||
|
@ -613,6 +234,8 @@ class EntityFieldQuery {
|
|||
* literals of the same type as the column.
|
||||
* - 'BETWEEN': This operator expects $value to be an array of two literals
|
||||
* of the same type as the column.
|
||||
* The operator can be omitted, and will default to 'IN' if the value is an
|
||||
* array, or to '=' otherwise.
|
||||
*
|
||||
* @return EntityFieldQuery
|
||||
* The called object.
|
||||
|
@ -729,6 +352,8 @@ class EntityFieldQuery {
|
|||
* literals of the same type as the column.
|
||||
* - 'BETWEEN': This operator expects $value to be an array of two literals
|
||||
* of the same type as the column.
|
||||
* The operator can be omitted, and will default to 'IN' if the value is an
|
||||
* array, or to '=' otherwise.
|
||||
* @param $delta_group
|
||||
* An arbitrary identifier: conditions in the same group must have the same
|
||||
* $delta_group. For example, let's presume a multivalue field which has
|
||||
|
@ -934,7 +559,7 @@ class EntityFieldQuery {
|
|||
}
|
||||
|
||||
/**
|
||||
* Enable a pager for the query.
|
||||
* Enables a pager for the query.
|
||||
*
|
||||
* @param $limit
|
||||
* An integer specifying the number of elements per page. If passed a false
|
||||
|
@ -962,7 +587,7 @@ class EntityFieldQuery {
|
|||
}
|
||||
|
||||
/**
|
||||
* Enable sortable tables for this query.
|
||||
* Enables sortable tables for this query.
|
||||
*
|
||||
* @param $headers
|
||||
* An EFQ Header array based on which the order clause is added to the query.
|
||||
|
@ -1239,7 +864,7 @@ class EntityFieldQuery {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the total number of results and initialize a pager for the query.
|
||||
* Gets the total number of results and initialize a pager for the query.
|
||||
*
|
||||
* This query can be detected by checking for ($this->pager && $this->count),
|
||||
* which allows a driver to return 0 from the count query and disable
|
||||
|
@ -1326,7 +951,3 @@ class EntityFieldQuery {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when a malformed entity is passed.
|
||||
*/
|
||||
class EntityMalformedException extends Exception { }
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Unit test file for the entity API.
|
|
@ -710,7 +710,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
|
|||
$data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']};
|
||||
}
|
||||
$cid = "field:$entity_type:$id";
|
||||
cache_set($cid, $data, 'cache_field');
|
||||
cache('field')->set($cid, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -984,7 +984,7 @@ function field_attach_update($entity_type, $entity) {
|
|||
|
||||
$entity_info = entity_get_info($entity_type);
|
||||
if ($entity_info['field cache']) {
|
||||
cache_clear_all("field:$entity_type:$id", 'cache_field');
|
||||
cache('field')->delete("field:$entity_type:$id");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1021,7 +1021,7 @@ function field_attach_delete($entity_type, $entity) {
|
|||
|
||||
$entity_info = entity_get_info($entity_type);
|
||||
if ($entity_info['field cache']) {
|
||||
cache_clear_all("field:$entity_type:$id", 'cache_field');
|
||||
cache('field')->delete("field:$entity_type:$id");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@ function theme_field_multiple_value_form($variables) {
|
|||
if ($element['#cardinality'] > 1 || $element['#cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
|
||||
$table_id = drupal_html_id($element['#field_name'] . '_values');
|
||||
$order_class = $element['#field_name'] . '-delta-order';
|
||||
$required = !empty($element['#required']) ? '<abbr class="form-required" title="' . t('This field is required. ') . '">*</abbr>' : '';
|
||||
$required = !empty($element['#required']) ? theme('form_required_marker', $variables) : '';
|
||||
|
||||
$header = array(
|
||||
array(
|
||||
|
|
|
@ -7,5 +7,6 @@ files[] = field.module
|
|||
files[] = field.attach.inc
|
||||
files[] = tests/field.test
|
||||
dependencies[] = field_sql_storage
|
||||
dependencies[] = entity
|
||||
required = TRUE
|
||||
stylesheets[all][] = theme/field.css
|
||||
|
|
|
@ -76,12 +76,12 @@ function _field_info_collate_types($reset = FALSE) {
|
|||
if ($reset) {
|
||||
$info = NULL;
|
||||
// Clear all languages.
|
||||
cache_clear_all('field_info_types:', 'cache_field', TRUE);
|
||||
cache('field')->deletePrefix('field_info_types:');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($info)) {
|
||||
if ($cached = cache_get("field_info_types:$langcode", 'cache_field')) {
|
||||
if ($cached = cache('field')->get("field_info_types:$langcode")) {
|
||||
$info = $cached->data;
|
||||
}
|
||||
else {
|
||||
|
@ -149,7 +149,7 @@ function _field_info_collate_types($reset = FALSE) {
|
|||
}
|
||||
drupal_alter('field_storage_info', $info['storage types']);
|
||||
|
||||
cache_set("field_info_types:$langcode", $info, 'cache_field');
|
||||
cache('field')->set("field_info_types:$langcode", $info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,12 +181,12 @@ function _field_info_collate_fields($reset = FALSE) {
|
|||
|
||||
if ($reset) {
|
||||
$info = NULL;
|
||||
cache_clear_all('field_info_fields', 'cache_field');
|
||||
cache('field')->delete('field_info_fields');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($info)) {
|
||||
if ($cached = cache_get('field_info_fields', 'cache_field')) {
|
||||
if ($cached = cache('field')->get('field_info_fields')) {
|
||||
$info = $cached->data;
|
||||
}
|
||||
else {
|
||||
|
@ -238,7 +238,7 @@ function _field_info_collate_fields($reset = FALSE) {
|
|||
}
|
||||
}
|
||||
|
||||
cache_set('field_info_fields', $info, 'cache_field');
|
||||
cache('field')->set('field_info_fields', $info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -421,7 +421,7 @@ function field_system_info_alter(&$info, $file, $type) {
|
|||
*/
|
||||
function field_flush_caches() {
|
||||
field_sync_field_status();
|
||||
return array('cache_field');
|
||||
return array('field');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -772,7 +772,7 @@ function _field_extra_fields_pre_render($elements) {
|
|||
* Clear the field info and field data caches.
|
||||
*/
|
||||
function field_cache_clear() {
|
||||
cache_clear_all('*', 'cache_field', TRUE);
|
||||
cache('field')->flush();
|
||||
field_info_cache_clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,9 +60,9 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_multilingual_settings_changed().
|
||||
* Implements hook_locale_language_delete().
|
||||
*/
|
||||
function field_multilingual_settings_changed() {
|
||||
function field_locale_language_delete() {
|
||||
field_info_cache_clear();
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ function field_valid_language($langcode, $default = TRUE) {
|
|||
return $langcode;
|
||||
}
|
||||
global $language_content;
|
||||
return $default ? language_default('language') : $language_content->language;
|
||||
return $default ? language_default()->language : $language_content->language;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -824,18 +824,18 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
|||
$cid = "field:$entity_type:{$entity_init->ftid}";
|
||||
|
||||
// Check that no initial cache entry is present.
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no initial cache entry'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Non-cached: no initial cache entry'));
|
||||
|
||||
// Save, and check that no cache entry is present.
|
||||
$entity = clone($entity_init);
|
||||
$entity->{$this->field_name}[$langcode] = $values;
|
||||
field_attach_insert($entity_type, $entity);
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no cache entry on insert'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Non-cached: no cache entry on insert'));
|
||||
|
||||
// Load, and check that no cache entry is present.
|
||||
$entity = clone($entity_init);
|
||||
field_attach_load($entity_type, array($entity->ftid => $entity));
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no cache entry on load'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Non-cached: no cache entry on load'));
|
||||
|
||||
|
||||
// Cacheable entity type.
|
||||
|
@ -846,24 +846,24 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
|||
field_create_instance($instance);
|
||||
|
||||
// Check that no initial cache entry is present.
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no initial cache entry'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Cached: no initial cache entry'));
|
||||
|
||||
// Save, and check that no cache entry is present.
|
||||
$entity = clone($entity_init);
|
||||
$entity->{$this->field_name}[$langcode] = $values;
|
||||
field_attach_insert($entity_type, $entity);
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on insert'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Cached: no cache entry on insert'));
|
||||
|
||||
// Load a single field, and check that no cache entry is present.
|
||||
$entity = clone($entity_init);
|
||||
field_attach_load($entity_type, array($entity->ftid => $entity), FIELD_LOAD_CURRENT, array('field_id' => $this->field_id));
|
||||
$cache = cache_get($cid, 'cache_field');
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on loading a single field'));
|
||||
$cache = cache('field')->get($cid);
|
||||
$this->assertFalse(cache('field')->get($cid), t('Cached: no cache entry on loading a single field'));
|
||||
|
||||
// Load, and check that a cache entry is present with the expected values.
|
||||
$entity = clone($entity_init);
|
||||
field_attach_load($entity_type, array($entity->ftid => $entity));
|
||||
$cache = cache_get($cid, 'cache_field');
|
||||
$cache = cache('field')->get($cid);
|
||||
$this->assertEqual($cache->data[$this->field_name][$langcode], $values, t('Cached: correct cache entry on load'));
|
||||
|
||||
// Update with different values, and check that the cache entry is wiped.
|
||||
|
@ -871,12 +871,12 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
|||
$entity = clone($entity_init);
|
||||
$entity->{$this->field_name}[$langcode] = $values;
|
||||
field_attach_update($entity_type, $entity);
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on update'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Cached: no cache entry on update'));
|
||||
|
||||
// Load, and check that a cache entry is present with the expected values.
|
||||
$entity = clone($entity_init);
|
||||
field_attach_load($entity_type, array($entity->ftid => $entity));
|
||||
$cache = cache_get($cid, 'cache_field');
|
||||
$cache = cache('field')->get($cid);
|
||||
$this->assertEqual($cache->data[$this->field_name][$langcode], $values, t('Cached: correct cache entry on load'));
|
||||
|
||||
// Create a new revision, and check that the cache entry is wiped.
|
||||
|
@ -885,18 +885,18 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
|
|||
$entity = clone($entity_init);
|
||||
$entity->{$this->field_name}[$langcode] = $values;
|
||||
field_attach_update($entity_type, $entity);
|
||||
$cache = cache_get($cid, 'cache_field');
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on new revision creation'));
|
||||
$cache = cache('field')->get($cid);
|
||||
$this->assertFalse(cache('field')->get($cid), t('Cached: no cache entry on new revision creation'));
|
||||
|
||||
// Load, and check that a cache entry is present with the expected values.
|
||||
$entity = clone($entity_init);
|
||||
field_attach_load($entity_type, array($entity->ftid => $entity));
|
||||
$cache = cache_get($cid, 'cache_field');
|
||||
$cache = cache('field')->get($cid);
|
||||
$this->assertEqual($cache->data[$this->field_name][$langcode], $values, t('Cached: correct cache entry on load'));
|
||||
|
||||
// Delete, and check that the cache entry is wiped.
|
||||
field_attach_delete($entity_type, $entity);
|
||||
$this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry after delete'));
|
||||
$this->assertFalse(cache('field')->get($cid), t('Cached: no cache entry after delete'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,11 +49,11 @@ After copying this file to your theme's folder and customizing it, remove this
|
|||
HTML comment.
|
||||
-->
|
||||
<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
|
||||
<?php if (!$label_hidden) : ?>
|
||||
<?php if (!$label_hidden): ?>
|
||||
<div class="field-label"<?php print $title_attributes; ?>><?php print $label ?>: </div>
|
||||
<?php endif; ?>
|
||||
<div class="field-items"<?php print $content_attributes; ?>>
|
||||
<?php foreach ($items as $delta => $item) : ?>
|
||||
<?php foreach ($items as $delta => $item): ?>
|
||||
<div class="field-item <?php print $delta % 2 ? 'odd' : 'even'; ?>"<?php print $item_attributes[$delta]; ?>><?php print render($item); ?></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
|
|
@ -428,7 +428,7 @@ function file_field_widget_settings_form($field, $instance) {
|
|||
'bar' => t('Bar with progress meter'),
|
||||
),
|
||||
'#default_value' => $settings['progress_indicator'],
|
||||
'#description' => t('The throbber display does not show the status of uploads but takes up space. The progress bar is helpful for monitoring progress on large uploads.'),
|
||||
'#description' => t('The throbber display does not show the status of uploads but takes up less space. The progress bar is helpful for monitoring progress on large uploads.'),
|
||||
'#weight' => 16,
|
||||
'#access' => file_progress_implementation(),
|
||||
);
|
||||
|
@ -447,37 +447,18 @@ function file_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
|||
'description' => '',
|
||||
);
|
||||
|
||||
// Retrieve any values set in $form_state, as will be the case during Ajax
|
||||
// rebuilds of this form.
|
||||
if (isset($form_state['values'])) {
|
||||
$path = array_merge($element['#field_parents'], array($field['field_name'], $langcode));
|
||||
$path_exists = FALSE;
|
||||
$values = drupal_array_get_nested_value($form_state['values'], $path, $path_exists);
|
||||
if ($path_exists) {
|
||||
$items = $values;
|
||||
drupal_array_set_nested_value($form_state['values'], $path, NULL);
|
||||
}
|
||||
// Load the items for form rebuilds from the field state as they might not be
|
||||
// in $form_state['values'] because of validation limitations. Also, they are
|
||||
// only passed in as $items when editing existing entities.
|
||||
$field_state = field_form_get_state($element['#field_parents'], $field['field_name'], $langcode, $form_state);
|
||||
if (isset($field_state['items'])) {
|
||||
$items = $field_state['items'];
|
||||
}
|
||||
|
||||
foreach ($items as $delta => $item) {
|
||||
$items[$delta] = array_merge($defaults, $items[$delta]);
|
||||
// Remove any items from being displayed that are not needed.
|
||||
if ($items[$delta]['fid'] == 0) {
|
||||
unset($items[$delta]);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-index deltas after removing empty items.
|
||||
$items = array_values($items);
|
||||
|
||||
// Update order according to weight.
|
||||
$items = _field_sort_items($field, $items);
|
||||
|
||||
// Essentially we use the managed_file type, extended with some enhancements.
|
||||
$element_info = element_info('managed_file');
|
||||
$element += array(
|
||||
'#type' => 'managed_file',
|
||||
'#default_value' => isset($items[$delta]) ? $items[$delta] : $defaults,
|
||||
'#upload_location' => file_field_widget_uri($field, $instance),
|
||||
'#upload_validators' => file_field_widget_upload_validators($field, $instance),
|
||||
'#value_callback' => 'file_field_widget_value',
|
||||
|
@ -487,6 +468,8 @@ function file_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
|||
);
|
||||
|
||||
if ($field['cardinality'] == 1) {
|
||||
// Set the default value.
|
||||
$element['#default_value'] = !empty($items) ? $items[0] : $defaults;
|
||||
// If there's only one field, return it as delta 0.
|
||||
if (empty($element['#default_value']['fid'])) {
|
||||
$element['#description'] = theme('file_upload_help', array('description' => $element['#description'], 'upload_validators' => $element['#upload_validators']));
|
||||
|
@ -495,15 +478,15 @@ function file_field_widget_form(&$form, &$form_state, $field, $instance, $langco
|
|||
}
|
||||
else {
|
||||
// If there are multiple values, add an element for each existing one.
|
||||
$delta = -1;
|
||||
foreach ($items as $delta => $item) {
|
||||
foreach ($items as $item) {
|
||||
$elements[$delta] = $element;
|
||||
$elements[$delta]['#default_value'] = $item;
|
||||
$elements[$delta]['#weight'] = $delta;
|
||||
$delta++;
|
||||
}
|
||||
// And then add one more empty row for new uploads.
|
||||
$delta++;
|
||||
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta < $field['cardinality']) {
|
||||
// And then add one more empty row for new uploads except when this is a
|
||||
// programmed form as it is not necessary.
|
||||
if (($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta < $field['cardinality']) && empty($form_state['programmed'])) {
|
||||
$elements[$delta] = $element;
|
||||
$elements[$delta]['#default_value'] = $defaults;
|
||||
$elements[$delta]['#weight'] = $delta;
|
||||
|
@ -757,6 +740,32 @@ function file_field_widget_submit($form, &$form_state) {
|
|||
// so nothing is lost in doing this.
|
||||
$parents = array_slice($form_state['triggering_element']['#parents'], 0, -2);
|
||||
drupal_array_set_nested_value($form_state['input'], $parents, NULL);
|
||||
|
||||
$button = $form_state['triggering_element'];
|
||||
|
||||
// Go one level up in the form, to the widgets container.
|
||||
$element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
|
||||
$field_name = $element['#field_name'];
|
||||
$langcode = $element['#language'];
|
||||
$parents = $element['#field_parents'];
|
||||
|
||||
$submitted_values = drupal_array_get_nested_value($form_state['values'], array_slice($button['#array_parents'], 0, -2));
|
||||
foreach ($submitted_values as $delta => $submitted_value) {
|
||||
if (!$submitted_value['fid']) {
|
||||
unset($submitted_values[$delta]);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-index deltas after removing empty items.
|
||||
$submitted_values = array_values($submitted_values);
|
||||
|
||||
// Update form_state values.
|
||||
drupal_array_set_nested_value($form_state['values'], array_slice($button['#array_parents'], 0, -2), $submitted_values);
|
||||
|
||||
// Update items.
|
||||
$field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
|
||||
$field_state['items'] = $submitted_values;
|
||||
field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -643,9 +643,18 @@ function file_managed_file_save_upload($element) {
|
|||
function theme_file_managed_file($variables) {
|
||||
$element = $variables['element'];
|
||||
|
||||
$attributes = array();
|
||||
if (isset($element['#id'])) {
|
||||
$attributes['id'] = $element['#id'];
|
||||
}
|
||||
if (!empty($element['#attributes']['class'])) {
|
||||
$attributes['class'] = (array) $element['#attributes']['class'];
|
||||
}
|
||||
$attributes['class'][] = 'form-managed-file';
|
||||
|
||||
// This wrapper is required to apply JS behaviors and CSS styling.
|
||||
$output = '';
|
||||
$output .= '<div class="form-managed-file">';
|
||||
$output .= '<div' . drupal_attributes($attributes) . '>';
|
||||
$output .= drupal_render_children($element);
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
|
|
|
@ -380,7 +380,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests upload and remove buttons, with and without Ajax, for a multi-valued File field.
|
||||
* Tests upload and remove buttons, with and without Ajax, for multiple multi-valued File field.
|
||||
*/
|
||||
function testMultiValuedWidget() {
|
||||
// Use 'page' instead of 'article', so that the 'article' image field does
|
||||
|
@ -389,77 +389,106 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
|
|||
// using a custom node type.
|
||||
$type_name = 'page';
|
||||
$field_name = strtolower($this->randomName());
|
||||
$field_name2 = strtolower($this->randomName());
|
||||
$this->createFileField($field_name, $type_name, array('cardinality' => 3));
|
||||
$this->createFileField($field_name2, $type_name, array('cardinality' => 3));
|
||||
|
||||
$field = field_info_field($field_name);
|
||||
$instance = field_info_instance('node', $field_name, $type_name);
|
||||
|
||||
$field2 = field_info_field($field_name2);
|
||||
$instance2 = field_info_instance('node', $field_name2, $type_name);
|
||||
|
||||
$test_file = $this->getTestFile('text');
|
||||
|
||||
foreach (array('nojs', 'js') as $type) {
|
||||
// Visit the node creation form, and upload 3 files. Since the field has
|
||||
// cardinality of 3, ensure the "Upload" button is displayed until after
|
||||
// the 3rd file, and after that, isn't displayed.
|
||||
// Visit the node creation form, and upload 3 files for each field. Since
|
||||
// the field has cardinality of 3, ensure the "Upload" button is displayed
|
||||
// until after the 3rd file, and after that, isn't displayed. Because
|
||||
// SimpleTest triggers the last button with a given name, so upload to the
|
||||
// second field first.
|
||||
// @todo This is only testing a non-Ajax upload, because drupalPostAJAX()
|
||||
// does not yet emulate jQuery's file upload.
|
||||
//
|
||||
$this->drupalGet("node/add/$type_name");
|
||||
for ($delta = 0; $delta < 3; $delta++) {
|
||||
$edit = array('files[' . $field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']' => drupal_realpath($test_file->uri));
|
||||
// If the Upload button doesn't exist, drupalPost() will automatically
|
||||
// fail with an assertion message.
|
||||
$this->drupalPost(NULL, $edit, t('Upload'));
|
||||
foreach (array($field_name2, $field_name) as $each_field_name) {
|
||||
for ($delta = 0; $delta < 3; $delta++) {
|
||||
$edit = array('files[' . $each_field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']' => drupal_realpath($test_file->uri));
|
||||
// If the Upload button doesn't exist, drupalPost() will automatically
|
||||
// fail with an assertion message.
|
||||
$this->drupalPost(NULL, $edit, t('Upload'));
|
||||
}
|
||||
}
|
||||
$this->assertNoFieldByXpath('//input[@type="submit"]', t('Upload'), t('After uploading 3 files, the "Upload" button is no longer displayed.'));
|
||||
$this->assertNoFieldByXpath('//input[@type="submit"]', t('Upload'), t('After uploading 3 files for each field, the "Upload" button is no longer displayed.'));
|
||||
|
||||
// Test clicking each "Remove" button. For extra robustness, test them out
|
||||
// of sequential order. They are 0-indexed, and get renumbered after each
|
||||
// iteration, so array(1, 1, 0) means:
|
||||
// - First remove the 2nd file.
|
||||
// - Then remove what is then the 2nd file (was originally the 3rd file).
|
||||
// - Then remove the first file.
|
||||
$num_expected_remove_buttons = 3;
|
||||
foreach (array(1, 1, 0) as $delta) {
|
||||
// Ensure we have the expected number of Remove buttons, and that they
|
||||
// are numbered sequentially.
|
||||
$buttons = $this->xpath('//input[@type="submit" and @value="Remove"]');
|
||||
$this->assertTrue(is_array($buttons) && count($buttons) === $num_expected_remove_buttons, t('There are %n "Remove" buttons displayed (JSMode=%type).', array('%n' => $num_expected_remove_buttons, '%type' => $type)));
|
||||
foreach ($buttons as $i => $button) {
|
||||
$this->assertIdentical((string) $button['name'], $field_name . '_' . LANGUAGE_NONE . '_' . $i . '_remove_button');
|
||||
}
|
||||
$num_expected_remove_buttons = 6;
|
||||
|
||||
// "Click" the remove button (emulating either a nojs or js submission).
|
||||
$button_name = $field_name . '_' . LANGUAGE_NONE . '_' . $delta . '_remove_button';
|
||||
switch ($type) {
|
||||
case 'nojs':
|
||||
// drupalPost() takes a $submit parameter that is the value of the
|
||||
// button whose click we want to emulate. Since we have multiple
|
||||
// buttons with the value "Remove", and want to control which one we
|
||||
// use, we change the value of the other ones to something else.
|
||||
// Since non-clicked buttons aren't included in the submitted POST
|
||||
// data, and since drupalPost() will result in $this being updated
|
||||
// with a newly rebuilt form, this doesn't cause problems.
|
||||
foreach ($buttons as $button) {
|
||||
if ($button['name'] != $button_name) {
|
||||
$button['value'] = 'DUMMY';
|
||||
}
|
||||
foreach (array($field_name, $field_name2) as $current_field_name) {
|
||||
// How many uploaded files for the current field are remaining.
|
||||
$remaining = 3;
|
||||
// Test clicking each "Remove" button. For extra robustness, test them out
|
||||
// of sequential order. They are 0-indexed, and get renumbered after each
|
||||
// iteration, so array(1, 1, 0) means:
|
||||
// - First remove the 2nd file.
|
||||
// - Then remove what is then the 2nd file (was originally the 3rd file).
|
||||
// - Then remove the first file.
|
||||
foreach (array(1,1,0) as $delta) {
|
||||
// Ensure we have the expected number of Remove buttons, and that they
|
||||
// are numbered sequentially.
|
||||
$buttons = $this->xpath('//input[@type="submit" and @value="Remove"]');
|
||||
$this->assertTrue(is_array($buttons) && count($buttons) === $num_expected_remove_buttons, t('There are %n "Remove" buttons displayed (JSMode=%type).', array('%n' => $num_expected_remove_buttons, '%type' => $type)));
|
||||
foreach ($buttons as $i => $button) {
|
||||
$key = $i >= $remaining ? $i - $remaining : $i;
|
||||
$check_field_name = $field_name2;
|
||||
if ($current_field_name == $field_name && $i < $remaining) {
|
||||
$check_field_name = $field_name;
|
||||
}
|
||||
$this->drupalPost(NULL, array(), t('Remove'));
|
||||
break;
|
||||
case 'js':
|
||||
// drupalPostAJAX() lets us target the button precisely, so we don't
|
||||
// require the workaround used above for nojs.
|
||||
$this->drupalPostAJAX(NULL, array(), array($button_name => t('Remove')));
|
||||
break;
|
||||
}
|
||||
$num_expected_remove_buttons--;
|
||||
|
||||
// Ensure we have a single Upload button, and that it is numbered
|
||||
// sequentially after the Remove buttons.
|
||||
$buttons = $this->xpath('//input[@type="submit" and @value="Upload"]');
|
||||
$this->assertTrue(is_array($buttons) && count($buttons) == 1 && ((string) $buttons[0]['name'] === ($field_name . '_' . LANGUAGE_NONE . '_' . $num_expected_remove_buttons . '_upload_button')), t('After removing a file, an "Upload" button is displayed (JSMode=%type).'));
|
||||
$this->assertIdentical((string) $button['name'], $check_field_name . '_' . LANGUAGE_NONE . '_' . $key. '_remove_button');
|
||||
}
|
||||
|
||||
// "Click" the remove button (emulating either a nojs or js submission).
|
||||
$button_name = $current_field_name . '_' . LANGUAGE_NONE . '_' . $delta . '_remove_button';
|
||||
switch ($type) {
|
||||
case 'nojs':
|
||||
// drupalPost() takes a $submit parameter that is the value of the
|
||||
// button whose click we want to emulate. Since we have multiple
|
||||
// buttons with the value "Remove", and want to control which one we
|
||||
// use, we change the value of the other ones to something else.
|
||||
// Since non-clicked buttons aren't included in the submitted POST
|
||||
// data, and since drupalPost() will result in $this being updated
|
||||
// with a newly rebuilt form, this doesn't cause problems.
|
||||
foreach ($buttons as $button) {
|
||||
if ($button['name'] != $button_name) {
|
||||
$button['value'] = 'DUMMY';
|
||||
}
|
||||
}
|
||||
$this->drupalPost(NULL, array(), t('Remove'));
|
||||
break;
|
||||
case 'js':
|
||||
// drupalPostAJAX() lets us target the button precisely, so we don't
|
||||
// require the workaround used above for nojs.
|
||||
$this->drupalPostAJAX(NULL, array(), array($button_name => t('Remove')));
|
||||
break;
|
||||
}
|
||||
$num_expected_remove_buttons--;
|
||||
$remaining--;
|
||||
|
||||
// Ensure an "Upload" button for the current field is displayed with the
|
||||
// correct name.
|
||||
$upload_button_name = $current_field_name . '_' . LANGUAGE_NONE . '_' . $remaining . '_upload_button';
|
||||
$buttons = $this->xpath('//input[@type="submit" and @value="Upload" and @name=:name]', array(':name' => $upload_button_name));
|
||||
$this->assertTrue(is_array($buttons) && count($buttons) == 1, t('The upload button is displayed with the correct name (JSMode=%type).', array('%type' => $type)));
|
||||
|
||||
// Ensure only at most one button per field is displayed.
|
||||
$buttons = $this->xpath('//input[@type="submit" and @value="Upload"]');
|
||||
$expected = $current_field_name == $field_name ? 1 : 2;
|
||||
$this->assertTrue(is_array($buttons) && count($buttons) == $expected, t('After removing a file, only one "Upload" button for each possible field is displayed (JSMode=%type).', array('%type' => $type)));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the page now has no Remove buttons.
|
||||
$this->assertNoFieldByXPath('//input[@type="submit"]', t('Remove'), t('After removing all files, there is no "Remove" button displayed.', array('%n' => $num_expected_remove_buttons, '%type' => $type)));
|
||||
$this->assertNoFieldByXPath('//input[@type="submit"]', t('Remove'), t('After removing all files, there is no "Remove" button displayed (JSMode=%type).', array('%type' => $type)));
|
||||
|
||||
// Save the node and ensure it does not have any files.
|
||||
$this->drupalPost(NULL, array('title' => $this->randomName()), t('Save'));
|
||||
|
|
|
@ -260,7 +260,7 @@ function filter_format_save($format) {
|
|||
$return = SAVED_UPDATED;
|
||||
|
||||
// Clear the filter cache whenever a text format is updated.
|
||||
cache_clear_all($format->format . ':', 'cache_filter', TRUE);
|
||||
cache('filter')->deletePrefix($format->format . ':');
|
||||
}
|
||||
|
||||
filter_formats_reset();
|
||||
|
@ -290,7 +290,7 @@ function filter_format_disable($format) {
|
|||
|
||||
// Clear the filter cache whenever a text format is disabled.
|
||||
filter_formats_reset();
|
||||
cache_clear_all($format->format . ':', 'cache_filter', TRUE);
|
||||
cache('filter')->deletePrefix($format->format . ':');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -395,7 +395,7 @@ function filter_formats($account = NULL) {
|
|||
|
||||
// All available formats are cached for performance.
|
||||
if (!isset($formats['all'])) {
|
||||
if ($cache = cache_get("filter_formats:{$language->language}")) {
|
||||
if ($cache = cache()->get("filter_formats:{$language->language}")) {
|
||||
$formats['all'] = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -407,7 +407,7 @@ function filter_formats($account = NULL) {
|
|||
->execute()
|
||||
->fetchAllAssoc('format');
|
||||
|
||||
cache_set("filter_formats:{$language->language}", $formats['all']);
|
||||
cache()->set("filter_formats:{$language->language}", $formats['all']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,8 +430,8 @@ function filter_formats($account = NULL) {
|
|||
* @see filter_formats()
|
||||
*/
|
||||
function filter_formats_reset() {
|
||||
cache_clear_all('filter_formats', 'cache', TRUE);
|
||||
cache_clear_all('filter_list_format', 'cache', TRUE);
|
||||
cache()->deletePrefix('filter_formats');
|
||||
cache()->deletePrefix('filter_list_format');
|
||||
drupal_static_reset('filter_list_format');
|
||||
drupal_static_reset('filter_formats');
|
||||
}
|
||||
|
@ -657,7 +657,7 @@ function filter_list_format($format_id) {
|
|||
$filter_info = filter_get_filters();
|
||||
|
||||
if (!isset($filters['all'])) {
|
||||
if ($cache = cache_get('filter_list_format')) {
|
||||
if ($cache = cache()->get('filter_list_format')) {
|
||||
$filters['all'] = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -665,7 +665,7 @@ function filter_list_format($format_id) {
|
|||
foreach ($result as $record) {
|
||||
$filters['all'][$record->format][$record->name] = $record;
|
||||
}
|
||||
cache_set('filter_list_format', $filters['all']);
|
||||
cache()->set('filter_list_format', $filters['all']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,7 +731,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
|
|||
$cache_id = '';
|
||||
if ($cache) {
|
||||
$cache_id = $format->format . ':' . $langcode . ':' . hash('sha256', $text);
|
||||
if ($cached = cache_get($cache_id, 'cache_filter')) {
|
||||
if ($cached = cache('filter')->get($cache_id)) {
|
||||
return $cached->data;
|
||||
}
|
||||
}
|
||||
|
@ -765,7 +765,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE)
|
|||
// automatically flushed when the text format is updated.
|
||||
// @see filter_format_save()
|
||||
if ($cache) {
|
||||
cache_set($cache_id, $text, 'cache_filter');
|
||||
cache('filter')->set($cache_id, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
|
@ -1079,7 +1079,7 @@ function filter_dom_serialize($dom_document) {
|
|||
foreach ($body_node->childNodes as $child_node) {
|
||||
$body_content .= $dom_document->saveXML($child_node);
|
||||
}
|
||||
return preg_replace('|<([^> ]*)/>|i', '<$1 />', $body_content);
|
||||
return $body_content;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,7 +55,7 @@ function forum_form_forum($form, &$form_state, $edit = array()) {
|
|||
|
||||
$form['vid'] = array('#type' => 'hidden', '#value' => variable_get('forum_nav_vocabulary', ''));
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit' ] = array('#type' => 'submit', '#value' => t('Save'));
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
|
||||
if ($edit['tid']) {
|
||||
$form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
|
||||
$form['tid'] = array('#type' => 'hidden', '#value' => $edit['tid']);
|
||||
|
|
|
@ -1127,7 +1127,6 @@ function template_preprocess_forum_topic_list(&$variables) {
|
|||
$variables['topics'][$id]->title = l($topic->title, "node/$topic->nid");
|
||||
$variables['topics'][$id]->message = '';
|
||||
}
|
||||
$topic->uid = $topic->last_comment_uid ? $topic->last_comment_uid : $topic->uid;
|
||||
$variables['topics'][$id]->created = theme('forum_submitted', array('topic' => $topic));
|
||||
$variables['topics'][$id]->last_reply = theme('forum_submitted', array('topic' => isset($topic->last_reply) ? $topic->last_reply : NULL));
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ function hook_image_style_delete($style) {
|
|||
*/
|
||||
function hook_image_style_flush($style) {
|
||||
// Empty cached data that contains information about the style.
|
||||
cache_clear_all('*', 'cache_mymodule', TRUE);
|
||||
cache('mymodule')->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,9 +28,6 @@ function image_uninstall() {
|
|||
function image_schema() {
|
||||
$schema = array();
|
||||
|
||||
$schema['cache_image'] = drupal_get_schema_unprocessed('system', 'cache');
|
||||
$schema['cache_image']['description'] = 'Cache table used to store information about image manipulations that are in-progress.';
|
||||
|
||||
$schema['image_styles'] = array(
|
||||
'description' => 'Stores configuration options for image styles.',
|
||||
'fields' => array(
|
||||
|
|
|
@ -258,13 +258,6 @@ function image_system_file_system_settings_submit($form, &$form_state) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_flush_caches().
|
||||
*/
|
||||
function image_flush_caches() {
|
||||
return array('cache_image');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_download().
|
||||
*
|
||||
|
@ -492,7 +485,7 @@ function image_styles() {
|
|||
|
||||
// Grab from cache or build the array.
|
||||
if (!isset($styles)) {
|
||||
if ($cache = cache_get('image_styles', 'cache')) {
|
||||
if ($cache = cache()->get('image_styles')) {
|
||||
$styles = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -534,7 +527,7 @@ function image_styles() {
|
|||
}
|
||||
|
||||
drupal_alter('image_styles', $styles);
|
||||
cache_set('image_styles', $styles);
|
||||
cache()->set('image_styles', $styles);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -827,8 +820,8 @@ function image_style_flush($style) {
|
|||
module_invoke_all('image_style_flush', $style);
|
||||
|
||||
// Clear image style and effect caches.
|
||||
cache_clear_all('image_styles', 'cache');
|
||||
cache_clear_all('image_effects:', 'cache', TRUE);
|
||||
cache()->delete('image_styles');
|
||||
cache()->deletePrefix('image_effects:');
|
||||
drupal_static_reset('image_styles');
|
||||
drupal_static_reset('image_effects');
|
||||
|
||||
|
@ -838,9 +831,9 @@ function image_style_flush($style) {
|
|||
|
||||
// Clear page caches when flushing.
|
||||
if (module_exists('block')) {
|
||||
cache_clear_all('*', 'cache_block', TRUE);
|
||||
cache('block')->flush();
|
||||
}
|
||||
cache_clear_all('*', 'cache_page', TRUE);
|
||||
cache('page')->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -952,7 +945,7 @@ function image_effect_definitions() {
|
|||
$effects = &drupal_static(__FUNCTION__);
|
||||
|
||||
if (!isset($effects)) {
|
||||
if ($cache = cache_get("image_effects:$langcode") && !empty($cache->data)) {
|
||||
if ($cache = cache()->get("image_effects:$langcode") && !empty($cache->data)) {
|
||||
$effects = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -969,7 +962,7 @@ function image_effect_definitions() {
|
|||
}
|
||||
uasort($effects, '_image_effect_definitions_sort');
|
||||
drupal_alter('image_effect_info', $effects);
|
||||
cache_set("image_effects:$langcode", $effects);
|
||||
cache()->set("image_effects:$langcode", $effects);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ function locale_languages_overview_form() {
|
|||
'#title' => t('Default language'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $options,
|
||||
'#default_value' => language_default('language'),
|
||||
'#default_value' => language_default()->language,
|
||||
);
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
|
||||
|
@ -168,7 +168,7 @@ function locale_languages_overview_form_submit($form, &$form_state) {
|
|||
drupal_set_message(t('Configuration saved.'));
|
||||
|
||||
// Changing the language settings impacts the interface.
|
||||
cache_clear_all('*', 'cache_page', TRUE);
|
||||
cache('page')->flush();
|
||||
module_invoke_all('multilingual_settings_changed');
|
||||
|
||||
$form_state['redirect'] = 'admin/config/regional/language';
|
||||
|
@ -280,7 +280,7 @@ function _locale_languages_common_controls(&$form, $language = NULL) {
|
|||
'#required' => TRUE,
|
||||
'#default_value' => @$language->language,
|
||||
'#disabled' => (isset($language->language)),
|
||||
'#description' => t('<a href="@rfc4646">RFC 4646</a> compliant language identifier. Language codes typically use a country code, and optionally, a script or regional variant name. <em>Examples: "en", "en-US" and "zh-Hant".</em>', array('@rfc4646' => 'http://www.ietf.org/rfc/rfc4646.txt')),
|
||||
'#description' => t('Use language codes as <a href="@w3ctags">defined by the W3C</a> for interoperability. <em>Examples: "en", "en-gb" and "zh-hant".</em>', array('@w3ctags' => 'http://www.w3.org/International/articles/language-tags/')),
|
||||
);
|
||||
}
|
||||
$form['name'] = array('#type' => 'textfield',
|
||||
|
@ -307,7 +307,7 @@ function _locale_languages_common_controls(&$form, $language = NULL) {
|
|||
'#title' => t('Language domain'),
|
||||
'#maxlength' => 128,
|
||||
'#default_value' => @$language->domain,
|
||||
'#description' => t('URL <strong>including protocol</strong> to use for this language, if your <em>Detection and selection</em> settings use URL domains. For the default language, this value may be left blank. <strong>Modifying this value may break existing URLs. Use with caution in a production environment.</strong> Example: Specifying "http://example.de" or "http://de.example.com" as language domains for German results in URLs like "http://example.de/contact" and "http://de.example.com/contact", respectively.'),
|
||||
'#description' => t('The domain name to use for this language if URL domains are used for <em>Detection and selection</em>. Leave blank for the default language. <strong>Changing this value may break existing URLs.</strong> Example: Specifying "de.example.com" as language domain for German will result in an URL like "http://de.example.com/contact".'),
|
||||
);
|
||||
$form['direction'] = array('#type' => 'radios',
|
||||
'#title' => t('Direction'),
|
||||
|
@ -331,8 +331,8 @@ function locale_languages_predefined_form_validate($form, &$form_state) {
|
|||
|
||||
if (!isset($form_state['values']['name'])) {
|
||||
// Predefined language selection.
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$predefined = _locale_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$predefined = standard_language_list();
|
||||
if (!isset($predefined[$langcode])) {
|
||||
form_set_error('langcode', t('Invalid language code.'));
|
||||
}
|
||||
|
@ -355,8 +355,8 @@ function locale_languages_predefined_form_submit($form, &$form_state) {
|
|||
}
|
||||
else {
|
||||
// Predefined language selection.
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$predefined = _locale_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$predefined = standard_language_list();
|
||||
locale_add_language($langcode);
|
||||
drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($predefined[$langcode][0]), '@locale-help' => url('admin/help/locale'))));
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ function locale_languages_edit_form_validate($form, &$form_state) {
|
|||
if (!empty($form_state['values']['domain']) && $duplicate = db_query("SELECT language FROM {languages} WHERE domain = :domain AND language <> :language", array(':domain' => $form_state['values']['domain'], ':language' => $form_state['values']['langcode']))->fetchField()) {
|
||||
form_set_error('domain', t('The domain (%domain) is already tied to a language (%language).', array('%domain' => $form_state['values']['domain'], '%language' => $duplicate->language)));
|
||||
}
|
||||
if (empty($form_state['values']['prefix']) && language_default('language') != $form_state['values']['langcode'] && empty($form_state['values']['domain'])) {
|
||||
if (empty($form_state['values']['prefix']) && language_default()->language != $form_state['values']['langcode'] && empty($form_state['values']['domain'])) {
|
||||
form_set_error('prefix', t('Only the default language can have both the domain and prefix empty.'));
|
||||
}
|
||||
if (!empty($form_state['values']['prefix']) && $duplicate = db_query("SELECT language FROM {languages} WHERE prefix = :prefix AND language <> :language", array(':prefix' => $form_state['values']['prefix'], ':language' => $form_state['values']['langcode']))->fetchField()) {
|
||||
|
@ -439,7 +439,7 @@ function locale_languages_delete_form($form, &$form_state, $langcode) {
|
|||
drupal_goto('admin/config/regional/language');
|
||||
}
|
||||
|
||||
if (language_default('language') == $langcode) {
|
||||
if (language_default()->language == $langcode) {
|
||||
drupal_set_message(t('The default language cannot be deleted.'));
|
||||
drupal_goto('admin/config/regional/language');
|
||||
}
|
||||
|
@ -461,37 +461,18 @@ function locale_languages_delete_form($form, &$form_state, $langcode) {
|
|||
* Process language deletion submissions.
|
||||
*/
|
||||
function locale_languages_delete_form_submit($form, &$form_state) {
|
||||
$langcode = $form_state['values']['langcode'];
|
||||
$languages = language_list();
|
||||
if (isset($languages[$form_state['values']['langcode']])) {
|
||||
// Remove translations first.
|
||||
db_delete('locales_target')
|
||||
->condition('language', $form_state['values']['langcode'])
|
||||
->execute();
|
||||
cache_clear_all('locale:' . $form_state['values']['langcode'], 'cache');
|
||||
// With no translations, this removes existing JavaScript translations file.
|
||||
_locale_rebuild_js($form_state['values']['langcode']);
|
||||
// Remove the language.
|
||||
db_delete('languages')
|
||||
->condition('language', $form_state['values']['langcode'])
|
||||
->execute();
|
||||
db_update('node')
|
||||
->fields(array('language' => ''))
|
||||
->condition('language', $form_state['values']['langcode'])
|
||||
->execute();
|
||||
if ($languages[$form_state['values']['langcode']]->enabled) {
|
||||
variable_set('language_count', variable_get('language_count', 1) - 1);
|
||||
}
|
||||
module_invoke_all('multilingual_settings_changed');
|
||||
$variables = array('%locale' => $languages[$form_state['values']['langcode']]->name);
|
||||
$language = $languages[$langcode];
|
||||
|
||||
$success = locale_language_delete($langcode);
|
||||
|
||||
if ($success) {
|
||||
$variables = array('%locale' => $language->name);
|
||||
drupal_set_message(t('The language %locale has been removed.', $variables));
|
||||
watchdog('locale', 'The language %locale has been removed.', $variables);
|
||||
}
|
||||
|
||||
// Changing the language settings impacts the interface:
|
||||
cache_clear_all('*', 'cache_page', TRUE);
|
||||
|
||||
$form_state['redirect'] = 'admin/config/regional/language';
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -154,19 +154,6 @@ function hook_language_negotiation_info_alter(array &$language_providers) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow modules to react to language settings changes.
|
||||
*
|
||||
* Every module needing to act when the number of enabled languages changes
|
||||
* should implement this. This is an "internal" hook and should not be invoked
|
||||
* elsewhere. The typical implementation would trigger some kind of rebuilding,
|
||||
* this way system components could properly react to the change of the enabled
|
||||
* languages number.
|
||||
*/
|
||||
function hook_multilingual_settings_changed() {
|
||||
field_info_cache_clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform alterations on the language fallback candidates.
|
||||
*
|
||||
|
@ -178,6 +165,20 @@ function hook_language_fallback_candidates_alter(array &$fallback_candidates) {
|
|||
$fallback_candidates = array_reverse($fallback_candidates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow modules to react before the deletion of a language.
|
||||
*
|
||||
* @param $language
|
||||
* The language object of the language that is about to be deleted.
|
||||
*/
|
||||
function hook_locale_language_delete($language) {
|
||||
// On nodes with this language, unset the language
|
||||
db_update('node')
|
||||
->fields(array('language' => ''))
|
||||
->condition('language', $language->language)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
||||
|
|
|
@ -68,8 +68,8 @@ function locale_translate_import_form_submit($form, &$form_state) {
|
|||
$languages = language_list('language');
|
||||
$langcode = $form_state['values']['langcode'];
|
||||
if (!isset($languages[$langcode])) {
|
||||
include_once DRUPAL_ROOT . '/includes/iso.inc';
|
||||
$predefined = _locale_get_predefined_list();
|
||||
include_once DRUPAL_ROOT . '/includes/standard.inc';
|
||||
$predefined = standard_language_list();
|
||||
locale_add_language($langcode);
|
||||
drupal_set_message(t('The language %language has been created.', array('%language' => t($predefined[$langcode][0]))));
|
||||
}
|
||||
|
|
|
@ -293,20 +293,6 @@ function locale_language_selector_form(&$form, &$form_state, $user) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
function locale_form_path_admin_form_alter(&$form, &$form_state) {
|
||||
$form['language'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Language'),
|
||||
'#options' => array(LANGUAGE_NONE => t('All languages')) + locale_language_list('name'),
|
||||
'#default_value' => $form['language']['#value'],
|
||||
'#weight' => -10,
|
||||
'#description' => t('A path alias set for a specific language will always be used when displaying this page in that language, and takes precedence over path aliases set for <em>All languages</em>.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
|
@ -638,7 +624,7 @@ function locale($string = NULL, $context = NULL, $langcode = NULL) {
|
|||
// perspective that is a really bad idea, so we have no user
|
||||
// interface for this. Be careful when turning this option off!
|
||||
if (variable_get('locale_cache_strings', 1) == 1) {
|
||||
if ($cache = cache_get('locale:' . $langcode, 'cache')) {
|
||||
if ($cache = cache()->get('locale:' . $langcode)) {
|
||||
$locale_t[$langcode] = $cache->data;
|
||||
}
|
||||
elseif (lock_acquire('locale_cache_' . $langcode)) {
|
||||
|
@ -649,7 +635,7 @@ function locale($string = NULL, $context = NULL, $langcode = NULL) {
|
|||
foreach ($result as $data) {
|
||||
$locale_t[$langcode][$data->context][$data->source] = (empty($data->translation) ? TRUE : $data->translation);
|
||||
}
|
||||
cache_set('locale:' . $langcode, $locale_t[$langcode]);
|
||||
cache()->set('locale:' . $langcode, $locale_t[$langcode]);
|
||||
lock_release('locale_cache_' . $langcode);
|
||||
}
|
||||
}
|
||||
|
@ -677,7 +663,7 @@ function locale($string = NULL, $context = NULL, $langcode = NULL) {
|
|||
->fields(array('version' => VERSION))
|
||||
->condition('lid', $translation->lid)
|
||||
->execute();
|
||||
cache_clear_all('locale:', 'cache', TRUE);
|
||||
cache()->deletePrefix('locale:');
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -692,7 +678,7 @@ function locale($string = NULL, $context = NULL, $langcode = NULL) {
|
|||
->execute();
|
||||
$locale_t[$langcode][$context][$string] = TRUE;
|
||||
// Clear locale cache so this string can be added in a later request.
|
||||
cache_clear_all('locale:', 'cache', TRUE);
|
||||
cache()->deletePrefix('locale:');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -778,6 +764,51 @@ function locale_language_list($field = 'name', $all = FALSE) {
|
|||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a language.
|
||||
*
|
||||
* @param $langcode
|
||||
* Language code of the language to be deleted.
|
||||
* @return
|
||||
* TRUE if language is successfully deleted. Otherwise FALSE.
|
||||
*/
|
||||
function locale_language_delete($langcode) {
|
||||
$languages = language_list();
|
||||
if (isset($languages[$langcode])) {
|
||||
$language = $languages[$langcode];
|
||||
|
||||
module_invoke_all('locale_language_delete', $language);
|
||||
|
||||
// Remove translations first.
|
||||
db_delete('locales_target')
|
||||
->condition('language', $language->language)
|
||||
->execute();
|
||||
|
||||
// Remove the language.
|
||||
db_delete('languages')
|
||||
->condition('language', $language->language)
|
||||
->execute();
|
||||
|
||||
if ($language->enabled) {
|
||||
variable_set('language_count', variable_get('language_count', 1) - 1);
|
||||
}
|
||||
|
||||
drupal_static_reset('language_list');
|
||||
_locale_invalidate_js($language->language);
|
||||
|
||||
// Changing the language settings impacts the interface:
|
||||
cache('page')->flush();
|
||||
|
||||
// Clearing all locale cache from database
|
||||
cache()->delete('locale:' . $language->language);
|
||||
|
||||
$variables = array('%locale' => $language->name);
|
||||
watchdog('locale', 'The language %locale has been removed.', $variables);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_installed().
|
||||
*/
|
||||
|
|
|
@ -410,7 +410,7 @@ function locale_translate_edit_form_submit($form, &$form_state) {
|
|||
|
||||
// Clear locale cache.
|
||||
_locale_invalidate_js();
|
||||
cache_clear_all('locale:', 'cache', TRUE);
|
||||
cache()->deletePrefix('locale:');
|
||||
|
||||
$form_state['redirect'] = 'admin/config/regional/translate/translate';
|
||||
return;
|
||||
|
@ -450,7 +450,7 @@ function locale_translate_delete_form_submit($form, &$form_state) {
|
|||
->execute();
|
||||
// Force JavaScript translation file recreation for all languages.
|
||||
_locale_invalidate_js();
|
||||
cache_clear_all('locale:', 'cache', TRUE);
|
||||
cache()->deletePrefix('locale:');
|
||||
drupal_set_message(t('The string has been removed.'));
|
||||
$form_state['redirect'] = 'admin/config/regional/translate/translate';
|
||||
}
|
||||
|
|
|
@ -290,9 +290,8 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
|
|||
$this->assertRaw(t('The language %locale has been removed.', array('%locale' => $name)), t('The test language has been removed.'));
|
||||
// Reload to remove $name.
|
||||
$this->drupalGet($path);
|
||||
$this->assertNoText($langcode, t('Language code not found.'));
|
||||
$this->assertNoText($name, t('Name not found.'));
|
||||
$this->assertNoText($native, t('Native not found.'));
|
||||
// Verify that language is no longer found.
|
||||
$this->assertResponse(404, t('Language no longer found.'));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Delete the string.
|
||||
|
@ -1900,8 +1899,8 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
|
|||
$this->assertResponse(404, "Unknown language path prefix should return 404");
|
||||
|
||||
// Setup for domain negotiation, first configure the language to have domain
|
||||
// URL.
|
||||
$edit = array('prefix' => '', 'domain' => "http://$language_domain");
|
||||
// URL. We use https and a port to make sure that only the domain name is used.
|
||||
$edit = array('prefix' => '', 'domain' => "https://$language_domain:99");
|
||||
$this->drupalPost("admin/config/regional/language/edit/$language", $edit, t('Save language'));
|
||||
// Set the site to use domain language negotiation.
|
||||
|
||||
|
|
|
@ -286,6 +286,7 @@ function menu_edit_item($form, &$form_state, $type, $item, $menu) {
|
|||
$form['link_path'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Path'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $path,
|
||||
'#description' => t('The path for this menu link. This can be an internal Drupal path such as %add-node or an external URL such as %drupal. Enter %front to link to the front page.', array('%front' => '<front>', '%add-node' => 'node/add', '%drupal' => 'http://drupal.org')),
|
||||
'#required' => TRUE,
|
||||
|
|
|
@ -230,12 +230,12 @@ function menu_load($menu_name) {
|
|||
function menu_load_all() {
|
||||
$custom_menus = &drupal_static(__FUNCTION__);
|
||||
if (!isset($custom_menus)) {
|
||||
if ($cached = cache_get('menu_custom', 'cache_menu')) {
|
||||
if ($cached = cache('menu')->get('menu_custom')) {
|
||||
$custom_menus = $cached->data;
|
||||
}
|
||||
else {
|
||||
$custom_menus = db_query('SELECT * FROM {menu_custom}')->fetchAllAssoc('menu_name', PDO::FETCH_ASSOC);
|
||||
cache_set('menu_custom', $custom_menus, 'cache_menu');
|
||||
cache('menu')->set('menu_custom', $custom_menus);
|
||||
}
|
||||
}
|
||||
return $custom_menus;
|
||||
|
|
|
@ -121,10 +121,6 @@ function node_build_filter_query(SelectQueryInterface $query) {
|
|||
foreach ($filter_data as $index => $filter) {
|
||||
list($key, $value) = $filter;
|
||||
switch ($key) {
|
||||
case 'term':
|
||||
$alias = $query->join('taxonomy_index', 'ti', "n.nid = %alias.nid");
|
||||
$query->condition($alias . '.tid', $value);
|
||||
break;
|
||||
case 'status':
|
||||
// Note: no exploitable hole as $key/$value have already been checked when submitted
|
||||
list($key, $value) = explode('-', $value, 2);
|
||||
|
|
|
@ -6,5 +6,6 @@ core = 8.x
|
|||
files[] = node.module
|
||||
files[] = node.test
|
||||
required = TRUE
|
||||
dependencies[] = entity
|
||||
configure = admin/structure/types
|
||||
stylesheets[all][] = node.css
|
||||
|
|
|
@ -675,7 +675,7 @@ function _node_types_build($rebuild = FALSE) {
|
|||
if (isset($_node_types)) {
|
||||
return $_node_types;
|
||||
}
|
||||
if ($cache = cache_get($cid)) {
|
||||
if ($cache = cache()->get($cid)) {
|
||||
$_node_types = $cache->data;
|
||||
return $_node_types;
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ function _node_types_build($rebuild = FALSE) {
|
|||
|
||||
asort($_node_types->names);
|
||||
|
||||
cache_set($cid, $_node_types);
|
||||
cache()->set($cid, $_node_types);
|
||||
|
||||
return $_node_types;
|
||||
}
|
||||
|
@ -746,7 +746,7 @@ function _node_types_build($rebuild = FALSE) {
|
|||
* Clears the node type cache.
|
||||
*/
|
||||
function node_type_cache_reset() {
|
||||
cache_clear_all('node_types:', 'cache', TRUE);
|
||||
cache()->deletePrefix('node_types:');
|
||||
drupal_static_reset('_node_types_build');
|
||||
}
|
||||
|
||||
|
@ -2452,7 +2452,7 @@ function node_feed($nids = FALSE, $channel = array()) {
|
|||
$nids = db_select('node', 'n')
|
||||
->fields('n', array('nid', 'created'))
|
||||
->condition('n.promote', 1)
|
||||
->condition('status', 1)
|
||||
->condition('n.status', 1)
|
||||
->orderBy('n.created', 'DESC')
|
||||
->range(0, variable_get('feed_default_items', 10))
|
||||
->addTag('node_access')
|
||||
|
@ -2833,8 +2833,6 @@ function node_search_validate($form, &$form_state) {
|
|||
* TRUE if the operation may be performed, FALSE otherwise.
|
||||
*/
|
||||
function node_access($op, $node, $account = NULL) {
|
||||
global $user;
|
||||
|
||||
$rights = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
|
||||
|
@ -2844,7 +2842,7 @@ function node_access($op, $node, $account = NULL) {
|
|||
}
|
||||
// If no user object is supplied, the access check is for the current user.
|
||||
if (empty($account)) {
|
||||
$account = $user;
|
||||
$account = $GLOBALS['user'];
|
||||
}
|
||||
|
||||
// $node may be either an object or a node type. Since node types cannot be
|
||||
|
@ -3948,3 +3946,14 @@ function node_file_download_access($field, $entity_type, $entity) {
|
|||
return node_access('view', $entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_locale_language_delete().
|
||||
*/
|
||||
function node_locale_language_delete($language) {
|
||||
// On nodes with this language, unset the language
|
||||
db_update('node')
|
||||
->fields(array('language' => ''))
|
||||
->condition('language', $language->language)
|
||||
->execute();
|
||||
}
|
||||
|
|
|
@ -2261,6 +2261,7 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
|
|||
$tests['[node:language]'] = check_plain($node->language);
|
||||
$tests['[node:url]'] = url('node/' . $node->nid, $url_options);
|
||||
$tests['[node:edit-url]'] = url('node/' . $node->nid . '/edit', $url_options);
|
||||
$tests['[node:author]'] = check_plain(format_username($account));
|
||||
$tests['[node:author:uid]'] = $node->uid;
|
||||
$tests['[node:author:name]'] = check_plain(format_username($account));
|
||||
$tests['[node:created:since]'] = format_interval(REQUEST_TIME - $node->created, 2, $language->language);
|
||||
|
|
|
@ -157,8 +157,9 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr
|
|||
|
||||
// Default values for the chained tokens handled below.
|
||||
case 'author':
|
||||
$name = ($node->uid == 0) ? variable_get('anonymous', t('Anonymous')) : $node->name;
|
||||
$replacements[$original] = $sanitize ? filter_xss($name) : $name;
|
||||
$account = user_load($node->uid);
|
||||
$name = format_username($account);
|
||||
$replacements[$original] = $sanitize ? check_plain($name) : $name;
|
||||
break;
|
||||
|
||||
case 'created':
|
||||
|
|
|
@ -49,8 +49,13 @@ function hook_openid_response($response, $account) {
|
|||
* Allow modules to declare OpenID discovery methods.
|
||||
*
|
||||
* The discovery function callbacks will be called in turn with an unique
|
||||
* parameter, the claimed identifier. They have to return an array of services,
|
||||
* in the same form returned by openid_discover().
|
||||
* parameter, the claimed identifier. They have to return an associative array
|
||||
* with array of services and claimed identifier in the same form as returned by
|
||||
* openid_discover(). The resulting array must contain following keys:
|
||||
* - 'services' (required) an array of discovered services (including OpenID
|
||||
* version, endpoint URI, etc).
|
||||
* - 'claimed_id' (optional) new claimed identifer, found by following HTTP
|
||||
* redirects during the services discovery.
|
||||
*
|
||||
* The first discovery method that succeed (return at least one services) will
|
||||
* stop the discovery process.
|
||||
|
@ -58,6 +63,7 @@ function hook_openid_response($response, $account) {
|
|||
* @return
|
||||
* An associative array which keys are the name of the discovery methods and
|
||||
* values are function callbacks.
|
||||
*
|
||||
* @see hook_openid_discovery_method_info_alter()
|
||||
*/
|
||||
function hook_openid_discovery_method_info() {
|
||||
|
|
|
@ -11,10 +11,10 @@ Drupal.behaviors.openid = {
|
|||
if (cookie) {
|
||||
$('#edit-openid-identifier').val(cookie);
|
||||
}
|
||||
if ($('#edit-openid-identifier').val()) {
|
||||
if ($('#edit-openid-identifier').val() || location.hash == '#openid-login') {
|
||||
$('#edit-openid-identifier').addClass('openid-processed');
|
||||
loginElements.hide();
|
||||
// Use .css('display', 'block') instead of .show() to Konqueror friendly.
|
||||
// Use .css('display', 'block') instead of .show() to be Konqueror friendly.
|
||||
openidElements.css('display', 'block');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,11 +146,11 @@ function _openid_user_login_form_alter(&$form, &$form_state) {
|
|||
|
||||
$items = array();
|
||||
$items[] = array(
|
||||
'data' => l(t('Log in using OpenID'), '#'),
|
||||
'data' => l(t('Log in using OpenID'), '#openid-login', array('external' => TRUE)),
|
||||
'class' => array('openid-link'),
|
||||
);
|
||||
$items[] = array(
|
||||
'data' => l(t('Cancel OpenID login'), '#'),
|
||||
'data' => l(t('Cancel OpenID login'), '#', array('external' => TRUE)),
|
||||
'class' => array('user-link'),
|
||||
);
|
||||
|
||||
|
@ -256,16 +256,25 @@ function openid_login_validate($form, &$form_state) {
|
|||
function openid_begin($claimed_id, $return_to = '', $form_values = array()) {
|
||||
module_load_include('inc', 'openid');
|
||||
|
||||
$service = NULL;
|
||||
$claimed_id = openid_normalize($claimed_id);
|
||||
$discovery = openid_discovery($claimed_id);
|
||||
|
||||
$services = openid_discovery($claimed_id);
|
||||
$service = _openid_select_service($services);
|
||||
if (!empty($discovery['services'])) {
|
||||
$service = _openid_select_service($discovery['services']);
|
||||
}
|
||||
|
||||
if (!$service) {
|
||||
// Quit if the discovery result was empty or if we can't select any service.
|
||||
if (!$discovery || !$service) {
|
||||
form_set_error('openid_identifier', t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set claimed id from discovery.
|
||||
if (!empty($discovery['claimed_id'])) {
|
||||
$claimed_id = $discovery['claimed_id'];
|
||||
}
|
||||
|
||||
// Store discovered information in the users' session so we don't have to rediscover.
|
||||
$_SESSION['openid']['service'] = $service;
|
||||
// Store the claimed id
|
||||
|
@ -352,11 +361,13 @@ function openid_complete($response = array()) {
|
|||
// identififer to make sure that the provider is authorized to
|
||||
// respond on behalf of this.
|
||||
if ($response_claimed_id != $claimed_id) {
|
||||
$services = openid_discovery($response_claimed_id);
|
||||
$uris = array();
|
||||
foreach ($services as $discovered_service) {
|
||||
if (in_array('http://specs.openid.net/auth/2.0/server', $discovered_service['types']) || in_array('http://specs.openid.net/auth/2.0/signon', $discovered_service['types'])) {
|
||||
$uris[] = $discovered_service['uri'];
|
||||
$discovery = openid_discovery($response['openid.claimed_id']);
|
||||
if ($discovery && !empty($discovery['services'])) {
|
||||
$uris = array();
|
||||
foreach ($discovery['services'] as $discovered_service) {
|
||||
if (in_array('http://specs.openid.net/auth/2.0/server', $discovered_service['types']) || in_array('http://specs.openid.net/auth/2.0/signon', $discovered_service['types'])) {
|
||||
$uris[] = $discovered_service['uri'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!in_array($service['uri'], $uris)) {
|
||||
|
@ -378,10 +389,21 @@ function openid_complete($response = array()) {
|
|||
/**
|
||||
* Perform discovery on a claimed ID to determine the OpenID provider endpoint.
|
||||
*
|
||||
* @param $claimed_id The OpenID URL to perform discovery on.
|
||||
* Discovery methods are provided by the hook_openid_discovery_method_info and
|
||||
* could be further altered using the hook_openid_discovery_method_info_alter.
|
||||
*
|
||||
* @return Array of services discovered (including OpenID version, endpoint
|
||||
* URI, etc).
|
||||
* @param $claimed_id
|
||||
* The OpenID URL to perform discovery on.
|
||||
*
|
||||
* @return
|
||||
* The resulting discovery array from the first successful discovery method,
|
||||
* which must contain following keys:
|
||||
* - 'services' (required) an array of discovered services (including OpenID
|
||||
* version, endpoint URI, etc).
|
||||
* - 'claimed_id' (optional) new claimed identifer, found by following HTTP
|
||||
* redirects during the services discovery.
|
||||
* If all the discovery method fails or if no appropriate discovery method is
|
||||
* found, FALSE is returned.
|
||||
*/
|
||||
function openid_discovery($claimed_id) {
|
||||
module_load_include('inc', 'openid');
|
||||
|
@ -389,15 +411,15 @@ function openid_discovery($claimed_id) {
|
|||
$methods = module_invoke_all('openid_discovery_method_info');
|
||||
drupal_alter('openid_discovery_method_info', $methods);
|
||||
|
||||
// Execute each method in turn.
|
||||
// Execute each method in turn and return first successful discovery.
|
||||
foreach ($methods as $method) {
|
||||
$discovered_services = $method($claimed_id);
|
||||
if (!empty($discovered_services)) {
|
||||
return $discovered_services;
|
||||
$discovery = $method($claimed_id);
|
||||
if (!empty($discovery)) {
|
||||
return $discovery;
|
||||
}
|
||||
}
|
||||
|
||||
return array();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -421,24 +443,33 @@ function openid_openid_discovery_method_info() {
|
|||
*
|
||||
* @see http://openid.net/specs/openid-authentication-2_0.html#discovery
|
||||
* @see hook_openid_discovery_method_info()
|
||||
* @see openid_discovery()
|
||||
*
|
||||
* @return
|
||||
* An array of discovered services and claimed identifier or NULL. See
|
||||
* openid_discovery() for more specific information.
|
||||
*/
|
||||
function _openid_xri_discovery($claimed_id) {
|
||||
if (_openid_is_xri($claimed_id)) {
|
||||
// Resolve XRI using a proxy resolver (Extensible Resource Identifier (XRI)
|
||||
// Resolution Version 2.0, section 11.2 and 14.3).
|
||||
$xrds_url = variable_get('xri_proxy_resolver', 'http://xri.net/') . rawurlencode($claimed_id) . '?_xrd_r=application/xrds+xml';
|
||||
$services = _openid_xrds_discovery($xrds_url);
|
||||
foreach ($services as $i => &$service) {
|
||||
$status = $service['xrd']->children(OPENID_NS_XRD)->Status;
|
||||
if ($status && $status->attributes()->cid == 'verified') {
|
||||
$service['claimed_id'] = openid_normalize((string)$service['xrd']->children(OPENID_NS_XRD)->CanonicalID);
|
||||
$discovery = _openid_xrds_discovery($xrds_url);
|
||||
if (!empty($discovery['services']) && is_array($discovery['services'])) {
|
||||
foreach ($discovery['services'] as $i => &$service) {
|
||||
$status = $service['xrd']->children(OPENID_NS_XRD)->Status;
|
||||
if ($status && $status->attributes()->cid == 'verified') {
|
||||
$service['claimed_id'] = openid_normalize((string)$service['xrd']->children(OPENID_NS_XRD)->CanonicalID);
|
||||
}
|
||||
else {
|
||||
// Ignore service if the Canonical ID could not be verified.
|
||||
unset($discovery['services'][$i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Ignore service if CanonicalID could not be verified.
|
||||
unset($services[$i]);
|
||||
if (!empty($discovery['services'])) {
|
||||
return $discovery;
|
||||
}
|
||||
}
|
||||
return $services;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,6 +478,11 @@ function _openid_xri_discovery($claimed_id) {
|
|||
*
|
||||
* @see http://openid.net/specs/openid-authentication-2_0.html#discovery
|
||||
* @see hook_openid_discovery_method_info()
|
||||
* @see openid_discovery()
|
||||
*
|
||||
* @return
|
||||
* An array of discovered services and claimed identifier or NULL. See
|
||||
* openid_discovery() for more specific information.
|
||||
*/
|
||||
function _openid_xrds_discovery($claimed_id) {
|
||||
$services = array();
|
||||
|
@ -458,7 +494,18 @@ function _openid_xrds_discovery($claimed_id) {
|
|||
$headers = array('Accept' => 'application/xrds+xml');
|
||||
$result = drupal_http_request($xrds_url, array('headers' => $headers));
|
||||
|
||||
if (!isset($result->error)) {
|
||||
// Check for HTTP error and make sure, that we reach the target. If the
|
||||
// maximum allowed redirects are exhausted, final destination URL isn't
|
||||
// reached, but drupal_http_request() doesn't return any error.
|
||||
// @todo Remove the check for 200 HTTP result code after the following issue
|
||||
// will be fixed: http://drupal.org/node/1096890.
|
||||
if (!isset($result->error) && $result->code == 200) {
|
||||
|
||||
// Replace the user-entered claimed_id if we received a redirect.
|
||||
if (!empty($result->redirect_url)) {
|
||||
$claimed_id = openid_normalize($result->redirect_url);
|
||||
}
|
||||
|
||||
if (isset($result->headers['content-type']) && preg_match("/application\/xrds\+xml/", $result->headers['content-type'])) {
|
||||
// Parse XML document to find URL
|
||||
$services = _openid_xrds_parse($result->data);
|
||||
|
@ -504,7 +551,13 @@ function _openid_xrds_discovery($claimed_id) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return $services;
|
||||
|
||||
if (!empty($services)) {
|
||||
return array(
|
||||
'services' => $services,
|
||||
'claimed_id' => $claimed_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue