2001-12-01 15:20:48 +00:00
< ? php
2014-02-27 04:48:12 +00:00
use Drupal\Component\Utility\Crypt ;
2013-06-27 21:04:31 +00:00
use Drupal\Component\Utility\Json ;
2013-10-16 11:04:31 +00:00
use Drupal\Component\Utility\Number ;
2013-09-06 17:52:42 +00:00
use Drupal\Component\Utility\Settings ;
2013-08-05 22:24:38 +00:00
use Drupal\Component\Utility\SortArray ;
2013-05-28 21:48:53 +00:00
use Drupal\Component\Utility\String ;
2013-06-14 22:11:48 +00:00
use Drupal\Component\Utility\Tags ;
2014-03-05 20:22:39 +00:00
use Drupal\Component\Utility\UrlHelper ;
2013-05-28 21:48:53 +00:00
use Drupal\Component\Utility\Xss ;
2013-03-22 09:36:55 +00:00
use Drupal\Core\Cache\Cache ;
2013-05-25 20:12:45 +00:00
use Drupal\Core\Language\Language ;
2013-06-06 08:21:58 +00:00
use Symfony\Component\HttpFoundation\Response ;
use Symfony\Component\HttpFoundation\Request ;
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
use Symfony\Component\Yaml\Parser ;
use Symfony\Component\Yaml\Exception\ParseException ;
2012-11-22 10:53:19 +00:00
use Drupal\Component\PhpStorage\PhpStorageFactory ;
2012-09-22 17:24:46 +00:00
use Drupal\Component\Utility\NestedArray ;
2012-11-06 09:45:17 +00:00
use Drupal\Core\Datetime\DrupalDateTime ;
2013-06-06 08:14:16 +00:00
use Drupal\Core\Routing\GeneratorNotInitializedException ;
2012-08-03 15:31:18 +00:00
use Drupal\Core\Template\Attribute ;
2013-12-10 21:23:03 +00:00
use Drupal\Core\Render\Element ;
2011-12-27 21:17:19 +00:00
2004-07-13 07:21:14 +00:00
/**
* @ file
* Common functions that many Drupal modules will need to reference .
*
* The functions that are critical and need to be available even when serving
* a cached page are instead located in bootstrap . inc .
*/
2009-09-28 22:22:54 +00:00
/**
* @ defgroup php_wrappers PHP wrapper functions
* @ {
* Functions that are wrappers or custom implementations of PHP functions .
*
* Certain PHP functions should not be used in Drupal . Instead , Drupal ' s
* replacement functions should be used .
*
* For example , for improved or more secure UTF8 - handling , or RFC - compliant
* handling of URLs in Drupal .
*
* For ease of use and memorizing , all these wrapper functions use the same name
* as the original PHP function , but prefixed with " drupal_ " . Beware , however ,
* that not all wrapper functions support the same arguments as the original
* functions .
*
* You should always use these wrapper functions in your code .
*
* Wrong :
* @ code
* $my_substring = substr ( $original_string , 0 , 5 );
* @ endcode
*
* Correct :
* @ code
* $my_substring = drupal_substr ( $original_string , 0 , 5 );
* @ endcode
*
2010-12-15 03:00:40 +00:00
* @ }
2009-09-28 22:22:54 +00:00
*/
2005-05-07 01:48:06 +00:00
/**
* Return status for saving which involved creating a new item .
*/
2011-11-29 09:56:53 +00:00
const SAVED_NEW = 1 ;
2005-05-07 01:48:06 +00:00
/**
* Return status for saving which involved an update to an existing item .
*/
2011-11-29 09:56:53 +00:00
const SAVED_UPDATED = 2 ;
2005-05-07 01:48:06 +00:00
/**
* Return status for saving which deleted an existing item .
*/
2011-11-29 09:56:53 +00:00
const SAVED_DELETED = 3 ;
2005-05-07 01:48:06 +00:00
2009-07-30 19:57:10 +00:00
/**
2013-04-04 02:14:52 +00:00
* The default aggregation group for CSS files added to the page .
2009-07-30 19:57:10 +00:00
*/
2013-04-04 02:14:52 +00:00
const CSS_AGGREGATE_DEFAULT = 0 ;
2009-07-30 19:57:10 +00:00
/**
2013-04-04 02:14:52 +00:00
* The default aggregation group for theme CSS files added to the page .
2009-07-30 19:57:10 +00:00
*/
2013-04-04 02:14:52 +00:00
const CSS_AGGREGATE_THEME = 100 ;
/**
* The default weight for CSS rules that style HTML elements ( " base " styles ) .
*/
const CSS_BASE = - 200 ;
/**
* The default weight for CSS rules that layout a page .
*/
const CSS_LAYOUT = - 100 ;
/**
2014-03-04 18:04:01 +00:00
* The default weight for CSS rules that style design components ( and their associated states and themes . )
2013-04-04 02:14:52 +00:00
*/
const CSS_COMPONENT = 0 ;
/**
* The default weight for CSS rules that style states and are not included with components .
*/
const CSS_STATE = 100 ;
/**
2014-03-04 18:04:01 +00:00
* The default weight for CSS rules that style themes and are not included with components .
2013-04-04 02:14:52 +00:00
*/
2014-03-04 18:04:01 +00:00
const CSS_THEME = 200 ;
2009-07-30 19:57:10 +00:00
2012-09-24 13:12:09 +00:00
/**
* The default group for JavaScript settings added to the page .
*/
const JS_SETTING = - 200 ;
2008-11-10 05:23:01 +00:00
/**
2011-12-05 12:52:27 +00:00
* The default group for JavaScript and jQuery libraries added to the page .
2008-11-10 05:23:01 +00:00
*/
2011-11-29 09:56:53 +00:00
const JS_LIBRARY = - 100 ;
2008-11-10 05:23:01 +00:00
/**
2010-10-05 19:59:10 +00:00
* The default group for module JavaScript code added to the page .
2008-11-10 05:23:01 +00:00
*/
2011-11-29 09:56:53 +00:00
const JS_DEFAULT = 0 ;
2008-11-10 05:23:01 +00:00
/**
2010-10-05 19:59:10 +00:00
* The default group for theme JavaScript code added to the page .
2008-11-10 05:23:01 +00:00
*/
2011-11-29 09:56:53 +00:00
const JS_THEME = 100 ;
2008-11-10 05:23:01 +00:00
2012-03-11 02:35:21 +00:00
/**
* The delimiter used to split plural strings .
*
* This is the ETX ( End of text ) character and is used as a minimal means to
* separate singular and plural variants in source and translation text . It
* was found to be the most compatible delimiter for the supported databases .
*/
const LOCALE_PLURAL_DELIMITER = " \03 " ;
2005-08-16 18:06:18 +00:00
/**
2011-12-05 12:52:27 +00:00
* Adds content to a specified region .
2005-08-16 18:06:18 +00:00
*
* @ param $region
2009-05-21 21:12:25 +00:00
* Page region the content is added to .
2005-08-16 18:06:18 +00:00
* @ param $data
2009-05-21 21:12:25 +00:00
* Content to be added .
2005-08-16 18:06:18 +00:00
*/
2009-05-21 21:12:25 +00:00
function drupal_add_region_content ( $region = NULL , $data = NULL ) {
2005-08-16 18:06:18 +00:00
static $content = array ();
2010-09-24 02:48:35 +00:00
if ( isset ( $region ) && isset ( $data )) {
2005-08-16 18:06:18 +00:00
$content [ $region ][] = $data ;
}
return $content ;
}
/**
2011-12-05 12:52:27 +00:00
* Gets assigned content for a given region .
2005-08-16 18:06:18 +00:00
*
* @ param $region
2007-10-08 14:08:19 +00:00
* A specified region to fetch content for . If NULL , all regions will be
* returned .
2005-08-16 18:06:18 +00:00
* @ param $delimiter
2009-07-30 10:54:41 +00:00
* Content to be inserted between imploded array elements .
2005-08-16 18:06:18 +00:00
*/
2009-05-21 21:12:25 +00:00
function drupal_get_region_content ( $region = NULL , $delimiter = ' ' ) {
$content = drupal_add_region_content ();
2005-10-23 09:47:53 +00:00
if ( isset ( $region )) {
if ( isset ( $content [ $region ]) && is_array ( $content [ $region ])) {
2005-12-17 10:35:59 +00:00
return implode ( $delimiter , $content [ $region ]);
2005-10-23 09:47:53 +00:00
}
2005-08-16 18:06:18 +00:00
}
else {
foreach ( array_keys ( $content ) as $region ) {
if ( is_array ( $content [ $region ])) {
2005-12-17 10:35:59 +00:00
$content [ $region ] = implode ( $delimiter , $content [ $region ]);
2005-08-16 18:06:18 +00:00
}
}
return $content ;
}
}
2009-08-21 07:50:08 +00:00
/**
2012-10-05 16:11:15 +00:00
* Gets the name of the currently active installation profile .
2009-08-21 07:50:08 +00:00
*
* When this function is called during Drupal ' s initial installation process ,
* the name of the profile that ' s about to be installed is stored in the global
2013-10-15 17:05:45 +00:00
* installation state . At all other times , the " install_profile " setting will be
* available in settings . php .
2009-08-21 07:50:08 +00:00
*
* @ return $profile
2012-10-05 16:11:15 +00:00
* The name of the installation profile .
2009-08-21 07:50:08 +00:00
*/
function drupal_get_profile () {
global $install_state ;
2013-09-06 17:52:42 +00:00
if ( drupal_installation_attempted ()) {
// If the profile has been selected return it.
if ( isset ( $install_state [ 'parameters' ][ 'profile' ])) {
$profile = $install_state [ 'parameters' ][ 'profile' ];
}
else {
$profile = '' ;
}
2009-08-21 07:50:08 +00:00
}
else {
2014-03-24 08:51:28 +00:00
$profile = Settings :: get ( 'install_profile' ) ? : 'standard' ;
2009-08-21 07:50:08 +00:00
}
return $profile ;
}
2004-01-14 22:30:09 +00:00
/**
2011-12-05 12:52:27 +00:00
* Adds output to the HEAD tag of the HTML page .
2007-10-12 14:10:18 +00:00
*
2011-10-27 17:34:00 +00:00
* This function can be called as long as the headers aren ' t sent . Pass no
2009-11-03 06:47:23 +00:00
* arguments ( or NULL for both ) to retrieve the currently stored elements .
*
* @ param $data
* A renderable array . If the '#type' key is not set then 'html_tag' will be
* added as the default '#type' .
* @ param $key
* A unique string key to allow implementations of hook_html_head_alter () to
* identify the element in $data . Required if $data is not NULL .
*
* @ return
* An array of all stored HEAD elements .
*
2013-06-09 20:54:08 +00:00
* @ see drupal_pre_render_html_tag ()
2004-01-14 22:30:09 +00:00
*/
2009-11-03 06:47:23 +00:00
function drupal_add_html_head ( $data = NULL , $key = NULL ) {
$stored_head = & drupal_static ( __FUNCTION__ );
2004-01-14 22:30:09 +00:00
2009-11-03 06:47:23 +00:00
if ( ! isset ( $stored_head )) {
// Make sure the defaults, including Content-Type, come first.
$stored_head = _drupal_default_html_head ();
}
if ( isset ( $data ) && isset ( $key )) {
if ( ! isset ( $data [ '#type' ])) {
$data [ '#type' ] = 'html_tag' ;
}
$stored_head [ $key ] = $data ;
2004-01-14 22:30:09 +00:00
}
return $stored_head ;
}
2004-09-09 05:51:08 +00:00
/**
2009-11-03 06:47:23 +00:00
* Returns elements that are always displayed in the HEAD tag of the HTML page .
*/
function _drupal_default_html_head () {
// Add default elements. Make sure the Content-Type comes first because the
// IE browser may be vulnerable to XSS via encoding attacks from any content
// that comes before this META tag, such as a TITLE tag.
$elements [ 'system_meta_content_type' ] = array (
'#type' => 'html_tag' ,
'#tag' => 'meta' ,
'#attributes' => array (
2011-11-18 15:06:47 +00:00
'charset' => 'utf-8' ,
2009-11-03 06:47:23 +00:00
),
// Security: This always has to be output first.
'#weight' => - 1000 ,
);
// Show Drupal and the major version number in the META GENERATOR tag.
// Get the major version.
2013-09-16 03:58:06 +00:00
list ( $version , ) = explode ( '.' , \Drupal :: VERSION );
2009-11-03 06:47:23 +00:00
$elements [ 'system_meta_generator' ] = array (
'#type' => 'html_tag' ,
'#tag' => 'meta' ,
'#attributes' => array (
'name' => 'Generator' ,
'content' => 'Drupal ' . $version . ' (http://drupal.org)' ,
),
);
// Also send the generator in the HTTP header.
$elements [ 'system_meta_generator' ][ '#attached' ][ 'drupal_add_http_header' ][] = array ( 'X-Generator' , $elements [ 'system_meta_generator' ][ '#attributes' ][ 'content' ]);
return $elements ;
}
/**
2011-12-05 12:52:27 +00:00
* Retrieves output to be displayed in the HEAD tag of the HTML page .
2014-01-01 20:32:52 +00:00
*/
2004-01-14 22:30:09 +00:00
function drupal_get_html_head () {
2009-11-03 06:47:23 +00:00
$elements = drupal_add_html_head ();
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'html_head' , $elements );
2009-11-03 06:47:23 +00:00
return drupal_render ( $elements );
2004-01-14 22:30:09 +00:00
}
2006-12-05 05:45:05 +00:00
/**
2011-12-05 12:52:27 +00:00
* Adds a feed URL for the current page .
2006-08-23 05:55:38 +00:00
*
2008-09-18 10:40:28 +00:00
* This function can be called as long the HTML header hasn ' t been sent .
*
2006-08-23 05:55:38 +00:00
* @ param $url
2010-11-29 04:53:32 +00:00
* An internal system path or a fully qualified external URL of the feed .
2006-08-23 07:23:09 +00:00
* @ param $title
2007-10-08 14:08:19 +00:00
* The title of the feed .
2006-08-23 05:55:38 +00:00
*/
2006-08-23 07:23:09 +00:00
function drupal_add_feed ( $url = NULL , $title = '' ) {
2009-05-31 07:00:12 +00:00
$stored_feed_links = & drupal_static ( __FUNCTION__ , array ());
2006-08-23 05:55:38 +00:00
2009-11-03 06:47:23 +00:00
if ( isset ( $url )) {
2014-02-04 13:13:54 +00:00
$feed_icon = array (
'#theme' => 'feed_icon' ,
'#url' => $url ,
'#title' => $title ,
);
2006-08-23 07:23:09 +00:00
2014-02-04 13:13:54 +00:00
$feed_icon [ '#attached' ][ 'drupal_add_html_head_link' ][][] = array (
2010-11-29 04:53:32 +00:00
'rel' => 'alternate' ,
'type' => 'application/rss+xml' ,
'title' => $title ,
// Force the URL to be absolute, for consistency with other <link> tags
// output by Drupal.
'href' => url ( $url , array ( 'absolute' => TRUE )),
2013-11-21 10:05:28 +00:00
);
2014-02-04 13:13:54 +00:00
$stored_feed_links [ $url ] = drupal_render ( $feed_icon );
2006-08-23 05:55:38 +00:00
}
return $stored_feed_links ;
}
/**
2011-12-05 12:52:27 +00:00
* Gets the feed URLs for the current page .
2006-08-23 05:55:38 +00:00
*
* @ param $delimiter
2007-10-08 14:08:19 +00:00
* A delimiter to split feeds by .
2006-08-23 05:55:38 +00:00
*/
function drupal_get_feeds ( $delimiter = " \n " ) {
$feeds = drupal_add_feed ();
return implode ( $feeds , $delimiter );
}
2004-02-08 17:12:44 +00:00
/**
2010-10-08 05:07:53 +00:00
* @ defgroup http_handling HTTP handling
2004-02-08 17:12:44 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Functions to properly handle HTTP responses .
2004-02-08 17:12:44 +00:00
*/
2006-04-13 08:25:27 +00:00
/**
2011-12-05 12:52:27 +00:00
* Processes a URL query parameter array to remove unwanted elements .
2006-04-13 08:25:27 +00:00
*
* @ param $query
2013-12-05 18:02:36 +00:00
* ( optional ) An array to be processed . Defaults to \Drupal :: request () -> query
* parameters .
2006-04-13 08:25:27 +00:00
* @ param $exclude
2009-09-29 15:31:17 +00:00
* ( optional ) A list of $query array keys to remove . Use " parent[child] " to
2012-04-29 15:16:27 +00:00
* exclude nested items .
2006-04-13 08:25:27 +00:00
* @ param $parent
2009-09-29 15:31:17 +00:00
* Internal use only . Used to build the $query array key for nested items .
*
2006-04-13 08:25:27 +00:00
* @ return
2009-09-29 15:31:17 +00:00
* An array containing query parameters , which can be used for url () .
2013-06-29 23:09:39 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
2014-03-05 20:22:39 +00:00
* Use \Drupal\Component\Utility\UrlHelper :: filterQueryParameters () .
2006-04-13 08:25:27 +00:00
*/
2012-04-29 15:16:27 +00:00
function drupal_get_query_parameters ( array $query = NULL , array $exclude = array (), $parent = '' ) {
2009-09-29 15:31:17 +00:00
if ( ! isset ( $query )) {
2013-09-16 03:58:06 +00:00
$query = \Drupal :: request () -> query -> all ();
2009-10-09 16:33:14 +00:00
}
2014-03-05 20:22:39 +00:00
return UrlHelper :: filterQueryParameters ( $query , $exclude , $parent );
2009-10-09 16:33:14 +00:00
}
2009-09-29 15:31:17 +00:00
/**
2011-12-05 12:52:27 +00:00
* Parses an array into a valid , rawurlencoded query string .
2009-09-29 15:31:17 +00:00
*
* @ see drupal_get_query_parameters ()
* @ ingroup php_wrappers
2013-06-29 23:09:39 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
2014-03-05 20:22:39 +00:00
* Use \Drupal\Component\Utility\UrlHelper :: buildQuery () .
2009-09-29 15:31:17 +00:00
*/
function drupal_http_build_query ( array $query , $parent = '' ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: buildQuery ( $query , $parent );
2006-04-13 08:25:27 +00:00
}
2005-02-01 19:45:58 +00:00
/**
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
* Prepares a 'destination' URL query parameter for use with url () .
2007-10-12 14:10:18 +00:00
*
2007-10-08 14:08:19 +00:00
* Used to direct the user back to the referring page after completing a form .
* By default the current URL is returned . If a destination exists in the
* previous request , that destination is returned . As such , a destination can
* persist across multiple pages .
2005-02-01 19:45:58 +00:00
*
2012-08-23 14:36:36 +00:00
* @ return
* An associative array containing the key :
* - destination : The path provided via the destination query string or , if
* not available , the current path .
*
* @ see current_path ()
2005-02-01 19:45:58 +00:00
*/
function drupal_get_destination () {
2009-09-29 15:31:17 +00:00
$destination = & drupal_static ( __FUNCTION__ );
if ( isset ( $destination )) {
return $destination ;
}
2013-09-16 03:58:06 +00:00
$query = \Drupal :: request () -> query ;
2013-06-29 23:09:39 +00:00
if ( $query -> has ( 'destination' )) {
$destination = array ( 'destination' => $query -> get ( 'destination' ));
2005-07-20 10:48:20 +00:00
}
else {
2012-04-29 15:16:27 +00:00
$path = current_path ();
2014-03-05 20:22:39 +00:00
$query = UrlHelper :: buildQuery ( UrlHelper :: filterQueryParameters ( $query -> all ()));
2006-04-13 08:25:27 +00:00
if ( $query != '' ) {
2008-04-14 17:48:46 +00:00
$path .= '?' . $query ;
2006-02-27 14:06:09 +00:00
}
2009-09-29 15:31:17 +00:00
$destination = array ( 'destination' => $path );
}
return $destination ;
}
/**
2011-12-05 12:52:27 +00:00
* Parses a system URL string into an associative array suitable for url () .
2009-10-11 02:14:43 +00:00
*
* This function should only be used for URLs that have been generated by the
2012-03-30 00:38:24 +00:00
* system , such as via url () . It should not be used for URLs that come from
* external sources , or URLs that link to external resources .
2009-09-29 15:31:17 +00:00
*
* The returned array contains a 'path' that may be passed separately to url () .
* For example :
* @ code
2013-12-05 18:02:36 +00:00
* $options = drupal_parse_url ( \Drupal :: request () -> query -> get ( 'destination' ));
2009-09-29 15:31:17 +00:00
* $my_url = url ( $options [ 'path' ], $options );
* $my_link = l ( 'Example link' , $options [ 'path' ], $options );
* @ endcode
*
* This is required , because url () does not support relative URLs containing a
* query string or fragment in its $path argument . Instead , any query string
* needs to be parsed into an associative query parameter array in
* $options [ 'query' ] and the fragment into $options [ 'fragment' ] .
*
* @ param $url
2013-12-05 18:02:36 +00:00
* The URL string to parse .
2009-09-29 15:31:17 +00:00
*
* @ return
* An associative array containing the keys :
* - 'path' : The path of the URL . If the given $url is external , this includes
* the scheme and host .
* - 'query' : An array of query parameters of $url , if existent .
* - 'fragment' : The fragment of $url , if existent .
*
* @ see url ()
* @ ingroup php_wrappers
2013-06-29 23:09:39 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
2014-03-05 20:22:39 +00:00
* Use \Drupal\Component\Utility\UrlHelper :: parse () .
2009-09-29 15:31:17 +00:00
*/
function drupal_parse_url ( $url ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: parse ( $url );
2009-09-29 15:31:17 +00:00
}
/**
2010-01-29 22:40:41 +00:00
* Encodes a Drupal path for use in a URL .
2009-09-29 15:31:17 +00:00
*
2010-01-29 22:40:41 +00:00
* For aesthetic reasons slashes are not escaped .
2009-09-29 15:31:17 +00:00
*
2010-01-29 22:40:41 +00:00
* Note that url () takes care of calling this function , so a path passed to that
* function should not be encoded in advance .
2009-09-29 15:31:17 +00:00
*
* @ param $path
2010-01-29 22:40:41 +00:00
* The Drupal path to encode .
2013-06-29 23:09:39 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
2014-03-05 20:22:39 +00:00
* Use \Drupal\Component\Utility\UrlHelper :: encodePath () .
2009-09-29 15:31:17 +00:00
*/
function drupal_encode_path ( $path ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: encodePath ( $path );
2005-02-01 19:45:58 +00:00
}
2012-10-29 22:46:16 +00:00
/**
* Determines if an external URL points to this Drupal installation .
*
* @ param $url
* A string containing an external URL , such as " http://example.com/foo " .
*
* @ return
* TRUE if the URL has the same domain and base path .
2013-06-29 23:09:39 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
2014-03-05 20:22:39 +00:00
* Use \Drupal\Component\Utility\UrlHelper :: externalIsLocal () .
2012-10-29 22:46:16 +00:00
*/
function _external_url_is_local ( $url ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: externalIsLocal ( $url , base_path ());
2012-10-29 22:46:16 +00:00
}
2012-06-29 13:17:34 +00:00
/**
* Helper function for determining hosts excluded from needing a proxy .
*
* @ return
* TRUE if a proxy should be used for this host .
*/
function _drupal_http_use_proxy ( $host ) {
2014-03-24 08:51:28 +00:00
$proxy_exceptions = Settings :: get ( 'proxy_exceptions' , array ( 'localhost' , '127.0.0.1' ));
2012-06-29 13:17:34 +00:00
return ! in_array ( strtolower ( $host ), $proxy_exceptions , TRUE );
}
2004-09-09 05:51:08 +00:00
/**
2012-05-17 12:58:49 +00:00
* @ } End of " defgroup http_handling " .
2004-09-09 05:51:08 +00:00
*/
2003-12-16 21:06:34 +00:00
2004-01-06 19:52:14 +00:00
/**
2004-09-09 05:51:08 +00:00
* @ defgroup validation Input validation
2004-02-08 17:12:44 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Functions to validate user input .
2004-01-06 19:52:14 +00:00
*/
2003-03-28 10:55:27 +00:00
/**
2011-12-05 12:52:27 +00:00
* Verifies the syntax of the given e - mail address .
2004-07-13 07:21:14 +00:00
*
2012-12-15 02:42:57 +00:00
* This uses the
* @ link http :// php . net / manual / filter . filters . validate . php PHP e - mail validation filter . @ endlink
2003-03-28 10:55:27 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $mail
2006-01-13 07:33:13 +00:00
* A string containing an e - mail address .
2011-12-05 12:52:27 +00:00
*
2004-01-07 19:52:10 +00:00
* @ return
2004-07-13 07:21:14 +00:00
* TRUE if the address is in a valid format .
2003-03-28 10:55:27 +00:00
*/
2003-04-13 13:42:51 +00:00
function valid_email_address ( $mail ) {
2008-09-16 17:50:02 +00:00
return ( bool ) filter_var ( $mail , FILTER_VALIDATE_EMAIL );
2003-03-28 10:55:27 +00:00
}
2003-07-16 20:14:26 +00:00
/**
2011-12-05 12:52:27 +00:00
* Verifies the syntax of the given URL .
2003-07-16 20:14:26 +00:00
*
2006-11-21 19:40:09 +00:00
* This function should only be used on actual URLs . It should not be used for
* Drupal menu paths , which can contain arbitrary characters .
2009-01-08 19:09:49 +00:00
* Valid values per RFC 3986.
2004-04-12 08:27:57 +00:00
* @ param $url
2004-07-13 07:21:14 +00:00
* The URL to verify .
2004-04-12 08:27:57 +00:00
* @ param $absolute
2004-09-09 05:51:08 +00:00
* Whether the URL is absolute ( beginning with a scheme such as " http: " ) .
2011-12-05 12:52:27 +00:00
*
2004-04-12 08:27:57 +00:00
* @ return
2004-07-13 07:21:14 +00:00
* TRUE if the URL is in a valid format .
2013-05-28 21:48:53 +00:00
*
2014-03-05 20:22:39 +00:00
* @ see \Drupal\Component\Utility\UrlHelper :: isValid ()
2013-06-14 22:11:48 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
2014-03-05 20:22:39 +00:00
* Use \Drupal\Component\Utility\UrlHelper :: isValid () .
2003-07-16 20:14:26 +00:00
*/
2004-04-12 08:27:57 +00:00
function valid_url ( $url , $absolute = FALSE ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: isValid ( $url , $absolute );
2003-07-16 20:14:26 +00:00
}
2008-01-28 16:05:17 +00:00
/**
* @ } End of " defgroup validation " .
*/
2009-05-24 07:17:14 +00:00
/**
* @ defgroup sanitization Sanitization functions
* @ {
* Functions to sanitize values .
2010-04-24 14:53:59 +00:00
*
* See http :// drupal . org / writing - secure - code for information
* on writing secure code .
2009-05-24 07:17:14 +00:00
*/
2010-07-07 17:00:43 +00:00
/**
2011-12-05 12:52:27 +00:00
* Strips dangerous protocols from a URI and encodes it for output to HTML .
2010-07-07 17:00:43 +00:00
*
* @ param $uri
* A plain - text URI that might contain dangerous protocols .
*
* @ return
* A URI stripped of dangerous protocols and encoded for output to an HTML
* attribute value . Because it is already encoded , it should not be set as a
2012-09-04 13:32:47 +00:00
* value within a $attributes array passed to Drupal\Core\Template\Attribute ,
* because Drupal\Core\Template\Attribute expects those values to be
* plain - text strings . To pass a filtered URI to
2013-10-09 04:42:16 +00:00
* Drupal\Core\Template\Attribute , call
2014-03-05 20:22:39 +00:00
* \Drupal\Component\Utility\UrlHelper :: stripDangerousProtocols () instead .
2010-07-07 17:00:43 +00:00
*
2014-03-05 20:22:39 +00:00
* @ see \Drupal\Component\Utility\UrlHelper :: stripDangerousProtocols ()
2013-05-28 21:48:53 +00:00
* @ see \Drupal\Component\Utility\String :: checkPlain ()
2005-11-30 10:27:13 +00:00
*/
function check_url ( $uri ) {
2014-03-05 20:22:39 +00:00
return String :: checkPlain ( UrlHelper :: stripDangerousProtocols ( $uri ));
2005-11-30 10:27:13 +00:00
}
2009-05-24 07:17:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Applies a very permissive XSS / HTML filter for admin - only use .
2009-05-24 07:17:14 +00:00
*
* Use only for fields where it is impractical to use the
* whole filter system , but where some ( mainly inline ) mark - up
2013-10-07 05:34:09 +00:00
* is desired ( so \Drupal\Component\Utility\String :: checkPlain () is not
* acceptable ) .
2009-05-24 07:17:14 +00:00
*
* Allows all tags that can be used inside an HTML body , save
* for scripts and styles .
2013-05-28 21:48:53 +00:00
*
* @ param string $string
* The string to apply the filter to .
*
* @ return string
* The filtered string .
*
* @ see \Drupal\Component\Utility\Xss :: filterAdmin ()
2009-05-24 07:17:14 +00:00
*/
function filter_xss_admin ( $string ) {
2013-05-28 21:48:53 +00:00
return Xss :: filterAdmin ( $string );
2009-05-24 07:17:14 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Filters HTML to prevent cross - site - scripting ( XSS ) vulnerabilities .
2009-05-24 07:17:14 +00:00
*
2010-06-24 18:51:33 +00:00
* Based on kses by Ulf Harnhammar , see http :// sourceforge . net / projects / kses .
* For examples of various XSS attacks , see : http :// ha . ckers . org / xss . html .
2009-05-24 07:17:14 +00:00
*
* This code does four things :
2010-06-24 18:51:33 +00:00
* - Removes characters and constructs that can trick browsers .
* - Makes sure all HTML entities are well - formed .
* - Makes sure all HTML tags and attributes are well - formed .
* - Makes sure no HTML tags contain URLs with a disallowed protocol ( e . g .
* javascript : ) .
2009-05-24 07:17:14 +00:00
*
* @ param $string
2010-06-24 18:51:33 +00:00
* The string with raw HTML in it . It will be stripped of everything that can
* cause an XSS attack .
2009-05-24 07:17:14 +00:00
* @ param $allowed_tags
* An array of allowed tags .
2010-06-24 18:51:33 +00:00
*
* @ return
* An XSS safe version of $string , or an empty string if $string is not
* valid UTF - 8.
*
2013-05-28 21:48:53 +00:00
* @ see \Drupal\Component\Utility\Xss :: filter ()
2009-05-24 07:17:14 +00:00
*/
function filter_xss ( $string , $allowed_tags = array ( 'a' , 'em' , 'strong' , 'cite' , 'blockquote' , 'code' , 'ul' , 'ol' , 'li' , 'dl' , 'dt' , 'dd' )) {
2013-05-28 21:48:53 +00:00
return Xss :: filter ( $string , $allowed_tags );
2009-05-24 07:17:14 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Processes an HTML attribute value and strips dangerous protocols from URLs .
2009-05-24 07:17:14 +00:00
*
2013-05-28 21:48:53 +00:00
* @ param string $string
2009-05-24 07:17:14 +00:00
* The string with the attribute value .
2011-12-05 12:52:27 +00:00
*
2013-05-28 21:48:53 +00:00
* @ return string
2009-05-24 07:17:14 +00:00
* Cleaned up and HTML - escaped version of $string .
2013-05-28 21:48:53 +00:00
*
2014-03-05 20:22:39 +00:00
* @ see \Drupal\Component\Utility\UrlHelper :: filterBadProtocol ()
2009-05-24 07:17:14 +00:00
*/
2013-05-28 21:48:53 +00:00
function filter_xss_bad_protocol ( $string ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: filterBadProtocol ( $string );
2009-05-24 07:17:14 +00:00
}
/**
* @ } End of " defgroup sanitization " .
*/
2004-02-08 17:12:44 +00:00
/**
2004-09-09 05:51:08 +00:00
* @ defgroup format Formatting
2004-02-08 17:12:44 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Functions to format numbers , strings , dates , etc .
2004-02-08 17:12:44 +00:00
*/
2004-07-13 07:21:14 +00:00
/**
* Formats an RSS channel .
*
* Arbitrary elements may be added using the $args associative array .
*/
2007-05-29 14:37:49 +00:00
function format_rss_channel ( $title , $link , $description , $items , $langcode = NULL , $args = array ()) {
2014-02-26 19:16:54 +00:00
$langcode = $langcode ? $langcode : \Drupal :: languageManager () -> getCurrentLanguage ( Language :: TYPE_CONTENT ) -> id ;
2002-04-27 13:19:37 +00:00
2003-12-13 14:59:55 +00:00
$output = " <channel> \n " ;
2013-10-07 05:34:09 +00:00
$output .= ' <title>' . String :: checkPlain ( $title ) . " </title> \n " ;
2008-04-14 17:48:46 +00:00
$output .= ' <link>' . check_url ( $link ) . " </link> \n " ;
2006-03-01 21:30:17 +00:00
// The RSS 2.0 "spec" doesn't indicate HTML can be used in the description.
// We strip all HTML tags, but need to prevent double encoding from properly
// escaped source data (such as & becoming &amp;).
2013-10-07 05:34:09 +00:00
$output .= ' <description>' . String :: checkPlain ( decode_entities ( strip_tags ( $description ))) . " </description> \n " ;
$output .= ' <language>' . String :: checkPlain ( $langcode ) . " </language> \n " ;
2006-07-17 15:42:55 +00:00
$output .= format_xml_elements ( $args );
2001-12-01 15:20:48 +00:00
$output .= $items ;
$output .= " </channel> \n " ;
return $output ;
}
2004-07-13 07:21:14 +00:00
/**
2011-12-05 12:52:27 +00:00
* Formats a single RSS item .
2004-07-13 07:21:14 +00:00
*
* Arbitrary elements may be added using the $args associative array .
*/
2002-04-27 13:19:37 +00:00
function format_rss_item ( $title , $link , $description , $args = array ()) {
2003-12-13 14:59:55 +00:00
$output = " <item> \n " ;
2013-10-07 05:34:09 +00:00
$output .= ' <title>' . String :: checkPlain ( $title ) . " </title> \n " ;
2008-04-14 17:48:46 +00:00
$output .= ' <link>' . check_url ( $link ) . " </link> \n " ;
2013-10-07 05:34:09 +00:00
$output .= ' <description>' . String :: checkPlain ( $description ) . " </description> \n " ;
2006-07-17 15:42:55 +00:00
$output .= format_xml_elements ( $args );
$output .= " </item> \n " ;
return $output ;
}
/**
2011-12-05 12:52:27 +00:00
* Formats XML elements .
2006-07-17 15:42:55 +00:00
*
* @ param $array
2010-09-26 23:31:36 +00:00
* An array where each item represents an element and is either a :
2006-07-17 15:42:55 +00:00
* - ( key => value ) pair ( < key > value </ key > )
* - Associative array with fields :
* - 'key' : element name
* - 'value' : element contents
* - 'attributes' : associative array of element attributes
*
* In both cases , 'value' can be a simple string , or it can be another array
* with the same format as $array itself for nesting .
*/
function format_xml_elements ( $array ) {
2007-03-27 05:13:55 +00:00
$output = '' ;
2006-07-17 15:42:55 +00:00
foreach ( $array as $key => $value ) {
if ( is_numeric ( $key )) {
2005-02-01 14:09:31 +00:00
if ( $value [ 'key' ]) {
2008-04-14 17:48:46 +00:00
$output .= ' <' . $value [ 'key' ];
2005-12-14 20:10:45 +00:00
if ( isset ( $value [ 'attributes' ]) && is_array ( $value [ 'attributes' ])) {
2012-09-04 13:32:47 +00:00
$output .= new Attribute ( $value [ 'attributes' ]);
2005-02-01 14:09:31 +00:00
}
2008-07-19 10:38:13 +00:00
if ( isset ( $value [ 'value' ]) && $value [ 'value' ] != '' ) {
2013-10-07 05:34:09 +00:00
$output .= '>' . ( is_array ( $value [ 'value' ]) ? format_xml_elements ( $value [ 'value' ]) : String :: checkPlain ( $value [ 'value' ])) . '</' . $value [ 'key' ] . " > \n " ;
2005-02-01 14:09:31 +00:00
}
else {
$output .= " /> \n " ;
}
}
}
else {
2013-10-07 05:34:09 +00:00
$output .= ' <' . $key . '>' . ( is_array ( $value ) ? format_xml_elements ( $value ) : String :: checkPlain ( $value )) . " </ $key > \n " ;
2005-02-01 14:09:31 +00:00
}
2002-04-27 13:19:37 +00:00
}
2001-12-01 15:20:48 +00:00
return $output ;
}
2003-01-21 22:44:25 +00:00
/**
2011-12-05 12:52:27 +00:00
* Formats a string containing a count of items .
2003-01-21 22:44:25 +00:00
*
2004-07-13 07:21:14 +00:00
* This function ensures that the string is pluralized correctly . Since t () is
2007-10-08 14:08:19 +00:00
* called by this function , make sure not to pass already - localized strings to
* it .
2004-07-13 07:21:14 +00:00
*
2007-03-07 13:08:04 +00:00
* For example :
* @ code
* $output = format_plural ( $node -> comment_count , '1 comment' , '@count comments' );
* @ endcode
*
* Example with additional replacements :
* @ code
* $output = format_plural ( $update_count ,
* 'Changed the content type of 1 post from %old-type to %new-type.' ,
* 'Changed the content type of @count posts from %old-type to %new-type.' ,
2012-09-13 23:38:55 +00:00
* array ( '%old-type' => $info -> old_type , '%new-type' => $info -> new_type ));
2007-03-07 13:08:04 +00:00
* @ endcode
*
2004-07-13 07:21:14 +00:00
* @ param $count
* The item count to display .
* @ param $singular
2011-12-05 12:52:27 +00:00
* The string for the singular case . Make sure it is clear this is singular ,
* to ease translation ( e . g . use " 1 new comment " instead of " 1 new " ) . Do not
* use @ count in the singular string .
2004-07-13 07:21:14 +00:00
* @ param $plural
2011-12-05 12:52:27 +00:00
* The string for the plural case . Make sure it is clear this is plural , to
* ease translation . Use @ count in place of the item count , as in
* " @count new comments " .
2007-03-07 13:08:04 +00:00
* @ param $args
2011-12-05 12:52:27 +00:00
* An associative array of replacements to make after translation . Instances
2007-03-07 13:08:04 +00:00
* of any key in this array are replaced with the corresponding value .
2011-12-05 12:52:27 +00:00
* Based on the first character of the key , the value is escaped and / or
* themed . See format_string () . Note that you do not need to include @ count
* in this array ; this replacement is done automatically for the plural case .
2009-06-08 05:00:12 +00:00
* @ param $options
2011-12-05 12:52:27 +00:00
* An associative array of additional options . See t () for allowed keys .
*
2004-07-13 07:21:14 +00:00
* @ return
* A translated string .
2011-12-05 12:52:27 +00:00
*
* @ see t ()
* @ see format_string ()
2014-02-20 13:49:37 +00:00
* @ see \Drupal\Core\StringTranslation\TranslationManager -> formatPlural ()
2013-12-03 19:35:43 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: translation () -> formatPlural () .
2003-01-21 22:44:25 +00:00
*/
2009-06-08 05:00:12 +00:00
function format_plural ( $count , $singular , $plural , array $args = array (), array $options = array ()) {
2013-12-03 19:35:43 +00:00
return \Drupal :: translation () -> formatPlural ( $count , $singular , $plural , $args , $options );
2001-12-01 15:20:48 +00:00
}
2006-12-07 17:02:25 +00:00
/**
2011-12-05 12:52:27 +00:00
* Parses a given byte count .
2006-12-07 17:02:25 +00:00
*
* @ param $size
2008-11-16 15:19:34 +00:00
* A size expressed as a number of bytes with optional SI or IEC binary unit
* prefix ( e . g . 2 , 3 K , 5 MB , 10 G , 6 GiB , 8 bytes , 9 mbytes ) .
2011-12-05 12:52:27 +00:00
*
2006-12-07 17:02:25 +00:00
* @ return
2008-11-16 15:19:34 +00:00
* An integer representation of the size in bytes .
2006-12-07 17:02:25 +00:00
*/
function parse_size ( $size ) {
2008-11-16 15:19:34 +00:00
$unit = preg_replace ( '/[^bkmgtpezy]/i' , '' , $size ); // Remove the non-unit characters from the size.
$size = preg_replace ( '/[^0-9\.]/' , '' , $size ); // Remove the non-numeric characters from the size.
if ( $unit ) {
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
return round ( $size * pow ( DRUPAL_KILOBYTE , stripos ( 'bkmgtpezy' , $unit [ 0 ])));
}
else {
return round ( $size );
2006-12-07 17:02:25 +00:00
}
}
2004-02-08 17:12:44 +00:00
/**
2011-12-05 12:52:27 +00:00
* Generates a string representation for the given byte count .
2004-02-08 17:12:44 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $size
2007-10-08 14:08:19 +00:00
* A size in bytes .
2007-05-29 14:37:49 +00:00
* @ param $langcode
2007-10-08 14:08:19 +00:00
* Optional language code to translate to a language other than what is used
* to display the page .
2011-12-05 12:52:27 +00:00
*
2004-07-13 07:21:14 +00:00
* @ return
* A translated string representation of the size .
2004-02-08 17:12:44 +00:00
*/
2007-05-29 14:37:49 +00:00
function format_size ( $size , $langcode = NULL ) {
2008-11-16 15:19:34 +00:00
if ( $size < DRUPAL_KILOBYTE ) {
2009-06-08 05:00:12 +00:00
return format_plural ( $size , '1 byte' , '@count bytes' , array (), array ( 'langcode' => $langcode ));
2001-12-01 15:20:48 +00:00
}
2006-12-30 21:33:04 +00:00
else {
2008-11-16 15:19:34 +00:00
$size = $size / DRUPAL_KILOBYTE ; // Convert bytes to kilobytes.
2008-08-14 09:21:49 +00:00
$units = array (
2009-06-08 05:00:12 +00:00
t ( '@size KB' , array (), array ( 'langcode' => $langcode )),
t ( '@size MB' , array (), array ( 'langcode' => $langcode )),
t ( '@size GB' , array (), array ( 'langcode' => $langcode )),
t ( '@size TB' , array (), array ( 'langcode' => $langcode )),
t ( '@size PB' , array (), array ( 'langcode' => $langcode )),
t ( '@size EB' , array (), array ( 'langcode' => $langcode )),
t ( '@size ZB' , array (), array ( 'langcode' => $langcode )),
t ( '@size YB' , array (), array ( 'langcode' => $langcode )),
2008-08-14 09:21:49 +00:00
);
foreach ( $units as $unit ) {
2008-11-16 15:19:34 +00:00
if ( round ( $size , 2 ) >= DRUPAL_KILOBYTE ) {
$size = $size / DRUPAL_KILOBYTE ;
2008-06-09 08:11:45 +00:00
}
else {
break ;
}
2006-12-30 21:33:04 +00:00
}
2008-08-14 09:21:49 +00:00
return str_replace ( '@size' , round ( $size , 2 ), $unit );
2001-12-01 15:20:48 +00:00
}
}
2004-02-08 17:12:44 +00:00
/**
2011-12-05 12:52:27 +00:00
* Formats a time interval with the requested granularity .
2004-02-08 17:12:44 +00:00
*
2012-01-25 13:19:32 +00:00
* @ param $interval
2004-07-13 07:21:14 +00:00
* The length of the interval in seconds .
* @ param $granularity
* How many different units to display in the string .
2007-05-29 14:37:49 +00:00
* @ param $langcode
* Optional language code to translate to a language other than
* what is used to display the page .
2011-12-05 12:52:27 +00:00
*
2004-07-13 07:21:14 +00:00
* @ return
* A translated string representation of the interval .
2013-12-03 19:35:43 +00:00
*
2014-02-20 13:49:37 +00:00
* @ see \Drupal\Core\Datetime\Date :: formatInterval ()
*
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: service ( 'date' ) -> formatInterval () .
2004-02-08 17:12:44 +00:00
*/
2012-01-25 13:19:32 +00:00
function format_interval ( $interval , $granularity = 2 , $langcode = NULL ) {
2013-12-03 19:35:43 +00:00
return \Drupal :: service ( 'date' ) -> formatInterval ( $interval , $granularity , $langcode );
2001-12-01 15:20:48 +00:00
}
2004-02-08 17:12:44 +00:00
/**
2010-11-30 06:30:21 +00:00
* Formats a date , using a date type or a custom date format string .
2004-02-08 17:12:44 +00:00
*
2004-07-13 07:21:14 +00:00
* @ param $timestamp
2010-11-30 06:30:21 +00:00
* A UNIX timestamp to format .
2004-07-13 07:21:14 +00:00
* @ param $type
2010-11-30 06:30:21 +00:00
* ( optional ) The format to use , one of :
2012-11-29 07:37:55 +00:00
* - One of the built - in formats : 'short' , 'medium' ,
* 'long' , 'html_datetime' , 'html_date' , 'html_time' ,
* 'html_yearless_date' , 'html_week' , 'html_month' , 'html_year' .
* - The name of a date type defined by a module in
* hook_date_format_types (), if it ' s been assigned a format .
2010-11-30 06:30:21 +00:00
* - The machine name of an administrator - defined date format .
* - 'custom' , to use $format .
* Defaults to 'medium' .
2004-07-13 07:21:14 +00:00
* @ param $format
2010-11-30 06:30:21 +00:00
* ( optional ) If $type is 'custom' , a PHP date format string suitable for
* input to date () . Use a backslash to escape ordinary text , so it does not
* get interpreted as date format characters .
2004-07-13 07:21:14 +00:00
* @ param $timezone
2010-11-30 06:30:21 +00:00
* ( optional ) Time zone identifier , as described at
2012-03-24 06:14:35 +00:00
* http :// php . net / manual / timezones . php Defaults to the time zone used to
2010-11-30 06:30:21 +00:00
* display the page .
2007-05-29 14:37:49 +00:00
* @ param $langcode
2010-11-30 06:30:21 +00:00
* ( optional ) Language code to translate to . Defaults to the language used to
* display the page .
*
2004-07-13 07:21:14 +00:00
* @ return
* A translated date string in the requested format .
2013-06-12 09:18:07 +00:00
*
* @ see \Drupal\Component\Datetime\Date :: format ()
2004-02-08 17:12:44 +00:00
*/
2007-05-29 14:37:49 +00:00
function format_date ( $timestamp , $type = 'medium' , $format = '' , $timezone = NULL , $langcode = NULL ) {
2013-09-16 03:58:06 +00:00
return \Drupal :: service ( 'date' ) -> format ( $timestamp , $type , $format , $timezone , $langcode );
2009-07-08 20:40:21 +00:00
}
2009-10-18 18:32:27 +00:00
/**
* Returns an ISO8601 formatted date based on the given date .
*
* @ param $date
* A UNIX timestamp .
2011-12-05 12:52:27 +00:00
*
2009-10-18 18:32:27 +00:00
* @ return string
* An ISO8601 formatted date .
*/
function date_iso8601 ( $date ) {
// The DATE_ISO8601 constant cannot be used here because it does not match
// date('c') and produces invalid RDF markup.
return date ( 'c' , $date );
}
2009-07-08 20:40:21 +00:00
/**
2011-12-05 12:52:27 +00:00
* Translates a formatted date string .
*
* Callback for preg_replace_callback () within format_date () .
2009-07-08 20:40:21 +00:00
*/
function _format_date_callback ( array $matches = NULL , $new_langcode = NULL ) {
// We cache translations to avoid redundant and rather costly calls to t().
static $cache , $langcode ;
if ( ! isset ( $matches )) {
$langcode = $new_langcode ;
return ;
}
$code = $matches [ 1 ];
$string = $matches [ 2 ];
if ( ! isset ( $cache [ $langcode ][ $code ][ $string ])) {
$options = array (
'langcode' => $langcode ,
);
if ( $code == 'F' ) {
$options [ 'context' ] = 'Long month name' ;
2003-09-29 18:20:38 +00:00
}
2009-07-08 20:40:21 +00:00
if ( $code == '' ) {
$cache [ $langcode ][ $code ][ $string ] = $string ;
2004-12-03 20:38:22 +00:00
}
2003-09-29 18:20:38 +00:00
else {
2009-07-08 20:40:21 +00:00
$cache [ $langcode ][ $code ][ $string ] = t ( $string , array (), $options );
2003-09-29 18:20:38 +00:00
}
2001-12-01 15:20:48 +00:00
}
2009-07-08 20:40:21 +00:00
return $cache [ $langcode ][ $code ][ $string ];
2001-12-01 15:20:48 +00:00
}
2013-02-16 23:29:53 +00:00
/**
* Retrieves the correct datetime format type for this system .
*
* This value is sometimes required when the format type needs to be determined
* before a date can be created .
*
* @ return string
* A string as defined in \DrupalComponent\Datetime\DateTimePlus . php : either
* 'intl' or 'php' , depending on whether IntlDateFormatter is available .
*/
function datetime_default_format_type () {
static $drupal_static_fast ;
if ( ! isset ( $drupal_static_fast )) {
$drupal_static_fast [ 'format_type' ] = & drupal_static ( __FUNCTION__ );
}
$format_type = & $drupal_static_fast [ 'format_type' ];
if ( ! isset ( $format_type )) {
$date = new DrupalDateTime ();
$format_type = $date -> canUseIntl () ? DrupalDateTime :: INTL : DrupalDateTime :: PHP ;
}
return $format_type ;
}
2004-09-09 05:51:08 +00:00
/**
* @ } End of " defgroup format " .
*/
2001-12-01 15:20:48 +00:00
2004-07-13 07:21:14 +00:00
/**
2010-04-06 16:41:08 +00:00
* Generates an internal or external URL .
*
* When creating links in modules , consider whether l () could be a better
* alternative than url () .
2004-07-13 07:21:14 +00:00
*
2013-08-22 17:21:03 +00:00
* @ see \Drupal\Core\Routing\UrlGeneratorInterface :: generateFromPath () .
2004-07-13 07:21:14 +00:00
*/
2008-10-06 11:07:14 +00:00
function url ( $path = NULL , array $options = array ()) {
2013-09-16 03:58:06 +00:00
$generator = \Drupal :: urlGenerator ();
2013-06-06 08:14:16 +00:00
try {
$url = $generator -> generateFromPath ( $path , $options );
2005-12-29 05:28:53 +00:00
}
2013-06-06 08:14:16 +00:00
catch ( GeneratorNotInitializedException $e ) {
// Fallback to using globals.
// @todo Remove this once there is no code that calls url() when there is
// no request.
global $base_url , $base_path , $script_path ;
$generator -> setBasePath ( $base_path );
$generator -> setBaseUrl ( $base_url . '/' );
$generator -> setScriptPath ( $script_path );
$url = $generator -> generateFromPath ( $path , $options );
2007-11-29 14:42:31 +00:00
}
2013-06-06 08:14:16 +00:00
return $url ;
2002-04-20 11:52:50 +00:00
}
2009-11-01 23:02:13 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns TRUE if a path is external to Drupal ( e . g . http :// example . com ) .
2010-06-09 14:55:30 +00:00
*
* If a path cannot be assessed by Drupal ' s menu handler , then we must
* treat it as potentially insecure .
*
* @ param $path
* The internal path or external URL being linked to , such as " node/34 " or
* " http://example.com/foo " .
2011-12-05 12:52:27 +00:00
*
2010-08-01 19:54:31 +00:00
* @ return
2010-06-09 14:55:30 +00:00
* Boolean TRUE or FALSE , where TRUE indicates an external path .
2009-11-01 23:02:13 +00:00
*/
function url_is_external ( $path ) {
2014-03-05 20:22:39 +00:00
return UrlHelper :: isExternal ( $path );
2009-11-01 23:02:13 +00:00
}
2009-11-03 06:47:23 +00:00
/**
2011-12-05 12:52:27 +00:00
* Formats an attribute string for an HTTP header .
2009-11-03 06:47:23 +00:00
*
* @ param $attributes
* An associative array of attributes such as 'rel' .
*
* @ return
* A ; separated string ready for insertion in a HTTP header . No escaping is
* performed for HTML entities , so this string is not safe to be printed .
*
* @ see drupal_add_http_header ()
*/
function drupal_http_header_attributes ( array $attributes = array ()) {
foreach ( $attributes as $attribute => & $data ) {
if ( is_array ( $data )) {
$data = implode ( ' ' , $data );
}
$data = $attribute . '="' . $data . '"' ;
}
return $attributes ? ' ' . implode ( '; ' , $attributes ) : '' ;
}
2004-07-13 07:21:14 +00:00
/**
2010-04-06 16:41:08 +00:00
* Formats an internal or external URL link as an HTML anchor tag .
2004-07-13 07:21:14 +00:00
*
2012-09-11 15:46:00 +00:00
* This function correctly handles aliased paths and adds an 'active' class
2010-04-06 16:41:08 +00:00
* attribute to links that point to the current page ( for theming ), so all
* internal links output by modules should be generated by this function if
* possible .
2004-07-13 07:21:14 +00:00
*
2012-11-13 16:21:04 +00:00
* However , for links enclosed in translatable text you should use t () and
* embed the HTML anchor tag directly in the translated string . For example :
* @ code
* t ( 'Visit the <a href="@url">settings</a> page' , array ( '@url' => url ( 'admin' )));
* @ endcode
* This keeps the context of the link title ( 'settings' in the example ) for
* translators .
*
2013-08-30 15:28:49 +00:00
* This function does not support generating links from internal routes . For
* that use \Drupal\Core\Utility\LinkGenerator :: generate (), which is exposed via
* the 'link_generator' service . It requires an internal route name and does not
* support external URLs . Using Drupal 7 style system paths should be avoided if
* possible but l () should still be used when rendering links to external URLs .
*
2013-06-02 16:12:36 +00:00
* @ param string | array $text
* The link text for the anchor tag as a translated string or render array .
2012-09-11 15:46:00 +00:00
* @ param string $path
2010-04-06 16:41:08 +00:00
* The internal path or external URL being linked to , such as " node/34 " or
* " http://example.com/foo " . After the url () function is called to construct
* the URL from $path and $options , the resulting URL is passed through
2013-10-07 05:34:09 +00:00
* \Drupal\Component\Utility\String :: checkPlain () before it is inserted into
* the HTML anchor tag , to ensure well - formed HTML . See url () for more
* information and notes .
2010-04-06 16:41:08 +00:00
* @ param array $options
2012-09-11 15:46:00 +00:00
* An associative array of additional options . Defaults to an empty array . It
* may contain the following elements .
2010-04-06 16:41:08 +00:00
* - 'attributes' : An associative array of HTML attributes to apply to the
2010-11-21 10:05:27 +00:00
* anchor tag . If element 'class' is included , it must be an array ; 'title'
* must be a string ; other elements are more flexible , as they just need
2012-09-04 13:32:47 +00:00
* to work as an argument for the constructor of the class
* Drupal\Core\Template\Attribute ( $options [ 'attributes' ]) .
2010-04-06 16:41:08 +00:00
* - 'html' ( default FALSE ) : Whether $text is HTML or just plain - text . For
* example , to make an image tag into a link , this must be set to TRUE , or
2011-07-03 18:00:28 +00:00
* you will see the escaped HTML image tag . $text is not sanitized if
* 'html' is TRUE . The calling function must ensure that $text is already
* safe .
2010-04-06 16:41:08 +00:00
* - 'language' : An optional language object . If the path being linked to is
* internal to the site , $options [ 'language' ] is used to determine whether
* the link is " active " , or pointing to the current page ( the language as
* well as the path must match ) . This element is also used by url () .
2014-01-23 18:04:41 +00:00
* - 'set_active_class' : Whether l () should compare the $path , language and
* query options to the current URL to determine whether the link is
* " active " . Defaults to FALSE . If TRUE , an " active " class will be applied
* to the link . It is important to use this sparingly since it is usually
* unnecessary and requires extra processing .
* For anonymous users , the " active " class will be calculated on the server ,
* because most sites serve each anonymous user the same cached page anyway .
* For authenticated users , the " active " class will be calculated on the
* client ( through JavaScript ), only data - attributes are added to links to
* prevent breaking the render cache . The JavaScript is added in
* system_page_build () .
2010-04-06 16:41:08 +00:00
* - Additional $options elements used by the url () function .
2010-03-18 19:15:02 +00:00
*
2012-09-11 15:46:00 +00:00
* @ return string
2010-04-06 16:41:08 +00:00
* An HTML string containing a link to the given path .
2012-09-11 15:46:00 +00:00
*
* @ see url ()
2014-01-23 18:04:41 +00:00
* @ see system_page_build ()
2004-07-13 07:21:14 +00:00
*/
2008-10-06 11:07:14 +00:00
function l ( $text , $path , array $options = array ()) {
2013-06-02 16:12:36 +00:00
// Start building a structured representation of our link to be altered later.
2013-05-01 08:53:04 +00:00
$variables = array (
2013-06-02 16:12:36 +00:00
'text' => is_array ( $text ) ? drupal_render ( $text ) : $text ,
2013-05-01 08:53:04 +00:00
'path' => $path ,
'options' => $options ,
);
2009-01-22 03:18:30 +00:00
2013-05-01 08:53:04 +00:00
// Merge in default options.
$variables [ 'options' ] += array (
2010-09-24 00:37:45 +00:00
'attributes' => array (),
2012-10-29 22:55:17 +00:00
'query' => array (),
2010-09-24 00:37:45 +00:00
'html' => FALSE ,
2013-05-01 08:53:04 +00:00
'language' => NULL ,
2014-01-23 18:04:41 +00:00
'set_active_class' => FALSE ,
2010-09-24 00:37:45 +00:00
);
2007-02-15 11:40:19 +00:00
2013-08-12 02:51:23 +00:00
// Add a hreflang attribute if we know the language of this link's url and
// hreflang has not already been set.
if ( ! empty ( $variables [ 'options' ][ 'language' ]) && ! isset ( $variables [ 'options' ][ 'attributes' ][ 'hreflang' ])) {
$variables [ 'options' ][ 'attributes' ][ 'hreflang' ] = $variables [ 'options' ][ 'language' ] -> id ;
}
2014-01-23 18:04:41 +00:00
// Set the "active" class if the 'set_active_class' option is not empty.
if ( ! empty ( $variables [ 'options' ][ 'set_active_class' ])) {
// Add a "data-drupal-link-query" attribute to let the drupal.active-link
// library know the query in a standardized manner.
if ( ! empty ( $variables [ 'options' ][ 'query' ])) {
$query = $variables [ 'options' ][ 'query' ];
ksort ( $query );
$variables [ 'options' ][ 'attributes' ][ 'data-drupal-link-query' ] = Json :: encode ( $query );
}
2013-05-01 08:53:04 +00:00
2014-01-23 18:04:41 +00:00
// Add a "data-drupal-link-system-path" attribute to let the
// drupal.active-link library know the path in a standardized manner.
if ( ! isset ( $variables [ 'options' ][ 'attributes' ][ 'data-drupal-link-system-path' ])) {
$variables [ 'options' ][ 'attributes' ][ 'data-drupal-link-system-path' ] = \Drupal :: service ( 'path.alias_manager.cached' ) -> getSystemPath ( $path );
}
2013-05-01 08:53:04 +00:00
}
// Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags()
// only when a quick strpos() gives suspicion tags are present.
if ( isset ( $variables [ 'options' ][ 'attributes' ][ 'title' ]) && strpos ( $variables [ 'options' ][ 'attributes' ][ 'title' ], '<' ) !== FALSE ) {
$variables [ 'options' ][ 'attributes' ][ 'title' ] = strip_tags ( $variables [ 'options' ][ 'attributes' ][ 'title' ]);
2009-11-08 12:43:41 +00:00
}
2013-05-01 08:53:04 +00:00
// Allow other modules to modify the structure of the link.
2013-09-16 03:58:06 +00:00
\Drupal :: moduleHandler () -> alter ( 'link' , $variables );
2013-05-01 08:53:04 +00:00
// Move attributes out of options. url() doesn't need them.
$attributes = new Attribute ( $variables [ 'options' ][ 'attributes' ]);
unset ( $variables [ 'options' ][ 'attributes' ]);
2010-02-01 07:06:14 +00:00
// The result of url() is a plain-text URL. Because we are using it here
// in an HTML argument context, we need to encode it properly.
2013-10-07 05:34:09 +00:00
$url = String :: checkPlain ( url ( $variables [ 'path' ], $variables [ 'options' ]));
2013-05-01 08:53:04 +00:00
// Sanitize the link text if necessary.
2013-10-07 05:34:09 +00:00
$text = $variables [ 'options' ][ 'html' ] ? $variables [ 'text' ] : String :: checkPlain ( $variables [ 'text' ]);
2013-05-01 08:53:04 +00:00
return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>' ;
2002-04-20 11:52:50 +00:00
}
2009-08-05 15:58:35 +00:00
/**
* Attempts to set the PHP maximum execution time .
*
* This function is a wrapper around the PHP function set_time_limit () .
* When called , set_time_limit () restarts the timeout counter from zero .
* In other words , if the timeout is the default 30 seconds , and 25 seconds
* into script execution a call such as set_time_limit ( 20 ) is made , the
* script will run for a total of 45 seconds before timing out .
2009-08-15 06:20:20 +00:00
*
2009-08-05 15:58:35 +00:00
* It also means that it is possible to decrease the total time limit if
* the sum of the new time limit and the current time spent running the
* script is inferior to the original time limit . It is inherent to the way
* set_time_limit () works , it should rather be called with an appropriate
* value every time you need to allocate a certain amount of time
* to execute a task than only once at the beginning of the script .
2009-08-15 06:20:20 +00:00
*
2009-08-05 15:58:35 +00:00
* Before calling set_time_limit (), we check if this function is available
* because it could be disabled by the server administrator . We also hide all
* the errors that could occur when calling set_time_limit (), because it is
* not possible to reliably ensure that PHP or a security extension will
* not issue a warning / error if they prevent the use of this function .
*
* @ param $time_limit
* An integer specifying the new time limit , in seconds . A value of 0
* indicates unlimited execution time .
2009-09-28 22:22:54 +00:00
*
* @ ingroup php_wrappers
2009-08-05 15:58:35 +00:00
*/
function drupal_set_time_limit ( $time_limit ) {
if ( function_exists ( 'set_time_limit' )) {
@ set_time_limit ( $time_limit );
}
}
2004-11-24 22:44:01 +00:00
/**
* Returns the path to a system item ( module , theme , etc . ) .
*
* @ param $type
2010-02-17 03:55:45 +00:00
* The type of the item ( i . e . theme , theme_engine , module , profile ) .
2004-11-24 22:44:01 +00:00
* @ param $name
* The name of the item for which the path is requested .
*
* @ return
2013-02-11 17:32:49 +00:00
* The path to the requested item or an empty string if the item is not found .
2004-11-24 22:44:01 +00:00
*/
function drupal_get_path ( $type , $name ) {
return dirname ( drupal_get_filename ( $type , $name ));
}
2006-02-02 12:44:57 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns the base URL path ( i . e . , directory ) of the Drupal installation .
2009-04-26 07:50:51 +00:00
*
2011-12-05 12:52:27 +00:00
* base_path () adds a " / " to the beginning and end of the returned path if the
* path is not empty . At the very least , this will return " / " .
2009-04-26 07:50:51 +00:00
*
2009-05-01 16:45:52 +00:00
* Examples :
* - http :// example . com returns " / " because the path is empty .
* - http :// example . com / drupal / folder returns " /drupal/folder/ " .
2006-02-02 12:44:57 +00:00
*/
function base_path () {
2012-04-01 01:17:44 +00:00
return $GLOBALS [ 'base_path' ];
2006-02-02 12:44:57 +00:00
}
2005-05-31 21:14:27 +00:00
/**
2011-12-05 12:52:27 +00:00
* Adds a LINK tag with a distinct 'rel' attribute to the page ' s HEAD .
2008-09-18 10:40:28 +00:00
*
2011-12-05 12:52:27 +00:00
* This function can be called as long the HTML header hasn ' t been sent , which
2014-02-18 10:54:10 +00:00
* on normal pages is up through the preprocess step of _theme ( 'html' ) . Adding
2011-12-05 12:52:27 +00:00
* a link will overwrite a prior link with the exact same 'rel' and 'href'
* attributes .
2009-12-15 08:45:32 +00:00
*
2009-11-03 06:47:23 +00:00
* @ param $attributes
* Associative array of element attributes including 'href' and 'rel' .
* @ param $header
* Optional flag to determine if a HTTP 'Link:' header should be sent .
*/
function drupal_add_html_head_link ( $attributes , $header = FALSE ) {
$element = array (
'#tag' => 'link' ,
'#attributes' => $attributes ,
);
$href = $attributes [ 'href' ];
if ( $header ) {
// Also add a HTTP header "Link:".
2013-10-07 05:34:09 +00:00
$href = '<' . String :: checkPlain ( $attributes [ 'href' ]) . '>;' ;
2009-11-03 06:47:23 +00:00
unset ( $attributes [ 'href' ]);
$element [ '#attached' ][ 'drupal_add_http_header' ][] = array ( 'Link' , $href . drupal_http_header_attributes ( $attributes ), TRUE );
}
drupal_add_html_head ( $element , 'drupal_add_html_head_link:' . $attributes [ 'rel' ] . ':' . $href );
2005-05-31 21:14:27 +00:00
}
2006-08-03 07:06:36 +00:00
/**
2009-03-30 05:13:45 +00:00
* Adds a cascading stylesheet to the stylesheet queue .
*
2014-01-08 06:44:57 +00:00
* Calling drupal_static_reset ( '_drupal_add_css' ) will clear all cascading
2009-05-16 13:26:31 +00:00
* stylesheets added so far .
*
2010-07-30 02:47:28 +00:00
* If CSS aggregation / compression is enabled , all cascading style sheets added
* with $options [ 'preprocess' ] set to TRUE will be merged into one aggregate
* file and compressed by removing all extraneous white space .
* Preprocessed inline stylesheets will not be aggregated into this single file ;
* instead , they are just compressed upon output on the page . Externally hosted
* stylesheets are never aggregated or compressed .
*
* The reason for aggregating the files is outlined quite thoroughly here :
2009-12-05 22:16:44 +00:00
* http :// www . die . net / musings / page_load_time / " Load fewer external objects. Due
* to request overhead , one bigger file just loads faster than two smaller ones
* half its size . "
*
2010-07-30 02:47:28 +00:00
* $options [ 'preprocess' ] should be only set to TRUE when a file is required for
* all typical visitors and most pages of a site . It is critical that all
* preprocessed files are added unconditionally on every page , even if the
* files do not happen to be needed on a page . This is normally done by calling
2014-01-08 06:44:57 +00:00
* _drupal_add_css () in a hook_page_build () implementation .
2009-12-05 22:16:44 +00:00
*
2010-07-30 02:47:28 +00:00
* Non - preprocessed files should only be added to the page when they are
* actually needed .
2009-12-05 22:16:44 +00:00
*
2009-03-30 05:13:45 +00:00
* @ param $data
* ( optional ) The stylesheet data to be added , depending on what is passed
* through to the $options [ 'type' ] parameter :
2011-07-28 19:32:16 +00:00
* - 'file' : The path to the CSS file relative to the base_path (), or a
* stream wrapper URI . For example : " modules/devel/devel.css " or
* " public://generated_css/stylesheet_1.css " . Note that Modules should
* always prefix the names of their CSS files with the module name ; for
* example , system - menus . css rather than simply menus . css . Themes can
* override module - supplied CSS files based on their filenames , and this
* prefixing helps prevent confusing name collisions for theme developers .
2013-09-12 05:25:51 +00:00
* See drupal_get_css () where the overrides are performed .
2009-03-30 05:13:45 +00:00
* - 'inline' : A string of CSS that should be placed in the given scope . Note
2009-12-05 22:16:44 +00:00
* that it is better practice to use 'file' stylesheets , rather than
* 'inline' , as the CSS would then be aggregated and cached .
2009-08-14 16:15:38 +00:00
* - 'external' : The absolute path to an external CSS file that is not hosted
2009-12-05 22:16:44 +00:00
* on the local server . These files will not be aggregated if CSS
* aggregation is enabled .
2008-10-26 18:06:39 +00:00
* @ param $options
2009-03-30 05:13:45 +00:00
* ( optional ) A string defining the 'type' of CSS that is being added in the
2009-12-05 22:16:44 +00:00
* $data parameter ( 'file' , 'inline' , or 'external' ), or an array which can
* have any or all of the following keys :
2009-08-14 16:15:38 +00:00
* - 'type' : The type of stylesheet being added . Available options are 'file' ,
* 'inline' or 'external' . Defaults to 'file' .
2010-03-21 21:14:30 +00:00
* - 'basename' : Force a basename for the file being added . Modules are
* expected to use stylesheets with unique filenames , but integration of
* external libraries may make this impossible . The basename of
2011-10-31 04:05:57 +00:00
* 'core/modules/node/node.css' is 'node.css' . If the external library
* " node.js " ships with a 'node.css' , then a different , unique basename
* would be 'node.js.css' .
2013-04-04 02:14:52 +00:00
* - 'group' : A number identifying the aggregation group in which to add the
* stylesheet . Available constants are :
* - CSS_AGGREGATE_DEFAULT : ( default ) Any module - layer CSS .
* - CSS_AGGREGATE_THEME : Any theme - layer CSS .
* The aggregate group number affects load order and the CSS cascade .
* Stylesheets in an aggregate with a lower group number will be output to
* the page before stylesheets in an aggregate with a higher group number ,
* so CSS within higher aggregate groups can take precendence over CSS
* within lower aggregate groups .
2010-10-05 19:59:10 +00:00
* - 'every_page' : For optimal front - end performance when aggregation is
* enabled , this should be set to TRUE if the stylesheet is present on every
* page of the website for users for whom it is present at all . This
* defaults to FALSE . It is set to TRUE for stylesheets added via module and
2013-06-05 07:47:39 +00:00
* theme . info . yml files . Modules that add stylesheets within
* hook_page_build () implementations , or from other code that ensures that
* the stylesheet is added to all website pages , should also set this flag
* to TRUE . All stylesheets within the same group that have the 'every_page'
* flag set to TRUE and do not have 'preprocess' set to FALSE are aggregated
* together into a single aggregate file , and that aggregate file can be
* reused across a user ' s entire site visit , leading to faster navigation
* between pages .
* However , stylesheets that are only needed on pages less frequently
2010-10-05 19:59:10 +00:00
* visited , can be added by code that only runs for those particular pages ,
* and that code should not set the 'every_page' flag . This minimizes the
* size of the aggregate file that the user needs to download when first
* visiting the website . Stylesheets without the 'every_page' flag are
* aggregated into a separate aggregate file . This other aggregate file is
* likely to change from page to page , and each new aggregate file needs to
* be downloaded when first encountered , so it should be kept relatively
* small by ensuring that most commonly needed stylesheets are added to
* every page .
* - 'weight' : The weight of the stylesheet specifies the order in which the
2013-04-04 02:14:52 +00:00
* CSS will appear relative to other stylesheets with the same aggregate
* group and 'every_page' flag . The exact ordering of stylesheets is as
* follows :
* - First by aggregate group .
2010-10-05 19:59:10 +00:00
* - Then by the 'every_page' flag , with TRUE coming before FALSE .
* - Then by weight .
* - Then by the order in which the CSS was added . For example , all else
2014-01-08 06:44:57 +00:00
* being the same , a stylesheet added by a call to _drupal_add_css () that
2010-10-05 19:59:10 +00:00
* happened later in the page request gets added to the page after one for
2014-01-08 06:44:57 +00:00
* which _drupal_add_css () happened earlier in the page request .
2013-04-04 02:14:52 +00:00
* Available constants are :
* - CSS_BASE : Styles for HTML elements ( " base " styles ) .
* - CSS_LAYOUT : Styles that layout a page .
* - CSS_COMPONENT : Styles for design components ( and their associated
2014-03-04 18:04:01 +00:00
* states and themes . )
2013-04-04 02:14:52 +00:00
* - CSS_STATE : Styles for states that are not included with components .
2014-03-04 18:04:01 +00:00
* - CSS_THEME : Styles for themes that are not included with components .
2013-04-04 02:14:52 +00:00
* The weight numbers follow the SMACSS convention of CSS categorization .
* See http :// drupal . org / node / 1887922
2009-03-30 05:13:45 +00:00
* - 'media' : The media type for the stylesheet , e . g . , all , print , screen .
2013-04-04 02:14:52 +00:00
* Defaults to 'all' . It is extremely important to leave this set to 'all'
* or it will negatively impact front - end peformance . Instead add a @ media
* block to the included CSS file .
2010-07-30 02:47:28 +00:00
* - 'preprocess' : If TRUE and CSS aggregation / compression is enabled , the
2010-10-05 19:59:10 +00:00
* styles will be aggregated and compressed . Defaults to TRUE .
2010-02-25 20:57:39 +00:00
* - 'browsers' : An array containing information specifying which browsers
* should load the CSS item . See drupal_pre_render_conditional_comments ()
* for details .
2009-12-05 22:16:44 +00:00
*
2006-08-03 07:06:36 +00:00
* @ return
2009-03-30 05:13:45 +00:00
* An array of queued cascading stylesheets .
2011-05-30 05:41:06 +00:00
*
2013-06-29 18:23:50 +00:00
* @ deprecated as of Drupal 8.0 . Use the #attached key in render arrays instead.
*
2011-05-30 05:41:06 +00:00
* @ see drupal_get_css ()
2006-08-03 07:06:36 +00:00
*/
2014-01-08 06:44:57 +00:00
function _drupal_add_css ( $data = NULL , $options = NULL ) {
2009-05-16 13:26:31 +00:00
$css = & drupal_static ( __FUNCTION__ , array ());
2006-12-10 09:54:35 +00:00
2009-01-22 03:56:12 +00:00
// Construct the options, taking the defaults into consideration.
if ( isset ( $options )) {
if ( ! is_array ( $options )) {
$options = array ( 'type' => $options );
}
}
else {
$options = array ();
}
2006-12-10 09:54:35 +00:00
// Create an array of CSS files for each media type first, since each type needs to be served
// to the browser differently.
2009-03-30 05:13:45 +00:00
if ( isset ( $data )) {
2008-10-26 18:06:39 +00:00
$options += array (
2009-07-30 19:57:10 +00:00
'type' => 'file' ,
2013-04-04 02:14:52 +00:00
'group' => CSS_AGGREGATE_DEFAULT ,
2010-10-05 19:59:10 +00:00
'weight' => 0 ,
'every_page' => FALSE ,
2008-10-26 18:06:39 +00:00
'media' => 'all' ,
2010-10-05 19:59:10 +00:00
'preprocess' => TRUE ,
2009-07-30 19:57:10 +00:00
'data' => $data ,
2010-02-25 20:57:39 +00:00
'browsers' => array (),
);
$options [ 'browsers' ] += array (
'IE' => TRUE ,
'!IE' => TRUE ,
2008-10-29 10:06:06 +00:00
);
2008-10-26 18:06:39 +00:00
2010-10-05 19:59:10 +00:00
// Files with a query string cannot be preprocessed.
if ( $options [ 'type' ] === 'file' && $options [ 'preprocess' ] && strpos ( $options [ 'data' ], '?' ) !== FALSE ) {
$options [ 'preprocess' ] = FALSE ;
}
2009-07-30 19:57:10 +00:00
// Always add a tiny value to the weight, to conserve the insertion order.
$options [ 'weight' ] += count ( $css ) / 1000 ;
2006-08-03 07:06:36 +00:00
2009-07-30 19:57:10 +00:00
// Add the data to the CSS array depending on the type.
switch ( $options [ 'type' ]) {
case 'inline' :
// For inline stylesheets, we don't want to use the $data as the array
// key as $data could be a very long string of CSS.
$css [] = $options ;
break ;
2012-12-29 20:01:54 +00:00
case 'file' :
// Local CSS files are keyed by basename; if a file with the same
// basename is added more than once, it gets overridden.
// By default, take over the filename as basename.
if ( ! isset ( $options [ 'basename' ])) {
$options [ 'basename' ] = drupal_basename ( $data );
}
$css [ $options [ 'basename' ]] = $options ;
break ;
2009-08-14 16:15:38 +00:00
default :
2012-12-29 20:01:54 +00:00
// External files are keyed by their full URI, so the same CSS file is
// not added twice.
2009-08-14 16:15:38 +00:00
$css [ $data ] = $options ;
2007-05-27 17:57:48 +00:00
}
}
2007-05-27 20:31:13 +00:00
2006-08-03 07:06:36 +00:00
return $css ;
}
/**
2011-12-05 12:52:27 +00:00
* Returns a themed representation of all stylesheets to attach to the page .
2007-10-08 14:08:19 +00:00
*
2008-02-20 13:38:32 +00:00
* It loads the CSS in order , with 'module' first , then 'theme' afterwards .
* This ensures proper cascading of styles so themes can easily override
* module styles through CSS selectors .
*
* Themes may replace module - defined CSS files by adding a stylesheet with the
2010-08-08 19:35:49 +00:00
* same filename . For example , themes / bartik / system - menus . css would replace
2008-02-20 13:38:32 +00:00
* modules / system / system - menus . css . This allows themes to override complete
* CSS files , rather than specific selectors , when necessary .
*
2006-08-03 07:06:36 +00:00
* @ param $css
2007-10-08 14:08:19 +00:00
* ( optional ) An array of CSS files . If no array is provided , the default
* stylesheets array is used instead .
2010-10-04 17:46:01 +00:00
* @ param $skip_alter
2014-02-24 10:10:52 +00:00
* ( optional ) If set to TRUE , this function skips calling
* \Drupal :: moduleHandler -> alter () on $css , useful when the calling function
* passes a $css array that has already been altered .
2011-05-30 05:41:06 +00:00
*
2006-08-03 07:06:36 +00:00
* @ return
* A string of XHTML CSS tags .
2011-05-30 05:41:06 +00:00
*
2014-01-08 06:44:57 +00:00
* @ see _drupal_add_css ()
2006-08-03 07:06:36 +00:00
*/
2010-10-04 17:46:01 +00:00
function drupal_get_css ( $css = NULL , $skip_alter = FALSE ) {
2012-12-29 20:01:54 +00:00
global $theme_info ;
2006-12-10 09:54:35 +00:00
if ( ! isset ( $css )) {
2014-01-08 06:44:57 +00:00
$css = _drupal_add_css ();
2006-08-03 07:06:36 +00:00
}
2010-06-25 18:56:11 +00:00
// Allow modules and themes to alter the CSS items.
2010-10-04 17:46:01 +00:00
if ( ! $skip_alter ) {
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'css' , $css );
2010-10-04 17:46:01 +00:00
}
2009-07-30 19:57:10 +00:00
2010-10-05 19:59:10 +00:00
// Sort CSS items, so that they appear in the correct order.
uasort ( $css , 'drupal_sort_css_js' );
2009-07-30 19:57:10 +00:00
2012-12-29 20:01:54 +00:00
// Allow themes to remove CSS files by basename.
if ( ! empty ( $theme_info -> stylesheets_remove )) {
foreach ( $css as $key => $options ) {
if ( isset ( $options [ 'basename' ]) && isset ( $theme_info -> stylesheets_remove [ $options [ 'basename' ]])) {
unset ( $css [ $key ]);
}
}
}
// Allow themes to conditionally override CSS files by basename.
if ( ! empty ( $theme_info -> stylesheets_override )) {
foreach ( $css as $key => $options ) {
if ( isset ( $options [ 'basename' ]) && isset ( $theme_info -> stylesheets_override [ $options [ 'basename' ]])) {
$css [ $key ][ 'data' ] = $theme_info -> stylesheets_override [ $options [ 'basename' ]];
2008-02-20 13:38:32 +00:00
}
2009-07-30 19:57:10 +00:00
}
}
2010-02-25 20:57:39 +00:00
// Render the HTML needed to load the CSS.
$styles = array (
'#type' => 'styles' ,
'#items' => $css ,
);
2012-02-27 03:01:22 +00:00
if ( ! empty ( $setting )) {
2012-01-08 13:58:16 +00:00
$styles [ '#attached' ][ 'js' ][] = array ( 'type' => 'setting' , 'data' => $setting );
}
2010-10-04 17:46:01 +00:00
2010-02-25 20:57:39 +00:00
return drupal_render ( $styles );
}
2010-10-05 19:59:10 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sorts CSS and JavaScript resources .
*
* Callback for uasort () within :
* - drupal_get_css ()
* - drupal_get_js ()
2010-10-05 19:59:10 +00:00
*
* This sort order helps optimize front - end performance while providing modules
* and themes with the necessary control for ordering the CSS and JavaScript
* appearing on a page .
2011-12-05 12:52:27 +00:00
*
* @ param $a
* First item for comparison . The compared items should be associative arrays
2014-01-08 06:44:57 +00:00
* of member items from _drupal_add_css () or _drupal_add_js () .
2011-12-05 12:52:27 +00:00
* @ param $b
* Second item for comparison .
*
2014-01-08 06:44:57 +00:00
* @ see _drupal_add_css ()
* @ see _drupal_add_js ()
2010-10-05 19:59:10 +00:00
*/
function drupal_sort_css_js ( $a , $b ) {
2013-06-14 13:33:02 +00:00
// First order by group, so that all items in the CSS_AGGREGATE_DEFAULT group
// appear before items in the CSS_AGGREGATE_THEME group. Modules may create
// additional groups by defining their own constants.
2010-10-05 19:59:10 +00:00
if ( $a [ 'group' ] < $b [ 'group' ]) {
return - 1 ;
}
elseif ( $a [ 'group' ] > $b [ 'group' ]) {
return 1 ;
}
// Within a group, order all infrequently needed, page-specific files after
// common files needed throughout the website. Separating this way allows for
// the aggregate file generated for all of the common files to be reused
// across a site visit without being cut by a page using a less common file.
elseif ( $a [ 'every_page' ] && ! $b [ 'every_page' ]) {
return - 1 ;
}
elseif ( ! $a [ 'every_page' ] && $b [ 'every_page' ]) {
return 1 ;
}
// Finally, order by weight.
elseif ( $a [ 'weight' ] < $b [ 'weight' ]) {
return - 1 ;
}
elseif ( $a [ 'weight' ] > $b [ 'weight' ]) {
return 1 ;
}
else {
return 0 ;
}
}
2010-02-25 20:57:39 +00:00
/**
2011-12-05 12:52:27 +00:00
* Pre - render callback : Adds the elements needed for CSS tags to be rendered .
2010-02-25 20:57:39 +00:00
*
* For production websites , LINK tags are preferable to STYLE tags with @ import
* statements , because :
* - They are the standard tag intended for linking to a resource .
* - On Firefox 2 and perhaps other browsers , CSS files included with @ import
* statements don ' t get saved when saving the complete web page for offline
* use : http :// drupal . org / node / 145218.
* - On IE , if only LINK tags and no @ import statements are used , all the CSS
* files are downloaded in parallel , resulting in faster page load , but if
* @ import statements are used and span across multiple STYLE tags , all the
* ones from one STYLE tag must be downloaded before downloading begins for
* the next STYLE tag . Furthermore , IE7 does not support media declaration on
* the @ import statement , so multiple STYLE tags must be used when different
* files are for different media types . Non - IE browsers always download in
* parallel , so this is an IE - specific performance quirk :
* http :// www . stevesouders . com / blog / 2009 / 04 / 09 / dont - use - import /.
*
* However , IE has an annoying limit of 31 total CSS inclusion tags
* ( http :// drupal . org / node / 228818 ) and LINK tags are limited to one file per
* tag , whereas STYLE tags can contain multiple @ import statements allowing
* multiple files to be loaded per tag . When CSS aggregation is disabled , a
* Drupal site can easily have more than 31 CSS files that need to be loaded , so
* using LINK tags exclusively would result in a site that would display
* incorrectly in IE . Depending on different needs , different strategies can be
* employed to decide when to use LINK tags and when to use STYLE tags .
*
* The strategy employed by this function is to use LINK tags for all aggregate
* files and for all files that cannot be aggregated ( e . g . , if 'preprocess' is
* set to FALSE or the type is 'external' ), and to use STYLE tags for groups
* of files that could be aggregated together but aren ' t ( e . g . , if the site - wide
* aggregation setting is disabled ) . This results in all LINK tags when
* aggregation is enabled , a guarantee that as many or only slightly more tags
* are used with aggregation disabled than enabled ( so that if the limit were to
* be crossed with aggregation enabled , the site developer would also notice the
* problem while aggregation is disabled ), and an easy way for a developer to
* view HTML source while aggregation is disabled and know what files will be
* aggregated together when aggregation becomes enabled .
*
* This function evaluates the aggregation enabled / disabled condition on a group
* by group basis by testing whether an aggregate file has been made for the
* group rather than by testing the site - wide aggregation setting . This allows
* this function to work correctly even if modules have implemented custom
* logic for grouping and aggregating files .
*
* @ param $element
* A render array containing :
2014-01-08 06:44:57 +00:00
* - '#items' : The CSS items as returned by _drupal_add_css () and altered by
2010-02-25 20:57:39 +00:00
* drupal_get_css () .
*
* @ return
* A render array that will render to a string of XHTML CSS tags .
*
* @ see drupal_get_css ()
*/
function drupal_pre_render_styles ( $elements ) {
2013-07-04 08:38:19 +00:00
$css_assets = $elements [ '#items' ];
2007-12-07 11:14:05 +00:00
2013-07-04 08:38:19 +00:00
// Aggregate the CSS if necessary, but only during normal site operation.
2013-09-16 03:58:06 +00:00
if ( ! defined ( 'MAINTENANCE_MODE' ) && \Drupal :: config ( 'system.performance' ) -> get ( 'css.preprocess' )) {
2013-07-04 08:38:19 +00:00
$css_assets = \Drupal :: service ( 'asset.css.collection_optimizer' ) -> optimize ( $css_assets );
2007-12-07 11:14:05 +00:00
}
2013-07-04 08:38:19 +00:00
return \Drupal :: service ( 'asset.css.collection_renderer' ) -> render ( $css_assets );
2007-12-07 11:14:05 +00:00
}
2006-12-10 09:54:35 +00:00
/**
2010-05-09 19:44:25 +00:00
* Deletes old cached CSS files .
2006-12-10 09:54:35 +00:00
*/
function drupal_clear_css_cache () {
2013-09-16 03:58:06 +00:00
\Drupal :: state () -> delete ( 'drupal_css_cache_files' );
2010-05-09 19:44:25 +00:00
file_scan_directory ( 'public://css' , '/.*/' , array ( 'callback' => 'drupal_delete_file_if_stale' ));
}
/**
2011-12-05 12:52:27 +00:00
* Deletes files modified more than a set time ago .
*
* Callback for file_scan_directory () within :
* - drupal_clear_css_cache ()
* - drupal_clear_js_cache ()
2010-05-09 19:44:25 +00:00
*/
function drupal_delete_file_if_stale ( $uri ) {
// Default stale file threshold is 30 days.
2013-09-16 03:58:06 +00:00
if ( REQUEST_TIME - filemtime ( $uri ) > \Drupal :: config ( 'system.performance' ) -> get ( 'stale_file_threshold' )) {
2010-05-09 19:44:25 +00:00
file_unmanaged_delete ( $uri );
}
2006-08-03 07:06:36 +00:00
}
2009-10-03 19:16:04 +00:00
/**
2011-12-05 12:52:27 +00:00
* Prepares a string for use as a CSS identifier ( element , class , or ID name ) .
2009-10-03 19:16:04 +00:00
*
* http :// www . w3 . org / TR / CSS21 / syndata . html #characters shows the syntax for valid
2009-10-09 08:08:56 +00:00
* CSS identifiers ( including element names , classes , and IDs in selectors . )
2009-10-03 19:16:04 +00:00
*
* @ param $identifier
2009-10-05 01:18:26 +00:00
* The identifier to clean .
2009-10-03 19:16:04 +00:00
* @ param $filter
* An array of string replacements to use on the identifier .
2011-12-05 12:52:27 +00:00
*
2009-10-03 19:16:04 +00:00
* @ return
* The cleaned identifier .
*/
2013-06-13 21:37:02 +00:00
function drupal_clean_css_identifier ( $identifier , $filter = array ( ' ' => '-' , '_' => '-' , '__' => '__' , '/' => '-' , '[' => '-' , ']' => '' )) {
2009-10-03 19:16:04 +00:00
// By default, we filter using Drupal's coding standards.
$identifier = strtr ( $identifier , $filter );
2009-10-09 08:08:56 +00:00
// Valid characters in a CSS identifier are:
2009-10-03 19:16:04 +00:00
// - the hyphen (U+002D)
// - a-z (U+0030 - U+0039)
// - A-Z (U+0041 - U+005A)
// - the underscore (U+005F)
// - 0-9 (U+0061 - U+007A)
// - ISO 10646 characters U+00A1 and higher
// We strip out any character not in the above list.
$identifier = preg_replace ( '/[^\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]/u' , '' , $identifier );
2013-12-11 07:02:15 +00:00
// Identifiers cannot start with a digit, two hyphens, or a hyphen followed by a digit.
$identifier = preg_replace ( array ( '/^[0-9]/' , '/^(-[0-9])|^(--)/' ), array ( '_' , '__' ) , $identifier );
2009-10-03 19:16:04 +00:00
return $identifier ;
}
/**
2011-12-05 12:52:27 +00:00
* Prepares a string for use as a valid class name .
2009-10-03 19:16:04 +00:00
*
* Do not pass one string containing multiple classes as they will be
* incorrectly concatenated with dashes , i . e . " one two " will become " one-two " .
*
* @ param $class
* The class name to clean .
2011-12-05 12:52:27 +00:00
*
2009-10-03 19:16:04 +00:00
* @ return
* The cleaned class name .
*/
2009-10-05 01:18:26 +00:00
function drupal_html_class ( $class ) {
2013-05-07 21:35:49 +00:00
// The output of this function will never change, so this uses a normal
// static instead of drupal_static().
static $classes = array ();
if ( ! isset ( $classes [ $class ])) {
$classes [ $class ] = drupal_clean_css_identifier ( drupal_strtolower ( $class ));
}
return $classes [ $class ];
2009-10-03 19:16:04 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Prepares a string for use as a valid HTML ID and guarantees uniqueness .
2009-10-03 19:16:04 +00:00
*
2010-04-07 17:30:43 +00:00
* This function ensures that each passed HTML ID value only exists once on the
* page . By tracking the already returned ids , this function enables forms ,
* blocks , and other content to be output multiple times on the same page ,
* without breaking ( X ) HTML validation .
*
2011-02-19 00:09:11 +00:00
* For already existing IDs , a counter is appended to the ID string . Therefore ,
2010-04-07 17:30:43 +00:00
* JavaScript and CSS code should not rely on any value that was generated by
* this function and instead should rely on manually added CSS classes or
* similarly reliable constructs .
*
2011-02-19 00:09:11 +00:00
* Two consecutive hyphens separate the counter from the original ID . To manage
* uniqueness across multiple Ajax requests on the same page , Ajax requests
2010-04-07 17:30:43 +00:00
* POST an array of all IDs currently present on the page , which are used to
* prime this function ' s cache upon first invocation .
*
2011-02-19 00:09:11 +00:00
* To allow reverse - parsing of IDs submitted via Ajax , any multiple consecutive
2010-04-07 17:30:43 +00:00
* hyphens in the originally passed $id are replaced with a single hyphen .
*
2009-10-03 19:16:04 +00:00
* @ param $id
* The ID to clean .
2010-04-07 17:30:43 +00:00
*
2009-10-03 19:16:04 +00:00
* @ return
* The cleaned ID .
*/
2009-10-05 01:18:26 +00:00
function drupal_html_id ( $id ) {
2011-02-19 00:09:11 +00:00
// If this is an Ajax request, then content returned by this page request will
// be merged with content already on the base page. The HTML IDs must be
2010-04-07 17:30:43 +00:00
// unique for the fully merged content. Therefore, initialize $seen_ids to
2011-02-19 00:09:11 +00:00
// take into account IDs that are already in use on the base page.
2010-04-07 17:30:43 +00:00
$seen_ids_init = & drupal_static ( __FUNCTION__ . ':init' );
if ( ! isset ( $seen_ids_init )) {
2013-12-05 18:02:36 +00:00
$ajax_html_ids = \Drupal :: request () -> request -> get ( 'ajax_html_ids' );
2010-04-07 17:30:43 +00:00
// Ideally, Drupal would provide an API to persist state information about
// prior page requests in the database, and we'd be able to add this
// function's $seen_ids static variable to that state information in order
// to have it properly initialized for this page request. However, no such
// page state API exists, so instead, ajax.js adds all of the in-use HTML
2011-02-19 00:09:11 +00:00
// IDs to the POST data of Ajax submissions. Direct use of $_POST is
2010-04-07 17:30:43 +00:00
// normally not recommended as it could open up security risks, but because
// the raw POST data is cast to a number before being returned by this
// function, this usage is safe.
2013-12-05 18:02:36 +00:00
if ( empty ( $ajax_html_ids )) {
2010-04-07 17:30:43 +00:00
$seen_ids_init = array ();
}
else {
// This function ensures uniqueness by appending a counter to the base id
// requested by the calling function after the first occurrence of that
// requested id. $_POST['ajax_html_ids'] contains the ids as they were
// returned by this function, potentially with the appended counter, so
// we parse that to reconstruct the $seen_ids array.
2013-12-05 18:02:36 +00:00
$ajax_html_ids = explode ( ' ' , $ajax_html_ids );
2012-09-24 09:33:31 +00:00
foreach ( $ajax_html_ids as $seen_id ) {
2010-04-07 17:30:43 +00:00
// We rely on '--' being used solely for separating a base id from the
// counter, which this function ensures when returning an id.
$parts = explode ( '--' , $seen_id , 2 );
if ( ! empty ( $parts [ 1 ]) && is_numeric ( $parts [ 1 ])) {
list ( $seen_id , $i ) = $parts ;
}
else {
$i = 1 ;
}
if ( ! isset ( $seen_ids_init [ $seen_id ]) || ( $i > $seen_ids_init [ $seen_id ])) {
$seen_ids_init [ $seen_id ] = $i ;
}
}
}
}
$seen_ids = & drupal_static ( __FUNCTION__ , $seen_ids_init );
2014-02-27 19:52:40 +00:00
$id = drupal_clean_id_identifier ( $id );
2010-04-07 17:30:43 +00:00
// Ensure IDs are unique by appending a counter after the first occurrence.
// The counter needs to be appended with a delimiter that does not exist in
// the base ID. Requiring a unique delimiter helps ensure that we really do
// return unique IDs and also helps us re-create the $seen_ids array during
2011-02-19 00:09:11 +00:00
// Ajax requests.
2009-10-03 19:16:04 +00:00
if ( isset ( $seen_ids [ $id ])) {
2010-04-07 17:30:43 +00:00
$id = $id . '--' . ++ $seen_ids [ $id ];
2009-10-03 19:16:04 +00:00
}
else {
$seen_ids [ $id ] = 1 ;
}
return $id ;
}
2014-02-27 19:52:40 +00:00
/**
* Prepares a string for use as a valid HTML ID .
*
* Only use this function when you want to intentionally skip the uniqueness
* guarantee of drupal_html_id () .
*
* @ param string $id
* The ID to clean .
*
* @ return string
* The cleaned ID .
*
* @ see drupal_html_id ()
*/
function drupal_clean_id_identifier ( $id ) {
$id = strtr ( drupal_strtolower ( $id ), array ( ' ' => '-' , '_' => '-' , '[' => '-' , ']' => '' ));
// As defined in http://www.w3.org/TR/html4/types.html#type-name, HTML IDs can
// only contain letters, digits ([0-9]), hyphens ("-"), underscores ("_"),
// colons (":"), and periods ("."). We strip out any character not in that
// list. Note that the CSS spec doesn't allow colons or periods in identifiers
// (http://www.w3.org/TR/CSS21/syndata.html#characters), so we strip those two
// characters as well.
$id = preg_replace ( '/[^A-Za-z0-9\-_]/' , '' , $id );
// Removing multiple consecutive hyphens.
$id = preg_replace ( '/\-+/' , '-' , $id );
return $id ;
}
2005-05-24 06:00:22 +00:00
/**
2010-03-27 05:55:24 +00:00
* Adds a JavaScript file , setting , or inline code to the page .
2005-05-24 06:00:22 +00:00
*
2006-08-22 09:00:31 +00:00
* The behavior of this function depends on the parameters it is called with .
* Generally , it handles the addition of JavaScript to the page , either as
* reference to an existing file or as inline code . The following actions can be
* performed using this function :
2010-03-27 05:55:24 +00:00
* - Add a file ( 'file' ) : Adds a reference to a JavaScript file to the page .
* - Add inline JavaScript code ( 'inline' ) : Executes a piece of JavaScript code
* on the current page by placing the code directly in the page ( for example ,
* to tell the user that a new message arrived , by opening a pop up , alert
* box , etc . ) . This should only be used for JavaScript that cannot be executed
* from a file . When adding inline code , make sure that you are not relying on
2011-12-05 12:52:27 +00:00
* $ () being the jQuery function . Wrap your code in
2010-03-27 05:55:24 +00:00
* @ code ( function ( $ ) { ... })( jQuery ); @ endcode
* or use jQuery () instead of $ () .
* - Add external JavaScript ( 'external' ) : Allows the inclusion of external
* JavaScript files that are not hosted on the local server . Note that these
* external JavaScript references do not get aggregated when preprocessing is
* on .
* - Add settings ( 'setting' ) : Adds settings to Drupal ' s global storage of
* JavaScript settings . Per - page settings are required by some modules to
2013-09-21 23:39:42 +00:00
* function properly . All settings will be accessible at drupalSettings .
2006-08-22 09:00:31 +00:00
*
2008-10-22 19:39:36 +00:00
* Examples :
* @ code
2014-01-08 06:44:57 +00:00
* _drupal_add_js ( 'core/misc/collapse.js' );
* _drupal_add_js ( 'core/misc/collapse.js' , 'file' );
* _drupal_add_js ( 'jQuery(document).ready(function () { alert("Hello!"); });' , 'inline' );
* _drupal_add_js ( 'jQuery(document).ready(function () { alert("Hello!"); });' ,
2008-11-10 05:23:01 +00:00
* array ( 'type' => 'inline' , 'scope' => 'footer' , 'weight' => 5 )
2008-10-22 19:39:36 +00:00
* );
2014-01-08 06:44:57 +00:00
* _drupal_add_js ( 'http://example.com/example.js' , 'external' );
* _drupal_add_js ( array ( 'myModule' => array ( 'key' => 'value' )), 'setting' );
2008-10-22 19:39:36 +00:00
* @ endcode
*
2014-01-08 06:44:57 +00:00
* Calling drupal_static_reset ( '_drupal_add_js' ) will clear all JavaScript added
2009-05-16 13:26:31 +00:00
* so far .
*
2010-07-30 02:47:28 +00:00
* If JavaScript aggregation is enabled , all JavaScript files added with
* $options [ 'preprocess' ] set to TRUE will be merged into one aggregate file .
* Preprocessed inline JavaScript will not be aggregated into this single file .
* Externally hosted JavaScripts are never aggregated .
*
* The reason for aggregating the files is outlined quite thoroughly here :
* http :// www . die . net / musings / page_load_time / " Load fewer external objects. Due
* to request overhead , one bigger file just loads faster than two smaller ones
* half its size . "
*
* $options [ 'preprocess' ] should be only set to TRUE when a file is required for
* all typical visitors and most pages of a site . It is critical that all
* preprocessed files are added unconditionally on every page , even if the
* files are not needed on a page . This is normally done by calling
2014-01-08 06:44:57 +00:00
* _drupal_add_js () in a hook_page_build () implementation .
2010-07-30 02:47:28 +00:00
*
* Non - preprocessed files should only be added to the page when they are
* actually needed .
*
2006-08-22 09:00:31 +00:00
* @ param $data
2012-11-07 15:19:48 +00:00
* ( optional ) If given , the value depends on the $options parameter , or
* $options [ 'type' ] if $options is passed as an associative array :
2008-11-10 05:23:01 +00:00
* - 'file' : Path to the file relative to base_path () .
2006-08-22 09:00:31 +00:00
* - 'inline' : The JavaScript code that should be placed in the given scope .
2009-08-14 16:15:38 +00:00
* - 'external' : The absolute path to an external JavaScript file that is not
2009-08-24 00:14:23 +00:00
* hosted on the local server . These files will not be aggregated if
2009-08-14 16:15:38 +00:00
* JavaScript aggregation is enabled .
2010-03-27 05:55:24 +00:00
* - 'setting' : An associative array with configuration options . The array is
2013-09-21 23:39:42 +00:00
* merged directly into drupalSettings . All modules should wrap their
2010-11-20 05:02:46 +00:00
* actual configuration settings in another variable to prevent conflicts in
2013-09-21 23:39:42 +00:00
* the drupalSettings namespace . Items added with a string key will replace
2010-11-20 05:02:46 +00:00
* existing settings with that key ; items with numeric array keys will be
* added to the existing settings array .
2008-10-22 19:39:36 +00:00
* @ param $options
2010-03-27 05:55:24 +00:00
* ( optional ) A string defining the type of JavaScript that is being added in
* the $data parameter ( 'file' / 'setting' / 'inline' / 'external' ), or an
* associative array . JavaScript settings should always pass the string
* 'setting' only . Other types can have the following elements in the array :
* - type : The type of JavaScript that is to be added to the page . Allowed
* values are 'file' , 'inline' , 'external' or 'setting' . Defaults
* to 'file' .
* - scope : The location in which you want to place the script . Possible
* values are 'header' or 'footer' . If your theme implements different
* regions , you can also use these . Defaults to 'header' .
2010-10-20 00:45:39 +00:00
* - group : A number identifying the group in which to add the JavaScript .
2010-10-05 19:59:10 +00:00
* Available constants are :
2010-03-27 05:55:24 +00:00
* - JS_LIBRARY : Any libraries , settings , or jQuery plugins .
* - JS_DEFAULT : Any module - layer JavaScript .
* - JS_THEME : Any theme - layer JavaScript .
2010-10-05 19:59:10 +00:00
* The group number serves as a weight : JavaScript within a lower weight
* group is presented on the page before JavaScript within a higher weight
* group .
2010-10-20 00:45:39 +00:00
* - every_page : For optimal front - end performance when aggregation is
2010-10-05 19:59:10 +00:00
* enabled , this should be set to TRUE if the JavaScript is present on every
* page of the website for users for whom it is present at all . This
* defaults to FALSE . It is set to TRUE for JavaScript files that are added
2013-03-06 22:51:39 +00:00
* via module and theme . info . yml files . Modules that add JavaScript within
2013-06-05 07:47:39 +00:00
* hook_page_build () implementations , or from other code that ensures that
* the JavaScript is added to all website pages , should also set this flag
* to TRUE . All JavaScript files within the same group and that have the
2010-10-05 19:59:10 +00:00
* 'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE
* are aggregated together into a single aggregate file , and that aggregate
* file can be reused across a user ' s entire site visit , leading to faster
* navigation between pages . However , JavaScript that is only needed on
* pages less frequently visited , can be added by code that only runs for
* those particular pages , and that code should not set the 'every_page'
* flag . This minimizes the size of the aggregate file that the user needs
* to download when first visiting the website . JavaScript without the
* 'every_page' flag is aggregated into a separate aggregate file . This
* other aggregate file is likely to change from page to page , and each new
* aggregate file needs to be downloaded when first encountered , so it
* should be kept relatively small by ensuring that most commonly needed
* JavaScript is added to every page .
* - weight : A number defining the order in which the JavaScript is added to
* the page relative to other JavaScript with the same 'scope' , 'group' ,
* and 'every_page' value . In some cases , the order in which the JavaScript
* is presented on the page is very important . jQuery , for example , must be
* added to the page before any jQuery code is run , so jquery . js uses the
* JS_LIBRARY group and a weight of - 20 , jquery . once . js ( a library drupal . js
* depends on ) uses the JS_LIBRARY group and a weight of - 19 , drupal . js uses
* the JS_LIBRARY group and a weight of - 1 , other libraries use the
* JS_LIBRARY group and a weight of 0 or higher , and all other scripts use
* one of the other group constants . The exact ordering of JavaScript is as
* follows :
* - First by scope , with 'header' first , 'footer' last , and any other
* scopes provided by a custom theme coming in between , as determined by
* the theme .
* - Then by group .
* - Then by the 'every_page' flag , with TRUE coming before FALSE .
* - Then by weight .
* - Then by the order in which the JavaScript was added . For example , all
2014-01-08 06:44:57 +00:00
* else being the same , JavaScript added by a call to _drupal_add_js () that
2010-10-05 19:59:10 +00:00
* happened later in the page request gets added to the page after one for
2014-01-08 06:44:57 +00:00
* which _drupal_add_js () happened earlier in the page request .
2010-03-27 05:55:24 +00:00
* - cache : If set to FALSE , the JavaScript file is loaded anew on every page
* call ; in other words , it is not cached . Used only when 'type' references
* a JavaScript file . Defaults to TRUE .
2010-07-30 02:47:28 +00:00
* - preprocess : If TRUE and JavaScript aggregation is enabled , the script
2010-10-05 19:59:10 +00:00
* file will be aggregated . Defaults to TRUE .
2012-11-03 00:44:03 +00:00
* - attributes : An associative array of attributes for the < script > tag . This
* may be used to add 'defer' , 'async' , or custom attributes . Note that
* setting any attributes will disable preprocessing as though the
* 'preprocess' option was set to FALSE .
2011-11-03 11:00:04 +00:00
* - browsers : An array containing information specifying which browsers
* should load the JavaScript item . See
* drupal_pre_render_conditional_comments () for details .
2010-03-27 05:55:24 +00:00
*
2006-08-22 09:00:31 +00:00
* @ return
2010-03-27 05:55:24 +00:00
* The current array of JavaScript files , settings , and in - line code ,
* including Drupal defaults , anything previously added with calls to
2014-01-08 06:44:57 +00:00
* _drupal_add_js (), and this function call ' s additions .
2010-03-27 05:55:24 +00:00
*
2013-06-29 18:23:50 +00:00
* @ deprecated as of Drupal 8.0 . Use the #attached key in render arrays instead.
*
2008-10-22 19:39:36 +00:00
* @ see drupal_get_js ()
2005-05-24 06:00:22 +00:00
*/
2014-01-08 06:44:57 +00:00
function _drupal_add_js ( $data = NULL , $options = NULL ) {
2009-05-16 13:26:31 +00:00
$javascript = & drupal_static ( __FUNCTION__ , array ());
2006-01-29 07:36:29 +00:00
2008-10-22 19:39:36 +00:00
// Construct the options, taking the defaults into consideration.
if ( isset ( $options )) {
if ( ! is_array ( $options )) {
$options = array ( 'type' => $options );
}
}
else {
$options = array ();
}
2008-11-23 16:00:08 +00:00
$options += drupal_js_defaults ( $data );
2012-11-03 00:44:03 +00:00
// Preprocess can only be set if caching is enabled and no attributes are set.
$options [ 'preprocess' ] = $options [ 'cache' ] && empty ( $options [ 'attributes' ]) ? $options [ 'preprocess' ] : FALSE ;
2008-10-22 19:39:36 +00:00
2009-07-10 05:45:56 +00:00
// Tweak the weight so that files of the same weight are included in the
2014-01-08 06:44:57 +00:00
// order of the calls to _drupal_add_js().
2009-07-10 05:45:56 +00:00
$options [ 'weight' ] += count ( $javascript ) / 1000 ;
2008-10-22 19:39:36 +00:00
if ( isset ( $data )) {
2008-11-10 05:23:01 +00:00
switch ( $options [ 'type' ]) {
2006-08-22 09:00:31 +00:00
case 'setting' :
2012-08-30 19:24:38 +00:00
// If the setting array doesn't exist, add defaults values.
if ( ! isset ( $javascript [ 'settings' ])) {
$javascript [ 'settings' ] = array (
'type' => 'setting' ,
'scope' => 'header' ,
'group' => JS_SETTING ,
'every_page' => TRUE ,
'weight' => 0 ,
'browsers' => array (),
);
// url() generates the script and prefix using hook_url_outbound_alter().
// Instead of running the hook_url_outbound_alter() again here, extract
// them from url().
// @todo Make this less hacky: http://drupal.org/node/1547376.
$scriptPath = $GLOBALS [ 'script_path' ];
$pathPrefix = '' ;
2014-01-23 18:04:41 +00:00
$current_query = \Drupal :: service ( 'request' ) -> query -> all ();
2012-08-30 19:24:38 +00:00
url ( '' , array ( 'script' => & $scriptPath , 'prefix' => & $pathPrefix ));
2013-11-26 22:06:57 +00:00
$current_path = current_path ();
$current_path_is_admin = FALSE ;
// The function path_is_admin() is not available on update.php pages.
2014-03-21 12:35:45 +00:00
if ( ! ( defined ( 'MAINTENANCE_MODE' ))) {
$current_path_is_admin = \Drupal :: service ( 'router.admin_context' ) -> isAdminRoute ();
2013-11-26 22:06:57 +00:00
}
2014-01-23 18:04:41 +00:00
$path = array (
2012-08-30 19:24:38 +00:00
'basePath' => base_path (),
'scriptPath' => $scriptPath ,
'pathPrefix' => $pathPrefix ,
2013-11-26 22:06:57 +00:00
'currentPath' => $current_path ,
'currentPathIsAdmin' => $current_path_is_admin ,
2014-01-23 18:04:41 +00:00
'isFront' => drupal_is_front_page (),
'currentLanguage' => \Drupal :: languageManager () -> getCurrentLanguage ( Language :: TYPE_URL ) -> id ,
2012-08-30 19:24:38 +00:00
);
2014-01-23 18:04:41 +00:00
if ( ! empty ( $current_query )) {
ksort ( $current_query );
$path [ 'currentQuery' ] = ( object ) $current_query ;
}
$javascript [ 'settings' ][ 'data' ][] = array ( 'path' => $path );
2012-08-30 19:24:38 +00:00
}
2008-11-10 05:23:01 +00:00
// All JavaScript settings are placed in the header of the page with
// the library weight so that inline scripts appear afterwards.
$javascript [ 'settings' ][ 'data' ][] = $data ;
2006-08-22 09:00:31 +00:00
break ;
2008-11-10 05:23:01 +00:00
2006-08-22 09:00:31 +00:00
case 'inline' :
2008-11-10 05:23:01 +00:00
$javascript [] = $options ;
2006-08-22 09:00:31 +00:00
break ;
2009-02-28 07:36:06 +00:00
default : // 'file' and 'external'
// Local and external files must keep their name as the associative key
2011-02-19 00:09:11 +00:00
// so the same JavaScript file is not added twice.
2008-11-10 05:23:01 +00:00
$javascript [ $options [ 'data' ]] = $options ;
}
2007-06-08 12:51:59 +00:00
}
2008-11-10 05:23:01 +00:00
return $javascript ;
2005-05-24 06:00:22 +00:00
}
2008-11-23 16:00:08 +00:00
/**
* Constructs an array of the defaults that are used for JavaScript items .
*
* @ param $data
* ( optional ) The default data parameter for the JavaScript item array .
2011-12-05 12:52:27 +00:00
*
2008-11-23 16:00:08 +00:00
* @ see drupal_get_js ()
2014-01-08 06:44:57 +00:00
* @ see _drupal_add_js ()
2008-11-23 16:00:08 +00:00
*/
function drupal_js_defaults ( $data = NULL ) {
return array (
'type' => 'file' ,
2010-10-05 19:59:10 +00:00
'group' => JS_DEFAULT ,
'every_page' => FALSE ,
'weight' => 0 ,
2008-11-23 16:00:08 +00:00
'scope' => 'header' ,
'cache' => TRUE ,
2010-10-05 19:59:10 +00:00
'preprocess' => TRUE ,
2012-11-03 00:44:03 +00:00
'attributes' => array (),
2010-03-09 03:39:44 +00:00
'version' => NULL ,
2008-11-23 16:00:08 +00:00
'data' => $data ,
2011-11-03 11:00:04 +00:00
'browsers' => array (),
2008-11-23 16:00:08 +00:00
);
}
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
/**
2006-08-22 09:00:31 +00:00
* Returns a themed presentation of all JavaScript code for the current page .
2007-10-08 14:08:19 +00:00
*
2006-08-22 09:00:31 +00:00
* References to JavaScript files are placed in a certain order : first , all
* 'core' files , then all 'module' and finally all 'theme' JavaScript files
* are added to the page . Then , all settings are output , followed by 'inline'
2007-11-16 15:35:24 +00:00
* JavaScript code . If running update . php , all preprocessing is disabled .
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
*
2008-11-23 16:00:08 +00:00
* Note that hook_js_alter ( & $javascript ) is called during this function call
* to allow alterations of the JavaScript during its presentation . Calls to
2014-01-08 06:44:57 +00:00
* _drupal_add_js () from hook_js_alter () will not be added to the output
2008-11-23 16:00:08 +00:00
* presentation . The correct way to add JavaScript during hook_js_alter ()
* is to add another element to the $javascript array , deriving from
* drupal_js_defaults () . See locale_js_alter () for an example of this .
*
2008-05-14 13:15:09 +00:00
* @ param $scope
2006-08-22 09:00:31 +00:00
* ( optional ) The scope for which the JavaScript rules should be returned .
* Defaults to 'header' .
2008-05-14 13:15:09 +00:00
* @ param $javascript
2006-08-22 09:00:31 +00:00
* ( optional ) An array with all JavaScript code . Defaults to the default
* JavaScript array for the given scope .
2013-08-12 02:10:59 +00:00
* @ param bool $skip_alter
2014-02-24 10:10:52 +00:00
* ( optional ) If set to TRUE , this function skips calling
* \Drupal :: moduleHandler -> alter () on $javascript , useful when the calling
* function passes a $javascript array that has already been altered .
2013-08-12 02:10:59 +00:00
* @ param bool $is_ajax
* ( optional ) If set to TRUE , this function is called from an Ajax request and
* adds javascript settings to update ajaxPageState values .
2011-12-05 12:52:27 +00:00
*
2006-08-22 09:00:31 +00:00
* @ return
* All JavaScript code segments and includes for the scope as HTML tags .
2011-12-05 12:52:27 +00:00
*
2014-01-08 06:44:57 +00:00
* @ see _drupal_add_js ()
2008-11-23 16:00:08 +00:00
* @ see locale_js_alter ()
* @ see drupal_js_defaults ()
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
*/
2013-08-12 02:10:59 +00:00
function drupal_get_js ( $scope = 'header' , $javascript = NULL , $skip_alter = FALSE , $is_ajax = FALSE ) {
2007-06-01 09:05:45 +00:00
if ( ! isset ( $javascript )) {
2014-01-08 06:44:57 +00:00
$javascript = _drupal_add_js ();
2006-08-22 09:00:31 +00:00
}
2007-11-30 15:31:13 +00:00
if ( empty ( $javascript )) {
2007-06-01 09:05:45 +00:00
return '' ;
2007-06-04 07:22:23 +00:00
}
2008-11-23 16:00:08 +00:00
// Allow modules to alter the JavaScript.
2010-10-04 17:46:01 +00:00
if ( ! $skip_alter ) {
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'js' , $javascript );
2010-10-04 17:46:01 +00:00
}
2008-11-23 16:00:08 +00:00
2008-11-10 05:23:01 +00:00
// Filter out elements of the given scope.
$items = array ();
2010-10-04 17:46:01 +00:00
foreach ( $javascript as $key => $item ) {
2008-11-10 05:23:01 +00:00
if ( $item [ 'scope' ] == $scope ) {
2010-10-04 17:46:01 +00:00
$items [ $key ] = $item ;
2008-11-10 05:23:01 +00:00
}
}
2012-08-30 19:24:38 +00:00
if ( ! empty ( $items )) {
// Sort the JavaScript files so that they appear in the correct order.
uasort ( $items , 'drupal_sort_css_js' );
// Don't add settings if there is no other JavaScript on the page, unless
// this is an AJAX request.
2013-08-12 02:10:59 +00:00
if ( ! empty ( $items [ 'settings' ]) || $is_ajax ) {
2012-08-30 19:24:38 +00:00
global $theme_key ;
// Provide the page with information about the theme that's used, so that
// a later AJAX request can be rendered using the same theme.
2013-12-17 11:03:15 +00:00
// @see \Drupal\Core\Theme\AjaxBasePageNegotiator
2012-08-30 19:24:38 +00:00
$setting [ 'ajaxPageState' ][ 'theme' ] = $theme_key ;
// Checks that the DB is available before filling theme_token.
if ( ! defined ( 'MAINTENANCE_MODE' )) {
$setting [ 'ajaxPageState' ][ 'theme_token' ] = drupal_get_token ( $theme_key );
}
// Provide the page with information about the individual JavaScript files
// used, information not otherwise available when aggregation is enabled.
2013-01-02 16:36:51 +00:00
$setting [ 'ajaxPageState' ][ 'js' ] = array_fill_keys ( array_keys ( $javascript ), 1 );
2012-08-30 19:24:38 +00:00
unset ( $setting [ 'ajaxPageState' ][ 'js' ][ 'settings' ]);
// Provide the page with information about the individual CSS files used,
// information not otherwise available when CSS aggregation is enabled.
// The setting is attached later in this function, but is set here, so
// that CSS files removed in drupal_process_attached() are still
// considered "used" and prevented from being added in a later AJAX
// request.
// Skip if no files were added to the page otherwise jQuery.extend() will
2013-09-21 23:39:42 +00:00
// overwrite the drupalSettings.ajaxPageState.css object with an empty
2012-08-30 19:24:38 +00:00
// array.
2014-01-08 06:44:57 +00:00
$css = _drupal_add_css ();
2012-08-30 19:24:38 +00:00
if ( ! empty ( $css )) {
// Cast the array to an object to be on the safe side even if not empty.
$setting [ 'ajaxPageState' ][ 'css' ] = ( object ) array_fill_keys ( array_keys ( $css ), 1 );
}
2011-11-03 11:00:04 +00:00
2014-01-08 06:44:57 +00:00
_drupal_add_js ( $setting , 'setting' );
2011-11-03 11:00:04 +00:00
2012-08-30 19:24:38 +00:00
// If we're outputting the header scope, then this might be the final time
// that drupal_get_js() is running, so add the settings to this output as well
2014-01-08 06:44:57 +00:00
// as to the _drupal_add_js() cache. If $items['settings'] doesn't exist, it's
2012-08-30 19:24:38 +00:00
// because drupal_get_js() was intentionally passed a $javascript argument
// stripped of settings, potentially in order to override how settings get
// output, so in this case, do not add the setting to this output.
if ( $scope == 'header' && isset ( $items [ 'settings' ])) {
$items [ 'settings' ][ 'data' ][] = $setting ;
}
}
2011-11-03 11:00:04 +00:00
}
// Render the HTML needed to load the JavaScript.
$elements = array (
'#type' => 'scripts' ,
'#items' => $items ,
);
return drupal_render ( $elements );
}
2013-01-18 18:00:29 +00:00
/**
* Merges an array of settings arrays into a single settings array .
*
* This function merges the items in the same way that
*
* @ code
* jQuery . extend ( true , {}, $settings_items [ 0 ], $settings_items [ 1 ], ... )
* @ endcode
*
2013-01-30 04:00:17 +00:00
* would . This means integer indices are preserved just like string indices are ,
2013-01-18 18:00:29 +00:00
* rather than re - indexed as is common in PHP array merging .
*
* Example :
* @ code
* function module1_page_build ( & $page ) {
* $page [ '#attached' ][ 'js' ][] = array (
* 'type' => 'setting' ,
* 'data' => array ( 'foo' => array ( 'a' , 'b' , 'c' )),
* );
* }
* function module2_page_build ( & $page ) {
* $page [ '#attached' ][ 'js' ][] = array (
* 'type' => 'setting' ,
* 'data' => array ( 'foo' => array ( 'd' )),
* );
* }
* // When the page is rendered after the above code, and the browser runs the
* // resulting <SCRIPT> tags, the value of drupalSettings.foo is
* // ['d', 'b', 'c'], not ['a', 'b', 'c', 'd'].
* @ endcode
*
* By following jQuery . extend () merge logic rather than common PHP array merge
* logic , the following are ensured :
2014-01-08 06:44:57 +00:00
* - _drupal_add_js () is idempotent : calling it twice with the same parameters
2013-01-18 18:00:29 +00:00
* does not change the output sent to the browser .
* - If pieces of the page are rendered in separate PHP requests and the
* returned settings are merged by JavaScript , the resulting settings are the
* same as if rendered in one PHP request and merged by PHP .
*
* @ param $settings_items
* An array of settings arrays , as returned by :
* @ code
2014-01-08 06:44:57 +00:00
* $js = _drupal_add_js ();
2013-01-18 18:00:29 +00:00
* $settings_items = $js [ 'settings' ][ 'data' ];
* @ endcode
*
* @ return
* A merged $settings array , suitable for JSON encoding and returning to the
* browser .
*
2014-01-08 06:44:57 +00:00
* @ see _drupal_add_js ()
2013-01-18 18:00:29 +00:00
* @ see drupal_pre_render_scripts ()
*/
function drupal_merge_js_settings ( $settings_items ) {
return NestedArray :: mergeDeepArray ( $settings_items , TRUE );
}
2013-10-24 15:43:00 +00:00
/**
* Merges two #attached arrays.
*
* @ param array $a
* An #attached array.
* @ param array $b
* Another #attached array.
*
* @ return array
* The merged #attached array.
*/
function drupal_merge_attached ( array $a , array $b ) {
return NestedArray :: mergeDeep ( $a , $b );
}
2011-11-03 11:00:04 +00:00
/**
* #pre_render callback to add the elements needed for JavaScript tags to be rendered.
*
* This function evaluates the aggregation enabled / disabled condition on a group
* by group basis by testing whether an aggregate file has been made for the
* group rather than by testing the site - wide aggregation setting . This allows
* this function to work correctly even if modules have implemented custom
* logic for grouping and aggregating files .
*
* @ param $element
* A render array containing :
2014-01-08 06:44:57 +00:00
* - #items: The JavaScript items as returned by _drupal_add_js() and
2011-11-03 11:00:04 +00:00
* altered by drupal_get_js () .
* - #group_callback: A function to call to group #items. Following
* this function , #aggregate_callback is called to aggregate items within
* the same group into a single file .
* - #aggregate_callback: A function to call to aggregate the items within
* the groups arranged by the #group_callback function.
*
* @ return
* A render array that will render to a string of JavaScript tags .
*
* @ see drupal_get_js ()
*/
function drupal_pre_render_scripts ( $elements ) {
2013-07-04 08:38:19 +00:00
$js_assets = $elements [ '#items' ];
2008-11-10 05:23:01 +00:00
2013-07-04 08:38:19 +00:00
// Aggregate the JavaScript if necessary, but only during normal site
// operation.
2013-09-16 03:58:06 +00:00
if ( ! defined ( 'MAINTENANCE_MODE' ) && \Drupal :: config ( 'system.performance' ) -> get ( 'js.preprocess' )) {
2013-07-04 08:38:19 +00:00
$js_assets = \Drupal :: service ( 'asset.js.collection_optimizer' ) -> optimize ( $js_assets );
2007-06-01 09:05:45 +00:00
}
2013-07-04 08:38:19 +00:00
return \Drupal :: service ( 'asset.js.collection_renderer' ) -> render ( $js_assets );
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
}
2009-08-25 21:16:31 +00:00
/**
2010-10-28 00:08:24 +00:00
* Adds attachments to a render () structure .
2009-08-25 21:16:31 +00:00
*
2009-09-05 15:05:05 +00:00
* Libraries , JavaScript , CSS and other types of custom structures are attached
2010-10-28 00:08:24 +00:00
* to elements using the #attached property. The #attached property is an
* associative array , where the keys are the the attachment types and the values
* are the attached data . For example :
2014-01-08 06:44:57 +00:00
*
2009-09-05 15:05:05 +00:00
* @ code
* $build [ '#attached' ] = array (
2012-08-30 19:24:38 +00:00
* 'library' => array ( array ( 'taxonomy' , 'taxonomy' )),
2013-06-07 10:48:55 +00:00
* 'css' => array ( drupal_get_path ( 'module' , 'taxonomy' ) . '/css/taxonomy.module.css' ),
2009-09-05 15:05:05 +00:00
* );
* @ endcode
*
2011-12-05 12:52:27 +00:00
* 'js' , 'css' , and 'library' are types that get special handling . For any
2009-09-05 15:05:05 +00:00
* other kind of attached data , the array key must be the full name of the
* callback function and each value an array of arguments . For example :
* @ code
2009-09-30 18:36:02 +00:00
* $build [ '#attached' ][ 'drupal_add_http_header' ] = array (
2009-09-05 15:05:05 +00:00
* array ( 'Content-Type' , 'application/rss+xml; charset=utf-8' ),
* );
* @ endcode
*
2010-11-20 09:46:22 +00:00
* External 'js' and 'css' files can also be loaded . For example :
* @ code
* $build [ '#attached' ][ 'js' ] = array (
* 'http://code.jquery.com/jquery-1.4.2.min.js' => array (
* 'type' => 'external' ,
* ),
* );
* @ endcode
*
2009-09-05 15:05:05 +00:00
* @ param $elements
* The structured array describing the data being rendered .
2009-08-25 21:16:31 +00:00
* @ param $dependency_check
* When TRUE , will exit if a given library ' s dependencies are missing . When
2010-10-28 00:08:24 +00:00
* set to FALSE , will continue to add the libraries , even though one or more
2009-08-25 21:16:31 +00:00
* dependencies are missing . Defaults to FALSE .
2010-03-26 17:14:46 +00:00
*
2009-08-25 21:16:31 +00:00
* @ return
2010-10-28 00:08:24 +00:00
* FALSE if there were any missing library dependencies ; TRUE if all library
* dependencies were met .
2009-08-25 21:16:31 +00:00
*
2014-03-12 15:46:33 +00:00
* @ see _drupal_add_library ()
2014-01-08 06:44:57 +00:00
* @ see _drupal_add_js ()
* @ see _drupal_add_css ()
2010-03-26 17:14:46 +00:00
* @ see drupal_render ()
2009-08-25 21:16:31 +00:00
*/
2013-06-14 13:33:02 +00:00
function drupal_process_attached ( $elements , $dependency_check = FALSE ) {
2009-09-05 15:05:05 +00:00
// Add defaults to the special attached structures that should be processed differently.
$elements [ '#attached' ] += array (
'library' => array (),
'js' => array (),
'css' => array (),
);
2009-08-25 21:16:31 +00:00
// Add the libraries first.
$success = TRUE ;
2009-09-05 15:05:05 +00:00
foreach ( $elements [ '#attached' ][ 'library' ] as $library ) {
2014-03-12 15:46:33 +00:00
if ( _drupal_add_library ( $library ) === FALSE ) {
2009-08-25 21:16:31 +00:00
$success = FALSE ;
// Exit if the dependency is missing.
if ( $dependency_check ) {
return $success ;
}
}
}
2009-09-05 15:05:05 +00:00
unset ( $elements [ '#attached' ][ 'library' ]);
2009-08-25 21:16:31 +00:00
// Add both the JavaScript and the CSS.
2014-01-08 06:44:57 +00:00
// The parameters for _drupal_add_js() and _drupal_add_css() require special
2009-09-05 15:05:05 +00:00
// handling.
foreach ( array ( 'js' , 'css' ) as $type ) {
foreach ( $elements [ '#attached' ][ $type ] as $data => $options ) {
2009-08-25 21:16:31 +00:00
// If the value is not an array, it's a filename and passed as first
// (and only) argument.
if ( ! is_array ( $options )) {
$data = $options ;
$options = NULL ;
}
// In some cases, the first parameter ($data) is an array. Arrays can't be
// passed as keys in PHP, so we have to get $data from the value array.
if ( is_numeric ( $data )) {
$data = $options [ 'data' ];
unset ( $options [ 'data' ]);
}
2014-01-08 06:44:57 +00:00
call_user_func ( '_drupal_add_' . $type , $data , $options );
2009-08-25 21:16:31 +00:00
}
2009-09-05 15:05:05 +00:00
unset ( $elements [ '#attached' ][ $type ]);
}
// Add additional types of attachments specified in the render() structure.
2011-02-19 00:09:11 +00:00
// Libraries, JavaScript and CSS have been added already, as they require
2009-09-05 15:05:05 +00:00
// special handling.
foreach ( $elements [ '#attached' ] as $callback => $options ) {
2011-12-15 17:33:38 +00:00
foreach ( $elements [ '#attached' ][ $callback ] as $args ) {
call_user_func_array ( $callback , $args );
2009-09-05 15:05:05 +00:00
}
2009-08-25 21:16:31 +00:00
}
2009-09-05 15:05:05 +00:00
2009-08-25 21:16:31 +00:00
return $success ;
}
2009-10-16 19:20:34 +00:00
/**
2010-05-01 00:05:04 +00:00
* Adds JavaScript to change the state of an element based on another element .
2009-10-16 19:20:34 +00:00
*
2010-05-01 00:05:04 +00:00
* A " state " means a certain property on a DOM element , such as " visible " or
* " checked " . A state can be applied to an element , depending on the state of
* another element on the page . In general , states depend on HTML attributes and
* DOM element properties , which change due to user interaction .
*
* Since states are driven by JavaScript only , it is important to understand
* that all states are applied on presentation only , none of the states force
* any server - side logic , and that they will not be applied for site visitors
* without JavaScript support . All modules implementing states have to make
* sure that the intended logic also works without JavaScript being enabled .
*
* #states is an associative array in the form of:
* @ code
* array (
* STATE1 => CONDITIONS_ARRAY1 ,
* STATE2 => CONDITIONS_ARRAY2 ,
* ...
* )
* @ endcode
* Each key is the name of a state to apply to the element , such as 'visible' .
* Each value is a list of conditions that denote when the state should be
* applied .
*
* Multiple different states may be specified to act on complex conditions :
* @ code
* array (
* 'visible' => CONDITIONS ,
* 'checked' => OTHER_CONDITIONS ,
* )
* @ endcode
*
* Every condition is a key / value pair , whose key is a jQuery selector that
* denotes another element on the page , and whose value is an array of
* conditions , which must bet met on that element :
* @ code
* array (
* 'visible' => array (
* JQUERY_SELECTOR => REMOTE_CONDITIONS ,
* JQUERY_SELECTOR => REMOTE_CONDITIONS ,
* ...
* ),
* )
* @ endcode
* All conditions must be met for the state to be applied .
*
* Each remote condition is a key / value pair specifying conditions on the other
* element that need to be met to apply the state to the element :
* @ code
* array (
* 'visible' => array (
* ':input[name="remote_checkbox"]' => array ( 'checked' => TRUE ),
* ),
* )
* @ endcode
*
* For example , to show a textfield only when a checkbox is checked :
* @ code
* $form [ 'toggle_me' ] = array (
* '#type' => 'checkbox' ,
* '#title' => t ( 'Tick this box to type' ),
* );
* $form [ 'settings' ] = array (
* '#type' => 'textfield' ,
* '#states' => array (
* // Only show this field when the 'toggle_me' checkbox is enabled.
* 'visible' => array (
* ':input[name="toggle_me"]' => array ( 'checked' => TRUE ),
2009-10-16 19:20:34 +00:00
* ),
2010-05-01 00:05:04 +00:00
* ),
* );
* @ endcode
*
* The following states may be applied to an element :
* - enabled
* - disabled
2011-08-10 19:47:50 +00:00
* - required
* - optional
2010-05-01 00:05:04 +00:00
* - visible
* - invisible
* - checked
* - unchecked
* - expanded
* - collapsed
*
* The following states may be used in remote conditions :
2011-08-10 19:47:50 +00:00
* - empty
* - filled
2010-05-01 00:05:04 +00:00
* - checked
* - unchecked
2011-08-10 19:47:50 +00:00
* - expanded
* - collapsed
2010-05-01 00:05:04 +00:00
* - value
*
2011-08-10 19:47:50 +00:00
* The following states exist for both elements and remote conditions , but are
* not fully implemented and may not change anything on the element :
2010-05-01 00:05:04 +00:00
* - relevant
* - irrelevant
* - valid
* - invalid
* - touched
* - untouched
* - readwrite
* - readonly
*
* When referencing select lists and radio buttons in remote conditions , a
* 'value' condition must be used :
* @ code
* '#states' => array (
* // Show the settings if 'bar' has been selected for 'foo'.
* 'visible' => array (
* ':input[name="foo"]' => array ( 'value' => 'bar' ),
* ),
* ),
* @ endcode
*
* @ param $elements
* A renderable array element having a #states property as described above.
*
* @ see form_example_states_form ()
2009-10-16 19:20:34 +00:00
*/
function drupal_process_states ( & $elements ) {
2014-03-09 19:59:45 +00:00
$elements [ '#attached' ][ 'library' ][] = 'core/drupal.states' ;
2013-11-05 16:46:25 +00:00
// Elements of '#type' => 'item' are not actual form input elements, but we
// still want to be able to show/hide them. Since there's no actual HTML input
// element available, setting #attributes does not make sense, but a wrapper
// is available, so setting #wrapper_attributes makes it work.
$key = ( $elements [ '#type' ] == 'item' ) ? '#wrapper_attributes' : '#attributes' ;
$elements [ $key ][ 'data-drupal-states' ] = JSON :: encode ( $elements [ '#states' ]);
2009-10-16 19:20:34 +00:00
}
2009-07-04 18:26:42 +00:00
/**
* Adds multiple JavaScript or CSS files at the same time .
*
* A library defines a set of JavaScript and / or CSS files , optionally using
* settings , and optionally requiring another library . For example , a library
* can be a jQuery plugin , a JavaScript framework , or a CSS framework . This
* function allows modules to load a library defined / shipped by itself or a
2010-10-28 00:08:24 +00:00
* depending module , without having to add all files of the library separately .
2009-07-04 18:26:42 +00:00
* Each library is only loaded once .
*
2014-03-09 19:59:45 +00:00
* @ param $library_name
2009-07-04 18:26:42 +00:00
* The name of the library to add .
2010-10-28 00:08:24 +00:00
* @ param $every_page
2013-06-14 13:33:02 +00:00
* Set to TRUE if this library is added to every page on the site .
2010-10-28 00:08:24 +00:00
*
2009-07-04 18:26:42 +00:00
* @ return
2010-10-28 00:08:24 +00:00
* TRUE if the library was successfully added ; FALSE if the library or one of
* its dependencies could not be added .
2009-07-04 18:26:42 +00:00
*
* @ see drupal_get_library ()
2011-09-24 19:50:19 +00:00
* @ see hook_library_info_alter ()
2009-07-04 18:26:42 +00:00
*/
2014-03-12 15:46:33 +00:00
function _drupal_add_library ( $library_name , $every_page = NULL ) {
2009-07-04 18:26:42 +00:00
$added = & drupal_static ( __FUNCTION__ , array ());
2014-03-09 19:59:45 +00:00
list ( $extension , $name ) = explode ( '/' , $library_name , 2 );
2009-07-04 18:26:42 +00:00
// Only process the library if it exists and it was not added already.
2014-03-09 19:59:45 +00:00
if ( ! isset ( $added [ $extension ][ $name ])) {
if ( $library = drupal_get_library ( $library_name )) {
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
// Allow modules and themes to dynamically attach request and context
// specific data for this library; e.g., localization.
2014-03-09 19:59:45 +00:00
\Drupal :: moduleHandler () -> alter ( 'library' , $library , $library_name );
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
2009-08-25 21:16:31 +00:00
// Add all components within the library.
2009-09-05 15:05:05 +00:00
$elements [ '#attached' ] = array (
'library' => $library [ 'dependencies' ],
'js' => $library [ 'js' ],
'css' => $library [ 'css' ],
);
2013-06-14 13:33:02 +00:00
foreach ( array ( 'js' , 'css' ) as $type ) {
foreach ( $elements [ '#attached' ][ $type ] as $data => $options ) {
// Set the every_page flag if one was passed.
if ( isset ( $every_page )) {
$elements [ '#attached' ][ $type ][ $data ][ 'every_page' ] = $every_page ;
}
}
}
2014-03-09 19:59:45 +00:00
$added [ $extension ][ $name ] = drupal_process_attached ( $elements , TRUE );
2009-07-04 18:26:42 +00:00
}
2009-08-25 21:16:31 +00:00
else {
// Requested library does not exist.
2014-03-09 19:59:45 +00:00
$added [ $extension ][ $name ] = FALSE ;
2009-07-04 18:26:42 +00:00
}
}
2014-03-09 19:59:45 +00:00
return $added [ $extension ][ $name ];
2009-07-04 18:26:42 +00:00
}
/**
* Retrieves information for a JavaScript / CSS library .
*
* Library information is statically cached . Libraries are keyed by module for
* several reasons :
* - Libraries are not unique . Multiple modules might ship with the same library
* in a different version or variant . This registry cannot ( and does not
* attempt to ) prevent library conflicts .
* - Modules implementing and thereby depending on a library that is registered
* by another module can only rely on that module ' s library .
* - Two ( or more ) modules can still register the same library and use it
* without conflicts in case the libraries are loaded on certain pages only .
*
2014-03-09 19:59:45 +00:00
* @ param $library_name
* The name of a registered library to retrieve . By default , all
* libraries registered by the extension are returned .
2010-12-15 04:21:39 +00:00
*
2009-07-04 18:26:42 +00:00
* @ return
2010-12-15 04:21:39 +00:00
* The definition of the requested library , if $name was passed and it exists ,
* or FALSE if it does not exist . If no $name was passed , an associative array
2014-03-09 19:59:45 +00:00
* of libraries registered by the module is returned ( which may be empty ) .
2009-07-04 18:26:42 +00:00
*
2014-03-12 15:46:33 +00:00
* @ see _drupal_add_library ()
2011-09-24 19:50:19 +00:00
* @ see hook_library_info_alter ()
2009-07-04 18:26:42 +00:00
*
* @ todo The purpose of drupal_get_ * () is completely different to other page
* requisite API functions ; find and use a different name .
*/
2014-03-09 19:59:45 +00:00
function drupal_get_library ( $library_name ) {
2009-07-04 18:26:42 +00:00
$libraries = & drupal_static ( __FUNCTION__ , array ());
2014-03-09 19:59:45 +00:00
$library_info = explode ( '/' , $library_name , 2 );
$extension = $library_info [ 0 ];
$name = isset ( $library_info [ 1 ]) ? $library_info [ 1 ] : NULL ;
2014-02-25 11:38:00 +00:00
if ( ! isset ( $libraries [ $extension ]) && ( $cache = \Drupal :: cache () -> get ( 'library:info:' . $extension ))) {
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
$libraries [ $extension ] = $cache -> data ;
}
if ( ! isset ( $libraries [ $extension ])) {
$libraries [ $extension ] = array ();
if ( $extension === 'core' ) {
$path = 'core' ;
$extension_type = 'core' ;
2010-03-09 03:39:44 +00:00
}
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
else {
// @todo Add a $type argument OR automatically figure out the type based
// on current extension data, possibly using a module->theme fallback.
$path = drupal_get_path ( 'module' , $extension );
$extension_type = 'module' ;
if ( ! $path ) {
$path = drupal_get_path ( 'theme' , $extension );
$extension_type = 'theme' ;
}
}
$library_file = $path . '/' . $extension . '.libraries.yml' ;
if ( $library_file && file_exists ( DRUPAL_ROOT . '/' . $library_file )) {
$libraries [ $extension ] = array ();
$parser = new Parser ();
try {
$libraries [ $extension ] = $parser -> parse ( file_get_contents ( DRUPAL_ROOT . '/' . $library_file ));
}
catch ( ParseException $e ) {
// Rethrow a more helpful exception, since ParseException lacks context.
throw new \RuntimeException ( sprintf ( 'Invalid library definition in %s: %s' , $library_file , $e -> getMessage ()), 0 , $e );
}
// Allow modules to alter the module's registered libraries.
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'library_info' , $libraries [ $extension ], $extension );
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
}
foreach ( $libraries [ $extension ] as $id => & $library ) {
if ( ! isset ( $library [ 'js' ]) && ! isset ( $library [ 'css' ]) && ! isset ( $library [ 'settings' ])) {
throw new \RuntimeException ( sprintf ( " Incomplete library definition for '%s' in %s " , $id , $library_file ));
}
$library += array ( 'dependencies' => array (), 'js' => array (), 'css' => array ());
if ( isset ( $library [ 'version' ])) {
// @todo Retrieve version of a non-core extension.
if ( $library [ 'version' ] === 'VERSION' ) {
$library [ 'version' ] = \Drupal :: VERSION ;
}
// Remove 'v' prefix from external library versions.
elseif ( $library [ 'version' ][ 0 ] === 'v' ) {
$library [ 'version' ] = substr ( $library [ 'version' ], 1 );
}
}
foreach ( array ( 'js' , 'css' ) as $type ) {
// Prepare (flatten) the SMACSS-categorized definitions.
// @todo After Asset(ic) changes, retain the definitions as-is and
// properly resolve dependencies for all (css) libraries per category,
// and only once prior to rendering out an HTML page.
if ( $type == 'css' && ! empty ( $library [ $type ])) {
foreach ( $library [ $type ] as $category => $files ) {
foreach ( $files as $source => $options ) {
if ( ! isset ( $options [ 'weight' ])) {
$options [ 'weight' ] = 0 ;
}
// Apply the corresponding weight defined by CSS_* constants.
2014-03-04 18:04:01 +00:00
$options [ 'weight' ] += constant ( 'CSS_' . strtoupper ( $category ));
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
$library [ $type ][ $source ] = $options ;
}
unset ( $library [ $type ][ $category ]);
}
}
foreach ( $library [ $type ] as $source => $options ) {
unset ( $library [ $type ][ $source ]);
// Allow to omit the options hashmap in YAML declarations.
if ( ! is_array ( $options )) {
$options = array ();
}
if ( $type == 'js' && isset ( $options [ 'weight' ]) && $options [ 'weight' ] > 0 ) {
throw new \UnexpectedValueException ( " The $extension / $id library defines a positive weight for ' $source '. Only negative weights are allowed (but should be avoided). Instead of a positive weight, specify accurate dependencies for this library. " );
}
// Unconditionally apply default groups for the defined asset files.
// The library system is a dependency management system. Each library
// properly specifies its dependencies instead of relying on a custom
// processing order.
if ( $type == 'js' ) {
$options [ 'group' ] = JS_LIBRARY ;
}
elseif ( $type == 'css' ) {
$options [ 'group' ] = $extension_type == 'theme' ? CSS_AGGREGATE_THEME : CSS_AGGREGATE_DEFAULT ;
2013-04-07 18:30:13 +00:00
}
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
// By default, all library assets are files.
if ( ! isset ( $options [ 'type' ])) {
$options [ 'type' ] = 'file' ;
}
if ( $options [ 'type' ] == 'external' ) {
$options [ 'data' ] = $source ;
}
// Determine the file asset URI.
else {
if ( $source [ 0 ] === '/' ) {
// An absolute path maps to DRUPAL_ROOT / base_path().
if ( $source [ 1 ] !== '/' ) {
$options [ 'data' ] = substr ( $source , 1 );
}
// A protocol-free URI (e.g., //cdn.com/example.js) is external.
else {
$options [ 'type' ] = 'external' ;
$options [ 'data' ] = $source ;
}
}
// A stream wrapper URI (e.g., public://generated_js/example.js).
elseif ( file_valid_uri ( $source )) {
$options [ 'data' ] = $source ;
}
// By default, file paths are relative to the registering extension.
else {
$options [ 'data' ] = $path . '/' . $source ;
}
}
$options [ 'version' ] = $library [ 'version' ];
$library [ $type ][] = $options ;
}
}
// @todo Introduce drupal_add_settings().
if ( isset ( $library [ 'settings' ])) {
$library [ 'js' ][] = array (
'type' => 'setting' ,
'data' => $library [ 'settings' ],
);
unset ( $library [ 'settings' ]);
}
2009-07-04 18:26:42 +00:00
}
2014-02-25 11:38:00 +00:00
\Drupal :: cache () -> set ( 'library:info:' . $extension , $libraries [ $extension ], Cache :: PERMANENT , array (
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
'extension' => array ( TRUE , $extension ),
'library_info' => array ( TRUE ),
));
2009-07-04 18:26:42 +00:00
}
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
2010-12-15 04:21:39 +00:00
if ( isset ( $name )) {
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
if ( ! isset ( $libraries [ $extension ][ $name ])) {
$libraries [ $extension ][ $name ] = FALSE ;
2010-12-15 04:21:39 +00:00
}
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
return $libraries [ $extension ][ $name ];
2009-07-04 18:26:42 +00:00
}
Issue #1996238 by sun, nod_, damiankloip, Wim Leers, longwave, alexpott, Xano, mdrummond, Mark Carver, Jeff Burnz, highrockmedia, joelpittet, et al: Replace hook_library_info() by *.libraries.yml file.
2014-02-23 04:56:51 +00:00
return $libraries [ $extension ];
2009-07-04 18:26:42 +00:00
}
2007-11-14 09:50:00 +00:00
/**
2013-12-20 12:05:47 +00:00
* Assists in attaching the tableDrag JavaScript behavior to a themed table .
2007-11-14 09:50:00 +00:00
*
* Draggable tables should be used wherever an outline or list of sortable items
* needs to be arranged by an end - user . Draggable tables are very flexible and
* can manipulate the value of form elements placed within individual columns .
*
2011-12-05 12:52:27 +00:00
* To set up a table to use drag and drop in place of weight select - lists or in
* place of a form that contains parent relationships , the form must be themed
* into a table . The table must have an ID attribute set . If using
* theme_table (), the ID may be set as follows :
2007-11-14 09:50:00 +00:00
* @ code
2014-02-18 10:54:10 +00:00
* $table = array (
* '#type' => 'table' ,
* '#header' => $header ,
* '#rows' => $rows ,
* '#attributes' => array (
* 'id' => 'my-module-table' ,
* ),
* );
* return drupal_render ( $table );
2007-11-14 09:50:00 +00:00
* @ endcode
*
* In the theme function for the form , a special class must be added to each
* form element within the same column , " grouping " them together .
*
* In a situation where a single weight column is being sorted in the table , the
* classes could be added like this ( in the theme function ) :
* @ code
2009-08-22 14:34:23 +00:00
* $form [ 'my_elements' ][ $delta ][ 'weight' ][ '#attributes' ][ 'class' ] = array ( 'my-elements-weight' );
2007-11-14 09:50:00 +00:00
* @ endcode
*
2011-12-05 12:52:27 +00:00
* Each row of the table must also have a class of " draggable " in order to
* enable the drag handles :
2007-11-20 20:13:04 +00:00
* @ code
* $row = array ( ... );
* $rows [] = array (
* 'data' => $row ,
2009-08-22 14:34:23 +00:00
* 'class' => array ( 'draggable' ),
2007-11-20 20:13:04 +00:00
* );
* @ endcode
2007-11-23 13:34:55 +00:00
*
2007-12-19 10:58:35 +00:00
* When tree relationships are present , the two additional classes
* 'tabledrag-leaf' and 'tabledrag-root' can be used to refine the behavior :
* - Rows with the 'tabledrag-leaf' class cannot have child rows .
* - Rows with the 'tabledrag-root' class cannot be nested under a parent row .
*
2013-12-20 12:05:47 +00:00
* Calling drupal_attach_tabledrag () would then be written as such :
2007-11-14 09:50:00 +00:00
* @ code
2013-12-20 12:05:47 +00:00
* drupal_attach_tabledrag ( 'my-module-table' , array (
* 'action' => 'order' ,
* 'relationship' => 'sibling' ,
* 'group' => 'my-elements-weight' ,
* );
2007-11-14 09:50:00 +00:00
* @ endcode
*
* In a more complex case where there are several groups in one column ( such as
2011-12-05 12:52:27 +00:00
* the block regions on the admin / structure / block page ), a separate subgroup
* class must also be added to differentiate the groups .
2007-11-14 09:50:00 +00:00
* @ code
2009-08-22 14:34:23 +00:00
* $form [ 'my_elements' ][ $region ][ $delta ][ 'weight' ][ '#attributes' ][ 'class' ] = array ( 'my-elements-weight' , 'my-elements-weight-' . $region );
2007-11-14 09:50:00 +00:00
* @ endcode
*
2013-12-20 12:05:47 +00:00
* The 'group' option is still 'my-element-weight' , and the additional
* 'subgroup' option will be passed in as 'my-elements-weight-' . $region . This
* also means that you ' ll need to call drupal_attach_tabledrag () once for every
* region added .
2007-11-14 09:50:00 +00:00
*
* @ code
* foreach ( $regions as $region ) {
2013-12-20 12:05:47 +00:00
* drupal_attach_tabledrag ( 'my-module-table' , array (
* 'action' => 'order' ,
* 'relationship' => sibling ' ,
* 'group' => 'my-elements-weight' ,
* 'subgroup' => my - elements - weight - ' . $region ,
* ));
2007-11-14 09:50:00 +00:00
* }
* @ endcode
*
* In a situation where tree relationships are present , adding multiple
* subgroups is not necessary , because the table will contain indentations that
2011-12-05 12:52:27 +00:00
* provide enough information about the sibling and parent relationships . See
* theme_menu_overview_form () for an example creating a table containing parent
* relationships .
*
2013-12-20 12:05:47 +00:00
* @ param $element
* A form element to attach the tableDrag behavior to .
* @ param array $options
* These options are used to generate JavaScript settings necessary to
* configure the tableDrag behavior appropriately for this particular table .
* An associative array containing the following keys :
* - 'table_id' : String containing the target table ' s id attribute .
* If the table does not have an id , one will need to be set ,
* such as < table id = " my-module-table " >.
* - 'action' : String describing the action to be done on the form item .
* Either 'match' 'depth' , or 'order' :
* - 'match' is typically used for parent relationships .
* - 'order' is typically used to set weights on other form elements with
* the same group .
* - 'depth' updates the target element with the current indentation .
* - 'relationship' : String describing where the " action " option
* should be performed . Either 'parent' , 'sibling' , 'group' , or 'self' :
* - 'parent' will only look for fields up the tree .
* - 'sibling' will look for fields in the same group in rows above and
* below it .
* - 'self' affects the dragged row itself .
* - 'group' affects the dragged row , plus any children below it ( the entire
* dragged group ) .
* - 'group' : A class name applied on all related form elements for this action .
* - 'subgroup' : ( optional ) If the group has several subgroups within it , this
* string should contain the class name identifying fields in the same
* subgroup .
* - 'source' : ( optional ) If the $action is 'match' , this string should contain
* the classname identifying what field will be used as the source value
* when matching the value in $subgroup .
* - 'hidden' : ( optional ) The column containing the field elements may be
* entirely hidden from view dynamically when the JavaScript is loaded . Set
* to FALSE if the column should not be hidden .
* - 'limit' : ( optional ) Limit the maximum amount of parenting in this table .
*
2007-11-14 09:50:00 +00:00
* @ see theme_menu_overview_form ()
*/
2013-12-20 12:05:47 +00:00
function drupal_attach_tabledrag ( & $element , array $options ) {
// Add default values to elements.
$options = $options + array (
'subgroup' => NULL ,
'source' => NULL ,
'hidden' => TRUE ,
'limit' => 0
);
2013-01-18 18:00:29 +00:00
2013-12-20 12:05:47 +00:00
$group = $options [ 'group' ];
$tabledrag_id = & drupal_static ( __FUNCTION__ );
$tabledrag_id = ( ! isset ( $tabledrag_id )) ? 0 : $tabledrag_id + 1 ;
2007-11-14 09:50:00 +00:00
// If a subgroup or source isn't set, assume it is the same as the group.
2013-12-20 12:05:47 +00:00
$target = isset ( $options [ 'subgroup' ]) ? $options [ 'subgroup' ] : $group ;
$source = isset ( $options [ 'source' ]) ? $options [ 'source' ] : $target ;
$settings [ 'tableDrag' ][ $options [ 'table_id' ]][ $group ][ $tabledrag_id ] = array (
2007-11-14 09:50:00 +00:00
'target' => $target ,
'source' => $source ,
2013-12-20 12:05:47 +00:00
'relationship' => $options [ 'relationship' ],
'action' => $options [ 'action' ],
'hidden' => $options [ 'hidden' ],
'limit' => $options [ 'limit' ],
2007-11-14 09:50:00 +00:00
);
2013-12-20 12:05:47 +00:00
2014-03-09 19:59:45 +00:00
$element [ '#attached' ][ 'library' ][] = 'core/drupal.tabledrag' ;
2013-12-20 12:05:47 +00:00
$element [ '#attached' ][ 'js' ][] = array ( 'data' => $settings , 'type' => 'setting' );
2007-11-14 09:50:00 +00:00
}
2007-06-01 09:05:45 +00:00
/**
2010-05-09 19:44:25 +00:00
* Deletes old cached JavaScript files and variables .
2007-06-01 09:05:45 +00:00
*/
function drupal_clear_js_cache () {
2013-09-16 03:58:06 +00:00
\Drupal :: state () -> delete ( 'system.javascript_parsed' );
\Drupal :: state () -> delete ( 'system.js_cache_files' );
2010-05-09 19:44:25 +00:00
file_scan_directory ( 'public://js' , '/.*/' , array ( 'callback' => 'drupal_delete_file_if_stale' ));
2007-06-01 09:05:45 +00:00
}
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
/**
2011-02-19 00:09:11 +00:00
* Converts a PHP variable into its JavaScript equivalent .
2006-02-05 19:04:58 +00:00
*
2011-12-05 12:17:24 +00:00
* We use HTML - safe strings , with several characters escaped .
2009-11-21 00:43:42 +00:00
*
* @ see drupal_json_decode ()
2014-02-20 13:49:37 +00:00
*
2010-01-04 12:27:33 +00:00
* @ ingroup php_wrappers
2014-02-20 13:49:37 +00:00
*
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Component\Utility\Json :: encode () .
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
*/
2009-09-21 07:56:09 +00:00
function drupal_json_encode ( $var ) {
2013-06-27 21:04:31 +00:00
return Json :: encode ( $var );
2009-11-21 00:43:42 +00:00
}
/**
* Converts an HTML - safe JSON string into its PHP equivalent .
*
* @ see drupal_json_encode ()
2014-02-20 13:49:37 +00:00
*
2010-01-04 23:08:34 +00:00
* @ ingroup php_wrappers
2014-02-20 13:49:37 +00:00
*
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Component\Utility\Json :: decode () .
2009-11-21 00:43:42 +00:00
*/
function drupal_json_decode ( $var ) {
2013-06-27 21:04:31 +00:00
return Json :: decode ( $var );
- Patch #28483 by Steven: JavaScript enabled uploading.
Comment from Steven: It does this by redirecting the submission of the form to a hidden <iframe> when you click "Attach" (we cannot submit data through Ajax directly because you cannot read file contents from JS for security reasons). Once the file is submitted, the upload-section of the form is updated. Things to note:
* The feature degrades back to the current behaviour without JS.
* If there are errors with the uploaded file (disallowed type, too big, ...), they are displayed at the top of the file attachments fieldset.
* Though the hidden-iframe method sounds dirty, it's quite compact and is 100% implemented in .js files. The drupal.js api makes it a snap to use.
* I included some minor improvements to the Drupal JS API and code.
* I added an API drupal_call_js() to bridge the PHP/JS gap: it takes a function name and arguments, and outputs a <script> tag. The kicker is that it preserves the structure and type of arguments, so e.g. PHP associative arrays end up as objects in JS.
* I also included a progressbar widget that I wrote for drumm's ongoing update.php work. It includes Ajax status updating/monitoring, but it is only used as a pure throbber in this patch. But as the code was already written and is going to be used in the near future, I left that part in. It's pretty small ;). If PHP supports ad-hoc upload info in the future like Ruby on Rails, we can implement that in 5 minutes.
2005-08-31 18:37:30 +00:00
}
2006-10-31 08:06:18 +00:00
/**
2011-12-05 12:52:27 +00:00
* Ensures the private key variable used to generate tokens is set .
2006-10-31 08:06:18 +00:00
*
2013-08-13 06:47:07 +00:00
* @ return string
2007-10-08 14:08:19 +00:00
* The private key .
2013-08-13 06:47:07 +00:00
*
2014-02-20 13:49:37 +00:00
* @ see \Drupal\Core\Access\CsrfTokenGenerator
2013-08-13 06:47:07 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: service ( 'private_key' ) -> get () .
2006-10-31 08:06:18 +00:00
*/
function drupal_get_private_key () {
2013-08-13 06:47:07 +00:00
return \Drupal :: service ( 'private_key' ) -> get ();
2006-10-31 08:06:18 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Generates a token based on $value , the user session , and the private key .
2006-10-31 08:06:18 +00:00
*
2013-08-13 06:47:07 +00:00
* @ param string $value
2007-10-08 14:08:19 +00:00
* An additional value to base the token on .
2012-12-04 17:50:15 +00:00
*
2014-02-13 00:13:01 +00:00
* The generated token is based on the session ID of the current user . Normally ,
* anonymous users do not have a session , so the generated token will be
* different on every page request . To generate a token for users without a
* session , manually start a session prior to calling this function .
*
2012-12-04 17:50:15 +00:00
* @ return string
* A 43 - character URL - safe token for validation , based on the user session ID ,
2013-04-07 23:00:15 +00:00
* the hash salt provided from drupal_get_hash_salt (), and the
2012-12-04 17:50:15 +00:00
* 'drupal_private_key' configuration variable .
2013-04-07 23:00:15 +00:00
*
* @ see drupal_get_hash_salt ()
2014-02-20 13:49:37 +00:00
* @ see \Drupal\Core\Access\CsrfTokenGenerator
2014-02-13 00:13:01 +00:00
* @ see drupal_session_start ()
2013-08-13 06:47:07 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: csrfToken () -> get () .
2006-10-31 08:06:18 +00:00
*/
function drupal_get_token ( $value = '' ) {
2013-08-13 06:47:07 +00:00
return \Drupal :: csrfToken () -> get ( $value );
2006-10-31 08:06:18 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Validates a token based on $value , the user session , and the private key .
2006-10-31 08:06:18 +00:00
*
2013-08-13 06:47:07 +00:00
* @ param string $token
2006-10-31 08:06:18 +00:00
* The token to be validated .
2013-08-13 06:47:07 +00:00
* @ param string $value
2006-10-31 08:06:18 +00:00
* An additional value to base the token on .
2013-08-13 06:47:07 +00:00
* @ param bool $skip_anonymous
2006-10-31 08:06:18 +00:00
* Set to true to skip token validation for anonymous users .
2011-12-05 12:52:27 +00:00
*
2013-08-13 06:47:07 +00:00
* @ return bool
2007-10-08 14:08:19 +00:00
* True for a valid token , false for an invalid token . When $skip_anonymous
* is true , the return value will always be true for anonymous users .
2013-08-13 06:47:07 +00:00
*
2014-02-20 13:49:37 +00:00
* @ see \Drupal\Core\Access\CsrfTokenGenerator
2013-08-13 06:47:07 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use return \Drupal :: csrfToken () -> validate () .
2006-10-31 08:06:18 +00:00
*/
function drupal_valid_token ( $token , $value = '' , $skip_anonymous = FALSE ) {
2013-08-13 06:47:07 +00:00
return \Drupal :: csrfToken () -> validate ( $token , $value , $skip_anonymous );
2006-10-31 08:06:18 +00:00
}
2012-05-24 04:52:03 +00:00
/**
* Loads code for subsystems and modules , and registers stream wrappers .
*/
2012-05-09 02:49:07 +00:00
function _drupal_bootstrap_code () {
2014-03-24 08:51:28 +00:00
require_once __DIR__ . '/../../' . Settings :: get ( 'path_inc' , 'core/includes/path.inc' );
2013-08-12 06:05:34 +00:00
require_once __DIR__ . '/module.inc' ;
2013-05-09 09:25:10 +00:00
require_once __DIR__ . '/theme.inc' ;
require_once __DIR__ . '/pager.inc' ;
2014-03-24 08:51:28 +00:00
require_once __DIR__ . '/../../' . Settings :: get ( 'menu_inc' , 'core/includes/menu.inc' );
2013-05-09 09:25:10 +00:00
require_once __DIR__ . '/tablesort.inc' ;
require_once __DIR__ . '/file.inc' ;
require_once __DIR__ . '/unicode.inc' ;
require_once __DIR__ . '/form.inc' ;
require_once __DIR__ . '/mail.inc' ;
require_once __DIR__ . '/ajax.inc' ;
require_once __DIR__ . '/errors.inc' ;
require_once __DIR__ . '/schema.inc' ;
require_once __DIR__ . '/entity.inc' ;
2008-10-15 16:05:51 +00:00
2012-05-26 18:46:07 +00:00
// Load all enabled modules
2013-09-16 03:58:06 +00:00
\Drupal :: moduleHandler () -> loadAll ();
2012-05-24 04:52:03 +00:00
2009-07-27 19:53:18 +00:00
// Make sure all stream wrappers are registered.
file_get_stream_wrappers ();
2014-02-27 04:48:12 +00:00
// Ensure mt_rand() is reseeded to prevent random values from one page load
// being exploited to predict random values in subsequent page loads.
$seed = unpack ( " L " , Crypt :: randomBytes ( 4 ));
mt_srand ( $seed [ 1 ]);
2010-06-28 19:57:34 +00:00
2013-05-28 21:48:53 +00:00
// Set the allowed protocols once we have the config available.
2013-09-16 03:58:06 +00:00
$allowed_protocols = \Drupal :: config ( 'system.filter' ) -> get ( 'protocols' );
2013-05-28 21:48:53 +00:00
if ( ! isset ( $allowed_protocols )) {
// filter_xss_admin() is called by the installer and update.php, in which
// case the configuration may not exist (yet). Provide a minimal default set
// of allowed protocols for these cases.
$allowed_protocols = array ( 'http' , 'https' );
}
2014-03-05 20:22:39 +00:00
UrlHelper :: setAllowedProtocols ( $allowed_protocols );
2012-05-09 02:49:07 +00:00
}
/**
2012-06-26 04:04:49 +00:00
* Temporary BC function for scripts not using DrupalKernel .
2012-05-09 02:49:07 +00:00
*
2012-06-26 04:04:49 +00:00
* DrupalKernel skips this and replicates it via event listeners .
2012-05-24 04:52:03 +00:00
*
2013-10-03 11:26:25 +00:00
* @ see \Drupal\Core\EventSubscriber\PathSubscriber ;
* @ see \Drupal\Core\EventSubscriber\LegacyRequestSubscriber ;
2012-05-09 02:49:07 +00:00
*/
function _drupal_bootstrap_full ( $skip = FALSE ) {
static $called = FALSE ;
if ( $called || $skip ) {
$called = TRUE ;
return ;
}
2010-08-22 12:46:21 +00:00
// Let all modules take action before the menu system handles the request.
2007-11-16 15:35:24 +00:00
// We do not want this while running update.php.
2008-01-07 19:43:29 +00:00
if ( ! defined ( 'MAINTENANCE_MODE' ) || MAINTENANCE_MODE != 'update' ) {
2010-08-22 12:46:21 +00:00
drupal_theme_initialize ();
2007-11-16 15:35:24 +00:00
}
2003-11-18 19:44:36 +00:00
}
2006-01-23 07:54:08 +00:00
/**
2011-12-05 12:52:27 +00:00
* Stores the current page in the cache .
2006-01-23 07:54:08 +00:00
*
2009-11-02 03:12:05 +00:00
* If page_compression is enabled , a gzipped version of the page is stored in
* the cache to avoid compressing the output on each request . The cache entry
* is unzipped in the relatively rare event that the page is requested by a
* client without gzip support .
*
* Page compression requires the PHP zlib extension
2012-03-24 06:14:35 +00:00
* ( http :// php . net / manual / ref . zlib . php ) .
2006-01-23 07:54:08 +00:00
*
2012-08-07 17:05:42 +00:00
* @ param $body
* The response body .
* @ return
* The cached object or NULL if the page cache was not set .
*
2010-01-30 07:54:01 +00:00
* @ see drupal_page_header ()
2006-01-23 07:54:08 +00:00
*/
2013-06-06 08:21:58 +00:00
function drupal_page_set_cache ( Response $response , Request $request ) {
2009-06-02 06:58:17 +00:00
if ( drupal_page_is_cacheable ()) {
2013-08-13 06:29:32 +00:00
// Check if the current page may be compressed.
2013-09-16 03:58:06 +00:00
$page_compressed = \Drupal :: config ( 'system.performance' ) -> get ( 'response.gzip' ) && extension_loaded ( 'zlib' );
2013-08-13 06:29:32 +00:00
2009-04-22 09:45:03 +00:00
$cache = ( object ) array (
2013-08-12 01:58:00 +00:00
'cid' => drupal_page_cache_get_cid ( $request ),
2010-05-18 18:26:30 +00:00
'data' => array (
2013-06-06 08:21:58 +00:00
'body' => $response -> getContent (),
2010-05-18 18:26:30 +00:00
'headers' => array (),
2013-08-13 06:29:32 +00:00
// We need to store whether page was compressed or not,
// because by the time it is read, the configuration might change.
'page_compressed' => $page_compressed ,
2010-05-18 18:26:30 +00:00
),
2014-01-29 10:47:12 +00:00
'tags' => array ( 'content' => TRUE ) + drupal_cache_tags_page_get ( $response ),
2014-01-26 05:21:53 +00:00
'expire' => Cache :: PERMANENT ,
2009-04-22 09:45:03 +00:00
'created' => REQUEST_TIME ,
);
2009-06-02 06:58:17 +00:00
2013-06-06 08:21:58 +00:00
$cache -> data [ 'headers' ] = $response -> headers -> all ();
// Hack: exclude the x-drupal-cache header; it may make it in here because
// of awkwardness in how we defer sending it over in _drupal_page_get_cache.
if ( isset ( $cache -> data [ 'headers' ][ 'x-drupal-cache' ])) {
unset ( $cache -> data [ 'headers' ][ 'x-drupal-cache' ]);
}
// Use the actual timestamp from an Expires header, if available.
if ( $date = $response -> getExpires ()) {
2013-08-10 07:00:02 +00:00
$date = DrupalDateTime :: createFromDateTime ( $date );
2013-06-06 08:21:58 +00:00
$cache -> expire = $date -> getTimestamp ();
2009-04-24 08:16:56 +00:00
}
2009-06-02 06:58:17 +00:00
2010-05-18 18:26:30 +00:00
if ( $cache -> data [ 'body' ]) {
2013-08-13 06:29:32 +00:00
if ( $page_compressed ) {
2010-05-18 18:26:30 +00:00
$cache -> data [ 'body' ] = gzencode ( $cache -> data [ 'body' ], 9 , FORCE_GZIP );
2006-01-23 07:54:08 +00:00
}
2014-02-21 15:21:08 +00:00
\Drupal :: cache ( 'page' ) -> set ( $cache -> cid , $cache -> data , $cache -> expire , $cache -> tags );
2006-01-23 07:54:08 +00:00
}
2009-06-02 06:58:17 +00:00
return $cache ;
2006-01-23 07:54:08 +00:00
}
2006-03-01 21:30:17 +00:00
}
2006-07-10 08:12:31 +00:00
2009-01-27 00:22:27 +00:00
/**
2011-12-05 12:52:27 +00:00
* Sets the main page content value for later use .
2009-01-27 00:22:27 +00:00
*
2009-05-21 21:12:25 +00:00
* Given the nature of the Drupal page handling , this will be called once with
* a string or array . We store that and return it later as the block is being
* displayed .
2009-01-27 00:22:27 +00:00
*
* @ param $content
* A string or renderable array representing the body of the page .
2011-12-05 12:52:27 +00:00
*
2009-01-27 00:22:27 +00:00
* @ return
2010-02-17 02:52:15 +00:00
* If called without $content , a renderable array representing the body of
2010-02-15 22:08:49 +00:00
* the page .
2009-01-27 00:22:27 +00:00
*/
2009-05-21 21:12:25 +00:00
function drupal_set_page_content ( $content = NULL ) {
$content_block = & drupal_static ( __FUNCTION__ , NULL );
2009-10-18 05:28:43 +00:00
$main_content_display = & drupal_static ( 'system_main_content_added' , FALSE );
2013-03-22 15:28:58 +00:00
// Filter out each empty value, though allow '0' and 0, which would be
// filtered out by empty().
if ( $content !== NULL && $content !== '' ) {
2009-05-21 21:12:25 +00:00
$content_block = ( is_array ( $content ) ? $content : array ( 'main' => array ( '#markup' => $content )));
}
else {
2009-10-18 05:28:43 +00:00
// Indicate that the main content has been requested. We assume that
// the module requesting the content will be adding it to the page.
// A module can indicate that it does not handle the content by setting
// the static variable back to FALSE after calling this function.
$main_content_display = TRUE ;
2009-05-21 21:12:25 +00:00
return $content_block ;
}
2009-01-27 00:22:27 +00:00
}
2010-02-25 20:57:39 +00:00
/**
2011-12-05 12:52:27 +00:00
* Pre - render callback : Renders #browsers into #prefix and #suffix.
2010-02-25 20:57:39 +00:00
*
* @ param $elements
* A render array with a '#browsers' property . The '#browsers' property can
* contain any or all of the following keys :
* - 'IE' : If FALSE , the element is not rendered by Internet Explorer . If
* TRUE , the element is rendered by Internet Explorer . Can also be a string
* containing an expression for Internet Explorer to evaluate as part of a
* conditional comment . For example , this can be set to 'lt IE 7' for the
* element to be rendered in Internet Explorer 6 , but not in Internet
2010-03-06 06:39:01 +00:00
* Explorer 7 or higher . Defaults to TRUE .
2010-02-25 20:57:39 +00:00
* - '!IE' : If FALSE , the element is not rendered by browsers other than
* Internet Explorer . If TRUE , the element is rendered by those browsers .
* Defaults to TRUE .
* Examples :
* - To render an element in all browsers , '#browsers' can be left out or set
* to array ( 'IE' => TRUE , '!IE' => TRUE ) .
* - To render an element in Internet Explorer only , '#browsers' can be set
* to array ( '!IE' => FALSE ) .
* - To render an element in Internet Explorer 6 only , '#browsers' can be set
* to array ( 'IE' => 'lt IE 7' , '!IE' => FALSE ) .
* - To render an element in Internet Explorer 8 and higher and in all other
* browsers , '#browsers' can be set to array ( 'IE' => 'gte IE 8' ) .
*
* @ return
2011-04-12 20:54:16 +00:00
* The passed - in element with markup for conditional comments potentially
2010-02-25 20:57:39 +00:00
* added to '#prefix' and '#suffix' .
*/
function drupal_pre_render_conditional_comments ( $elements ) {
$browsers = isset ( $elements [ '#browsers' ]) ? $elements [ '#browsers' ] : array ();
$browsers += array (
'IE' => TRUE ,
'!IE' => TRUE ,
);
// If rendering in all browsers, no need for conditional comments.
if ( $browsers [ 'IE' ] === TRUE && $browsers [ '!IE' ]) {
return $elements ;
}
// Determine the conditional comment expression for Internet Explorer to
// evaluate.
if ( $browsers [ 'IE' ] === TRUE ) {
$expression = 'IE' ;
}
elseif ( $browsers [ 'IE' ] === FALSE ) {
$expression = '!IE' ;
}
else {
$expression = $browsers [ 'IE' ];
}
// Wrap the element's potentially existing #prefix and #suffix properties with
// conditional comment markup. The conditional comment expression is evaluated
// by Internet Explorer only. To control the rendering by other browsers,
// either the "downlevel-hidden" or "downlevel-revealed" technique must be
// used. See http://en.wikipedia.org/wiki/Conditional_comment for details.
$elements += array (
'#prefix' => '' ,
'#suffix' => '' ,
);
if ( ! $browsers [ '!IE' ]) {
// "downlevel-hidden".
$elements [ '#prefix' ] = " \n <!--[if $expression ]> \n " . $elements [ '#prefix' ];
$elements [ '#suffix' ] .= " <![endif]--> \n " ;
}
else {
// "downlevel-revealed".
$elements [ '#prefix' ] = " \n <!--[if $expression ]><!--> \n " . $elements [ '#prefix' ];
$elements [ '#suffix' ] .= " <!--<![endif]--> \n " ;
}
return $elements ;
}
2013-06-09 20:54:08 +00:00
/**
* Pre - render callback : Renders a generic HTML tag with attributes into #markup.
*
* @ param array $element
* An associative array containing :
* - #tag: The tag name to output. Typical tags added to the HTML HEAD:
* - meta : To provide meta information , such as a page refresh .
* - link : To refer to stylesheets and other contextual information .
* - script : To load JavaScript .
* - #attributes: (optional) An array of HTML attributes to apply to the
* tag .
* - #value: (optional) A string containing tag content, such as inline
* CSS .
* - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
* wrapper prefix .
* - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
* wrapper suffix .
*/
function drupal_pre_render_html_tag ( $element ) {
$attributes = isset ( $element [ '#attributes' ]) ? new Attribute ( $element [ '#attributes' ]) : '' ;
if ( ! isset ( $element [ '#value' ])) {
$markup = '<' . $element [ '#tag' ] . $attributes . " /> \n " ;
}
else {
$markup = '<' . $element [ '#tag' ] . $attributes . '>' ;
if ( isset ( $element [ '#value_prefix' ])) {
$markup .= $element [ '#value_prefix' ];
}
$markup .= $element [ '#value' ];
if ( isset ( $element [ '#value_suffix' ])) {
$markup .= $element [ '#value_suffix' ];
}
$markup .= '</' . $element [ '#tag' ] . " > \n " ;
}
2014-01-01 20:32:52 +00:00
if ( ! empty ( $element [ '#noscript' ])) {
$element [ '#markup' ] = '<noscript>' . $markup . '</noscript>' ;
}
else {
$element [ '#markup' ] = $markup ;
}
2013-06-09 20:54:08 +00:00
return $element ;
}
2009-11-03 05:27:18 +00:00
/**
2011-12-05 12:52:27 +00:00
* Pre - render callback : Renders a link into #markup.
2009-11-03 05:27:18 +00:00
*
* Doing so during pre_render gives modules a chance to alter the link parts .
*
* @ param $elements
* A structured array whose keys form the arguments to l () :
* - #title: The link text to pass as argument to l().
2013-08-30 15:28:49 +00:00
* - One of the following
* - #route_name and (optionally) and a #route_parameters array; The route
* name and route parameters which will be passed into the link generator .
* - #href: The system path or URL to pass as argument to l().
* - #options: (optional) An array of options to pass to l() or the link
* generator .
2009-11-03 05:27:18 +00:00
*
* @ return
2011-04-12 20:54:16 +00:00
* The passed - in elements containing a rendered link in '#markup' .
2009-11-03 05:27:18 +00:00
*/
2010-10-21 19:31:39 +00:00
function drupal_pre_render_link ( $element ) {
// By default, link options to pass to l() are normally set in #options.
$element += array ( '#options' => array ());
// However, within the scope of renderable elements, #attributes is a valid
// way to specify attributes, too. Take them into account, but do not override
// attributes from #options.
if ( isset ( $element [ '#attributes' ])) {
$element [ '#options' ] += array ( 'attributes' => array ());
$element [ '#options' ][ 'attributes' ] += $element [ '#attributes' ];
}
// This #pre_render callback can be invoked from inside or outside of a Form
// API context, and depending on that, a HTML ID may be already set in
// different locations. #options should have precedence over Form API's #id.
// #attributes have been taken over into #options above already.
if ( isset ( $element [ '#options' ][ 'attributes' ][ 'id' ])) {
$element [ '#id' ] = $element [ '#options' ][ 'attributes' ][ 'id' ];
}
elseif ( isset ( $element [ '#id' ])) {
$element [ '#options' ][ 'attributes' ][ 'id' ] = $element [ '#id' ];
}
// Conditionally invoke ajax_pre_render_element(), if #ajax is set.
if ( isset ( $element [ '#ajax' ]) && ! isset ( $element [ '#ajax_processed' ])) {
// If no HTML ID was found above, automatically create one.
if ( ! isset ( $element [ '#id' ])) {
$element [ '#id' ] = $element [ '#options' ][ 'attributes' ][ 'id' ] = drupal_html_id ( 'ajax-link' );
}
2011-02-19 00:09:11 +00:00
// If #ajax['path] was not specified, use the href as Ajax request URL.
2010-10-21 19:31:39 +00:00
if ( ! isset ( $element [ '#ajax' ][ 'path' ])) {
$element [ '#ajax' ][ 'path' ] = $element [ '#href' ];
$element [ '#ajax' ][ 'options' ] = $element [ '#options' ];
}
$element = ajax_pre_render_element ( $element );
}
2013-08-30 15:28:49 +00:00
if ( isset ( $element [ '#route_name' ])) {
$element [ '#route_parameters' ] = empty ( $element [ '#route_parameters' ]) ? array () : $element [ '#route_parameters' ];
2013-09-16 03:58:06 +00:00
$element [ '#markup' ] = \Drupal :: linkGenerator () -> generate ( $element [ '#title' ], $element [ '#route_name' ], $element [ '#route_parameters' ], $element [ '#options' ]);
2013-08-30 15:28:49 +00:00
}
else {
$element [ '#markup' ] = l ( $element [ '#title' ], $element [ '#href' ], $element [ '#options' ]);
}
2010-10-21 19:31:39 +00:00
return $element ;
2009-11-03 05:27:18 +00:00
}
2010-11-14 21:04:45 +00:00
/**
2011-12-05 12:52:27 +00:00
* Pre - render callback : Collects child links into a single array .
2010-11-14 21:04:45 +00:00
*
* This function can be added as a pre_render callback for a renderable array ,
2014-02-07 04:28:14 +00:00
* usually one which will be themed by links . html . twig . It iterates through all
2010-11-14 21:04:45 +00:00
* unrendered children of the element , collects any #links properties it finds,
* merges them into the parent element ' s #links array, and prevents those
* children from being rendered separately .
*
* The purpose of this is to allow links to be logically grouped into related
* categories , so that each child group can be rendered as its own list of
* links if drupal_render () is called on it , but calling drupal_render () on the
* parent element will still produce a single list containing all the remaining
* links , regardless of what group they were in .
*
* A typical example comes from node links , which are stored in a renderable
* array similar to this :
* @ code
* $node -> content [ 'links' ] = array (
* '#theme' => 'links__node' ,
2013-01-22 00:20:08 +00:00
* '#pre_render' => array ( 'drupal_pre_render_links' ),
2010-11-14 21:04:45 +00:00
* 'comment' => array (
* '#theme' => 'links__node__comment' ,
* '#links' => array (
* // An array of links associated with node comments, suitable for
2014-02-07 04:28:14 +00:00
* // passing in to links.html.twig.
2010-11-14 21:04:45 +00:00
* ),
* ),
* 'statistics' => array (
* '#theme' => 'links__node__statistics' ,
* '#links' => array (
* // An array of links associated with node statistics, suitable for
2014-02-07 04:28:14 +00:00
* // passing in to links.html.twig.
2010-11-14 21:04:45 +00:00
* ),
* ),
* 'translation' => array (
* '#theme' => 'links__node__translation' ,
* '#links' => array (
* // An array of links associated with node translation, suitable for
2014-02-07 04:28:14 +00:00
* // passing in to links.html.twig.
2010-11-14 21:04:45 +00:00
* ),
* ),
* );
* @ endcode
*
* In this example , the links are grouped by functionality , which can be
* helpful to themers who want to display certain kinds of links independently .
Issue #1898432 by WebDevDude, steveoliver, vlad.dancer, jenlampton, pixelmord, Fabianx, iztok, EVIIILJ, jwilson3, c4rl, Cottser: Convert node module to Twig.
2013-05-24 17:13:55 +00:00
* For example , adding this code to node . html . twig will result in the comment
2010-11-14 21:04:45 +00:00
* links being rendered as a single list :
* @ code
2013-07-15 22:28:09 +00:00
* {{ content . links . comment }}
2010-11-14 21:04:45 +00:00
* @ endcode
*
* ( where $node -> content has been transformed into $content before handing
Issue #1898432 by WebDevDude, steveoliver, vlad.dancer, jenlampton, pixelmord, Fabianx, iztok, EVIIILJ, jwilson3, c4rl, Cottser: Convert node module to Twig.
2013-05-24 17:13:55 +00:00
* control to the node . html . twig template ) .
2010-11-14 21:04:45 +00:00
*
* The pre_render function defined here allows the above flexibility , but also
* allows the following code to be used to render all remaining links into a
* single list , regardless of their group :
* @ code
2013-07-15 22:28:09 +00:00
* {{ content . links }}
2010-11-14 21:04:45 +00:00
* @ endcode
*
* In the above example , this will result in the statistics and translation
* links being rendered together in a single list ( but not the comment links ,
* which were rendered previously on their own ) .
*
* Because of the way this function works , the individual properties of each
* group ( for example , a group - specific #theme property such as
* 'links__node__comment' in the example above , or any other property such as
* #attributes or #pre_render that is attached to it) are only used when that
* group is rendered on its own . When the group is rendered together with other
* children , these child - specific properties are ignored , and only the overall
* properties of the parent are used .
*/
function drupal_pre_render_links ( $element ) {
2013-10-24 15:43:00 +00:00
$element += array ( '#links' => array (), '#attached' => array ());
2010-11-14 21:04:45 +00:00
foreach ( element_children ( $element ) as $key ) {
$child = & $element [ $key ];
// If the child has links which have not been printed yet and the user has
// access to it, merge its links in to the parent.
if ( isset ( $child [ '#links' ]) && empty ( $child [ '#printed' ]) && ( ! isset ( $child [ '#access' ]) || $child [ '#access' ])) {
$element [ '#links' ] += $child [ '#links' ];
// Mark the child as having been printed already (so that its links
// cannot be mistakenly rendered twice).
$child [ '#printed' ] = TRUE ;
}
2013-10-24 15:43:00 +00:00
// Merge attachments.
if ( isset ( $child [ '#attached' ])) {
$element [ '#attached' ] = drupal_merge_attached ( $element [ '#attached' ], $child [ '#attached' ]);
}
2010-11-14 21:04:45 +00:00
}
return $element ;
}
2012-10-04 02:03:22 +00:00
/**
* Pre - render callback : Attaches the dropbutton library and required markup .
*/
function drupal_pre_render_dropbutton ( $element ) {
2014-03-09 19:59:45 +00:00
$element [ '#attached' ][ 'library' ][] = 'core/drupal.dropbutton' ;
2012-10-04 02:03:22 +00:00
$element [ '#attributes' ][ 'class' ][] = 'dropbutton' ;
if ( ! isset ( $element [ '#theme_wrappers' ])) {
$element [ '#theme_wrappers' ] = array ();
}
array_unshift ( $element [ '#theme_wrappers' ], 'dropbutton_wrapper' );
// Enable targeted theming of specific dropbuttons (e.g., 'operations' or
// 'operations__node').
if ( isset ( $element [ '#subtype' ])) {
$element [ '#theme' ] .= '__' . $element [ '#subtype' ];
}
return $element ;
}
2009-01-27 00:22:27 +00:00
/**
2014-01-01 20:32:52 +00:00
* Processes the page render array , enhancing it as necessary .
2009-01-27 00:22:27 +00:00
*
* @ param $page
* A string or array representing the content of a page . The array consists of
* the following keys :
2011-12-05 12:52:27 +00:00
* - #type: Value is always 'page'. This pushes the theming through
2013-05-24 16:46:19 +00:00
* the page template ( required ) .
2011-12-05 12:52:27 +00:00
* - #show_messages: Suppress drupal_get_message() items. Used by Batch
* API ( optional ) .
2009-01-27 00:22:27 +00:00
*
2014-01-01 20:32:52 +00:00
* @ return array
* The processed render array for the page .
*
2009-01-27 00:22:27 +00:00
* @ see hook_page_alter ()
2010-03-26 17:14:46 +00:00
* @ see element_info ()
2009-01-27 00:22:27 +00:00
*/
2014-01-01 20:32:52 +00:00
function drupal_prepare_page ( $page ) {
2009-10-18 05:28:43 +00:00
$main_content_display = & drupal_static ( 'system_main_content_added' , FALSE );
2013-08-16 20:36:55 +00:00
// Pull out the page title to set it back later.
if ( is_array ( $page ) && isset ( $page [ '#title' ])) {
$title = $page [ '#title' ];
}
2009-05-21 21:12:25 +00:00
// Allow menu callbacks to return strings or arbitrary arrays to render.
// If the array returned is not of #type page directly, we need to fill
// in the page with defaults.
if ( is_string ( $page ) || ( is_array ( $page ) && ( ! isset ( $page [ '#type' ]) || ( $page [ '#type' ] != 'page' )))) {
drupal_set_page_content ( $page );
$page = element_info ( 'page' );
2009-01-27 00:22:27 +00:00
}
2009-08-31 16:46:32 +00:00
// Modules can add elements to $page as needed in hook_page_build().
2013-09-16 03:58:06 +00:00
foreach ( \Drupal :: moduleHandler () -> getImplementations ( 'page_build' ) as $module ) {
2009-08-31 16:46:32 +00:00
$function = $module . '_page_build' ;
$function ( $page );
}
2009-01-27 00:22:27 +00:00
// Modules alter the $page as needed. Blocks are populated into regions like
2009-08-11 12:20:26 +00:00
// 'sidebar_first', 'footer', etc.
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'page' , $page );
2009-01-27 00:22:27 +00:00
2014-02-18 13:37:58 +00:00
// The "main" and "secondary" menus are never part of the page-level render
// array and therefore their cache tags will never bubble up into the page
// cache, even though they should be. This happens because they're rendered
// directly by the theme system.
// @todo Remove this once https://drupal.org/node/1869476 lands.
if ( theme_get_setting ( 'features.main_menu' ) && count ( menu_main_menu ())) {
$main_links_source = _menu_get_links_source ( 'main_links' , 'main' );
$page [ 'page_top' ][ '#cache' ][ 'tags' ][ 'menu' ][ $main_links_source ] = $main_links_source ;
}
if ( theme_get_setting ( 'features.secondary_menu' ) && count ( menu_secondary_menu ())) {
$secondary_links_source = _menu_get_links_source ( 'secondary_links' , 'account' );
$page [ 'page_top' ][ '#cache' ][ 'tags' ][ 'menu' ][ $secondary_links_source ] = $secondary_links_source ;
}
2009-10-18 05:28:43 +00:00
// If no module has taken care of the main content, add it to the page now.
// This allows the site to still be usable even if no modules that
// control page regions (for example, the Block module) are enabled.
if ( ! $main_content_display ) {
$page [ 'content' ][ 'system_main' ] = drupal_set_page_content ();
}
2013-08-16 20:36:55 +00:00
// Set back the previously stored title.
if ( isset ( $title )) {
$page [ '#title' ] = $title ;
}
2014-01-01 20:32:52 +00:00
return $page ;
}
/**
* Renders the page , including all theming .
*
* @ param string | array $page
* A string or array representing the content of a page . The array consists of
* the following keys :
* - #type: Value is always 'page'. This pushes the theming through
* the page template ( required ) .
* - #show_messages: Suppress drupal_get_message() items. Used by Batch
* API ( optional ) .
*
* @ return string
* Returns the rendered string .
*
* @ see hook_page_alter ()
* @ see element_info ()
*/
function drupal_render_page ( $page ) {
$page = drupal_prepare_page ( $page );
2009-01-27 00:22:27 +00:00
return drupal_render ( $page );
}
2006-08-10 15:42:33 +00:00
/**
2007-10-08 14:08:19 +00:00
* Renders HTML given a structured array tree .
*
2013-07-17 14:43:41 +00:00
* Renderable arrays have two kinds of key / value pairs : properties and children .
* Properties have keys starting with '#' and their values influence how the
* array will be rendered . Children are all elements whose keys do not start
* with a '#' . Their values should be renderable arrays themselves , which will
* be rendered during the rendering of the parent array . The markup provided by
* the children is typically inserted into the markup generated by the parent
* array .
*
* The process of rendering an element is recursive unless the element defines
* an implemented theme hook in #theme. During each call to drupal_render(), the
* outermost renderable array ( also known as an " element " ) is processed using
* the following steps :
* - If this element has already been printed ( #printed = TRUE) or the user
* does not have access to it ( #access = FALSE), then an empty string is
* returned .
* - If this element has #cache defined then the cached markup for this
* element will be returned if it exists in drupal_render () ' s cache . To use
* drupal_render () caching , set the element ' s #cache property to an
* associative array with one or several of the following keys :
* - 'keys' : An array of one or more keys that identify the element . If
* 'keys' is set , the cache ID is created automatically from these keys .
2014-03-22 22:00:38 +00:00
* Cache keys may either be static ( just strings ) or tokens ( placeholders
* that are converted to static keys by the @ cache_contexts service ,
* depending on the request ) . See drupal_render_cid_create () .
2013-07-17 14:43:41 +00:00
* - 'cid' : Specify the cache ID directly . Either 'keys' or 'cid' is
2014-03-22 22:00:38 +00:00
* required . If 'cid' is set , 'keys' is ignored . Use only if you have
* special requirements .
2013-07-17 14:43:41 +00:00
* - 'expire' : Set to one of the cache lifetime constants .
* - 'bin' : Specify a cache bin to cache the element in . Default is 'cache' .
* - If this element has #type defined and the default attributes for this
* element have not already been merged in ( #defaults_loaded = TRUE) then
* the defaults for this type of element , defined in hook_element_info (),
* are merged into the array . #defaults_loaded is set by functions that
* process render arrays and call element_info () before passing the array to
* drupal_render (), such as form_builder () in the Form API .
* - If this element has an array of #pre_render functions defined, they are
* called sequentially to modify the element before rendering . After all the
* #pre_render functions have been called, #printed is checked a second time
* in case a #pre_render function flags the element as printed.
* - The child elements of this element are sorted by weight using uasort () in
* element_children () . Since this is expensive , when passing already sorted
* elements to drupal_render (), for example from a database query , set
* $elements [ '#sorted' ] = TRUE to avoid sorting them a second time .
* - The main render phase to produce #children for this element takes place:
* - If this element has #theme defined and #theme is an implemented theme
2014-02-18 10:54:10 +00:00
* hook / suggestion then _theme () is called and must render both the element
* and its children . If #render_children is set, _theme() will not be
* called . #render_children is usually only set internally by _theme() so
2013-07-17 14:43:41 +00:00
* that we can avoid the situation where drupal_render () called from
* within a theme preprocess function creates an infinite loop .
* - If this element does not have a defined #theme, or the defined #theme
* hook is not implemented , or #render_children is set, then
* drupal_render () is called recursively on each of the child elements of
* this element , and the result of each is concatenated onto #children.
* This is skipped if #children is not empty at this point.
* - Once #children has been rendered for this element, if #theme is not
* implemented and #markup is set for this element, #markup will be
* prepended to #children.
* - If this element has #states defined then JavaScript state information is
* added to this element ' s #attached attribute by drupal_process_states().
* - If this element has #attached defined then any required libraries,
* JavaScript , CSS , or other custom data are added to the current page by
* drupal_process_attached () .
* - If this element has an array of #theme_wrappers defined and
* #render_children is not set, #children is then re-rendered by passing the
2014-02-18 10:54:10 +00:00
* element in its current state to _theme () successively for each item in
2013-08-05 13:40:57 +00:00
* #theme_wrappers. Since #theme and #theme_wrappers hooks often define
* variables with the same names it is possible to explicitly override each
* attribute passed to each #theme_wrappers hook by setting the hook name as
* the key and an array of overrides as the value in #theme_wrappers array.
* For example , if we have a render element as follows :
* @ code
* array (
* '#theme' => 'image' ,
* '#attributes' => array ( 'class' => 'foo' ),
* '#theme_wrappers' => array ( 'container' ),
* );
* @ endcode
* and we need to pass the class ' bar ' as an attribute for ' container ' , we
* can rewrite our element thus :
* @ code
* array (
* '#theme' => 'image' ,
* '#attributes' => array ( 'class' => 'foo' ),
* '#theme_wrappers' => array (
* 'container' => array (
* '#attributes' => array ( 'class' => 'bar' ),
* ),
* ),
* );
* @ endcode
2013-07-17 14:43:41 +00:00
* - If this element has an array of #post_render functions defined, they are
* called sequentially to modify the rendered #children. Unlike #pre_render
* functions , #post_render functions are passed both the rendered #children
* attribute as a string and the element itself .
* - If this element has #prefix and/or #suffix defined, they are concatenated
* to #children.
* - If this element has #cache defined, the rendered output of this element
2013-11-18 14:19:10 +00:00
* is saved to drupal_render () ' s internal cache . This includes the changes
* made by #post_render.
* - If this element ( or any of its children ) has an array of
* #post_render_cache functions defined, they are called sequentially to
* replace placeholders in the final #markup and extend #attached.
* Placeholders must contain a unique token , to guarantee that e . g . samples
* of placeholders are not replaced also . For this , a special element named
* 'render_cache_placeholder' is provided .
* Note that these callbacks run always : when hitting the render cache , when
* missing , or when render caching is not used at all . This is done to allow
* any Drupal module to customize other render arrays without breaking the
* render cache if it is enabled , and to not require it to use other logic
* when render caching is disabled .
2013-07-17 14:43:41 +00:00
* - #printed is set to TRUE for this element to ensure that it is only
* rendered once .
* - The final value of #children for this element is returned as the rendered
* output .
2006-08-10 15:42:33 +00:00
*
2013-04-21 19:17:35 +00:00
* @ param array $elements
2006-08-10 15:42:33 +00:00
* The structured array describing the data to be rendered .
2013-11-18 14:19:10 +00:00
* @ param bool $is_recursive_call
* Whether this is a recursive call or not , for internal use .
2011-12-05 12:52:27 +00:00
*
2013-04-21 19:17:35 +00:00
* @ return string
2006-08-10 15:42:33 +00:00
* The rendered HTML .
2013-07-17 14:43:41 +00:00
*
* @ see element_info ()
2014-02-18 10:54:10 +00:00
* @ see _theme ()
2013-07-17 14:43:41 +00:00
* @ see drupal_process_states ()
* @ see drupal_process_attached ()
2006-08-10 15:42:33 +00:00
*/
2013-11-18 14:19:10 +00:00
function drupal_render ( & $elements , $is_recursive_call = FALSE ) {
2009-01-23 14:23:27 +00:00
// Early-return nothing if user does not have access.
2009-11-16 05:11:01 +00:00
if ( empty ( $elements ) || ( isset ( $elements [ '#access' ]) && ! $elements [ '#access' ])) {
2013-04-21 19:17:35 +00:00
return '' ;
2009-02-03 18:55:32 +00:00
}
// Do not print elements twice.
2009-12-14 13:32:53 +00:00
if ( ! empty ( $elements [ '#printed' ])) {
2013-04-21 19:17:35 +00:00
return '' ;
2006-08-10 15:42:33 +00:00
}
2006-08-22 11:13:04 +00:00
2013-11-18 14:19:10 +00:00
// Try to fetch the prerendered element from cache, run any #post_render_cache
// callbacks and return the final markup.
2012-01-19 12:47:15 +00:00
if ( isset ( $elements [ '#cache' ])) {
2013-11-18 14:19:10 +00:00
$cached_element = drupal_render_cache_get ( $elements );
if ( $cached_element !== FALSE ) {
$elements = $cached_element ;
// Only when we're not in a recursive drupal_render() call,
// #post_render_cache callbacks must be executed, to prevent breaking the
// render cache in case of nested elements with #cache set.
if ( ! $is_recursive_call ) {
_drupal_render_process_post_render_cache ( $elements );
}
return $elements [ '#markup' ];
2012-01-19 12:47:15 +00:00
}
2009-08-31 17:06:10 +00:00
}
2009-11-16 05:11:01 +00:00
2009-02-03 18:55:32 +00:00
// If the default values for this element have not been loaded yet, populate
2007-06-28 07:48:41 +00:00
// them.
2009-02-03 18:55:32 +00:00
if ( isset ( $elements [ '#type' ]) && empty ( $elements [ '#defaults_loaded' ])) {
$elements += element_info ( $elements [ '#type' ]);
}
2009-03-17 22:35:07 +00:00
2007-06-28 07:48:41 +00:00
// Make any final changes to the element before it is rendered. This means
2007-07-02 14:41:37 +00:00
// that the $element or the children can be altered or corrected before the
2007-06-28 07:48:41 +00:00
// element is rendered into the final text.
if ( isset ( $elements [ '#pre_render' ])) {
2013-05-22 00:22:44 +00:00
foreach ( $elements [ '#pre_render' ] as $callable ) {
$elements = call_user_func ( $callable , $elements );
2007-06-28 07:48:41 +00:00
}
}
2009-12-14 13:32:53 +00:00
// Allow #pre_render to abort rendering.
if ( ! empty ( $elements [ '#printed' ])) {
2013-04-21 19:17:35 +00:00
return '' ;
2009-12-14 13:32:53 +00:00
}
2014-02-28 10:06:00 +00:00
// Collect all #post_render_cache callbacks associated with this element when:
// - about to store this element in the render cache, or when;
// - about to apply #post_render_cache callbacks.
if ( isset ( $elements [ '#cache' ]) || ! $is_recursive_call ) {
$post_render_cache = drupal_render_collect_post_render_cache ( $elements );
if ( $post_render_cache ) {
$elements [ '#post_render_cache' ] = $post_render_cache ;
}
}
2013-10-13 12:35:20 +00:00
// Add any JavaScript state information associated with the element.
if ( ! empty ( $elements [ '#states' ])) {
drupal_process_states ( $elements );
}
2014-03-12 15:46:33 +00:00
// Add additional libraries, CSS, JavaScript and other custom
// attached data associated with this element.
if ( ! empty ( $elements [ '#attached' ])) {
drupal_process_attached ( $elements );
}
2010-01-03 06:54:41 +00:00
// Get the children of the element, sorted by weight.
2013-12-10 21:23:03 +00:00
$children = Element :: children ( $elements , TRUE );
2010-01-03 06:54:41 +00:00
2009-11-03 05:27:18 +00:00
// Initialize this element's #children, unless a #pre_render callback already
// preset #children.
if ( ! isset ( $elements [ '#children' ])) {
$elements [ '#children' ] = '' ;
}
2013-06-30 12:38:12 +00:00
// Assume that if #theme is set it represents an implemented hook.
$theme_is_implemented = isset ( $elements [ '#theme' ]);
2009-02-03 18:55:32 +00:00
// Call the element's #theme function if it is set. Then any children of the
2013-05-19 23:34:52 +00:00
// element have to be rendered there. If the internal #render_children
// property is set, do not call the #theme function to prevent infinite
// recursion.
2013-06-30 12:38:12 +00:00
if ( $theme_is_implemented && ! isset ( $elements [ '#render_children' ])) {
2014-02-18 10:54:10 +00:00
$elements [ '#children' ] = _theme ( $elements [ '#theme' ], $elements );
2013-06-30 12:38:12 +00:00
2014-02-18 10:54:10 +00:00
// If _theme() returns FALSE this means that the hook in #theme was not
// found in the registry and so we need to update our flag accordingly. This
// is common for theme suggestions.
2013-06-30 12:38:12 +00:00
$theme_is_implemented = ( $elements [ '#children' ] !== FALSE );
2013-06-24 10:08:43 +00:00
}
2013-06-30 12:38:12 +00:00
// If #theme is not implemented or #render_children is set and the element has
// an empty #children attribute, render the children now. This is the same
// process as drupal_render_children() but is inlined for speed.
if (( ! $theme_is_implemented || isset ( $elements [ '#render_children' ])) && empty ( $elements [ '#children' ])) {
2010-01-03 06:54:41 +00:00
foreach ( $children as $key ) {
2013-11-18 14:19:10 +00:00
$elements [ '#children' ] .= drupal_render ( $elements [ $key ], TRUE );
2009-11-07 14:02:31 +00:00
}
2013-06-24 10:08:43 +00:00
}
2013-06-30 12:38:12 +00:00
// If #theme is not implemented and the element has raw #markup as a
// fallback, prepend the content in #markup to #children. In this case
// #children will contain whatever is provided by #pre_render prepended to
// what is rendered recursively above. If #theme is implemented then it is
// the responsibility of that theme implementation to render #markup if
// required. Eventually #theme_wrappers will expect both #markup and
// #children to be a single string as #children.
if ( ! $theme_is_implemented && isset ( $elements [ '#markup' ])) {
2013-06-24 10:08:43 +00:00
$elements [ '#children' ] = $elements [ '#markup' ] . $elements [ '#children' ];
2012-11-16 13:05:26 +00:00
}
2006-08-10 15:42:33 +00:00
2009-08-04 06:38:57 +00:00
// Let the theme functions in #theme_wrappers add markup around the rendered
2009-02-03 18:55:32 +00:00
// children.
2012-12-13 12:23:00 +00:00
// #states and #attached have to be processed before #theme_wrappers, because
// the #type 'page' render array from drupal_render_page() would render the
2013-10-03 20:55:34 +00:00
// $page and wrap it into the html.html.twig template without the attached
2012-12-13 12:23:00 +00:00
// assets otherwise.
2013-05-19 23:34:52 +00:00
// If the internal #render_children property is set, do not call the
// #theme_wrappers function(s) to prevent infinite recursion.
if ( isset ( $elements [ '#theme_wrappers' ]) && ! isset ( $elements [ '#render_children' ])) {
2013-08-05 13:40:57 +00:00
foreach ( $elements [ '#theme_wrappers' ] as $key => $value ) {
// If the value of a #theme_wrappers item is an array then the theme hook
// is found in the key of the item and the value contains attribute
// overrides. Attribute overrides replace key/value pairs in $elements for
2014-02-18 10:54:10 +00:00
// only this _theme() call. This allows #theme hooks and #theme_wrappers
2013-08-05 13:40:57 +00:00
// hooks to share variable names without conflict or ambiguity.
$wrapper_elements = $elements ;
2013-08-21 05:55:44 +00:00
if ( is_string ( $key )) {
2013-08-05 13:40:57 +00:00
$wrapper_hook = $key ;
foreach ( $value as $attribute => $override ) {
$wrapper_elements [ $attribute ] = $override ;
}
}
else {
$wrapper_hook = $value ;
}
2014-02-18 10:54:10 +00:00
$elements [ '#children' ] = _theme ( $wrapper_hook , $wrapper_elements );
2009-08-04 06:38:57 +00:00
}
2006-08-10 15:42:33 +00:00
}
2009-02-03 18:55:32 +00:00
// Filter the outputted content and make any last changes before the
// content is sent to the browser. The changes are made on $content
// which allows the output'ed text to be filtered.
if ( isset ( $elements [ '#post_render' ])) {
2013-05-22 00:22:44 +00:00
foreach ( $elements [ '#post_render' ] as $callable ) {
$elements [ '#children' ] = call_user_func ( $callable , $elements [ '#children' ], $elements );
2007-06-28 07:48:41 +00:00
}
2006-08-10 15:42:33 +00:00
}
2009-07-13 21:09:54 +00:00
2013-11-18 14:19:10 +00:00
// We store the resulting output in $elements['#markup'], to be consistent
// with how render cached output gets stored. This ensures that
// #post_render_cache callbacks get the same data to work with, no matter if
// #cache is disabled, #cache is enabled, there is a cache hit or miss.
2009-02-03 18:55:32 +00:00
$prefix = isset ( $elements [ '#prefix' ]) ? $elements [ '#prefix' ] : '' ;
$suffix = isset ( $elements [ '#suffix' ]) ? $elements [ '#suffix' ] : '' ;
2013-11-18 14:19:10 +00:00
$elements [ '#markup' ] = $prefix . $elements [ '#children' ] . $suffix ;
2009-02-03 18:55:32 +00:00
2014-03-18 10:17:33 +00:00
// Collect all cache tags. This allows the caller of drupal_render() to also
// access the complete list of cache tags.
if ( ! $is_recursive_call || isset ( $elements [ '#cache' ])) {
$elements [ '#cache' ][ 'tags' ] = drupal_render_collect_cache_tags ( $elements );
}
2014-01-16 13:18:41 +00:00
// Cache the processed element if #cache is set.
if ( isset ( $elements [ '#cache' ])) {
2013-11-18 14:19:10 +00:00
drupal_render_cache_set ( $elements [ '#markup' ], $elements );
}
// Only when we're not in a recursive drupal_render() call,
// #post_render_cache callbacks must be executed, to prevent breaking the
// render cache in case of nested elements with #cache set.
//
// By running them here, we ensure that:
// - they run when #cache is disabled,
// - they run when #cache is enabled and there is a cache miss.
// Only the case of a cache hit when #cache is enabled, is not handled here,
// that is handled earlier in drupal_render().
if ( ! $is_recursive_call ) {
_drupal_render_process_post_render_cache ( $elements );
2009-08-31 17:06:10 +00:00
}
2009-02-03 18:55:32 +00:00
$elements [ '#printed' ] = TRUE ;
2013-11-18 14:19:10 +00:00
return $elements [ '#markup' ];
2009-02-03 18:55:32 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Renders children of an element and concatenates them .
2009-02-03 18:55:32 +00:00
*
2014-01-14 07:05:39 +00:00
* @ param array $element
2009-02-03 18:55:32 +00:00
* The structured array whose children shall be rendered .
2014-01-14 07:05:39 +00:00
* @ param array $children_keys
* ( optional ) If the keys of the element ' s children are already known , they
* can be passed in to save another run of element_children () .
*
* @ return string
* The rendered HTML of all children of the element .
* @ see drupal_render ()
2009-02-03 18:55:32 +00:00
*/
2009-02-05 01:21:16 +00:00
function drupal_render_children ( & $element , $children_keys = NULL ) {
2009-02-03 18:55:32 +00:00
if ( $children_keys === NULL ) {
$children_keys = element_children ( $element );
}
$output = '' ;
foreach ( $children_keys as $key ) {
2009-11-16 05:11:01 +00:00
if ( ! empty ( $element [ $key ])) {
$output .= drupal_render ( $element [ $key ]);
}
2009-02-03 18:55:32 +00:00
}
return $output ;
2006-08-10 15:42:33 +00:00
}
2009-06-18 21:19:02 +00:00
/**
2011-12-05 12:52:27 +00:00
* Renders an element .
2009-06-18 21:19:02 +00:00
*
2009-07-13 21:09:54 +00:00
* This function renders an element using drupal_render () . The top level
2011-01-12 23:15:26 +00:00
* element is shown with show () before rendering , so it will always be rendered
* even if hide () had been previously used on it .
2009-06-18 21:19:02 +00:00
*
2011-01-12 23:15:26 +00:00
* @ param $element
* The element to be rendered .
*
* @ return
* The rendered element .
2009-06-18 21:19:02 +00:00
*
* @ see drupal_render ()
* @ see show ()
* @ see hide ()
*/
function render ( & $element ) {
2012-11-03 17:36:10 +00:00
if ( ! $element && $element !== 0 ) {
return NULL ;
}
2009-06-18 21:19:02 +00:00
if ( is_array ( $element )) {
show ( $element );
2014-02-28 10:06:00 +00:00
return drupal_render ( $element , TRUE );
2009-06-18 21:19:02 +00:00
}
else {
2009-07-13 21:09:54 +00:00
// Safe-guard for inappropriate use of render() on flat variables: return
// the variable as-is.
return $element ;
2009-06-18 21:19:02 +00:00
}
}
/**
2011-12-05 12:52:27 +00:00
* Hides an element from later rendering .
2009-06-18 21:19:02 +00:00
*
2011-01-12 23:15:26 +00:00
* The first time render () or drupal_render () is called on an element tree ,
* as each element in the tree is rendered , it is marked with a #printed flag
* and the rendered children of the element are cached . Subsequent calls to
* render () or drupal_render () will not traverse the child tree of this element
* again : they will just use the cached children . So if you want to hide an
* element , be sure to call hide () on the element before its parent tree is
* rendered for the first time , as it will have no effect on subsequent
* renderings of the parent tree .
*
* @ param $element
* The element to be hidden .
*
* @ return
* The element .
*
2009-06-18 21:19:02 +00:00
* @ see render ()
* @ see show ()
*/
function hide ( & $element ) {
$element [ '#printed' ] = TRUE ;
return $element ;
}
/**
2011-12-05 12:52:27 +00:00
* Shows a hidden element for later rendering .
2011-01-12 23:15:26 +00:00
*
* You can also use render ( $element ), which shows the element while rendering
* it .
*
* The first time render () or drupal_render () is called on an element tree ,
* as each element in the tree is rendered , it is marked with a #printed flag
* and the rendered children of the element are cached . Subsequent calls to
* render () or drupal_render () will not traverse the child tree of this element
* again : they will just use the cached children . So if you want to show an
* element , be sure to call show () on the element before its parent tree is
* rendered for the first time , as it will have no effect on subsequent
* renderings of the parent tree .
2009-06-18 21:19:02 +00:00
*
2011-01-12 23:15:26 +00:00
* @ param $element
* The element to be shown .
*
* @ return
* The element .
2009-06-18 21:19:02 +00:00
*
* @ see render ()
* @ see hide ()
*/
function show ( & $element ) {
$element [ '#printed' ] = FALSE ;
return $element ;
}
2009-08-31 17:06:10 +00:00
/**
2013-11-18 14:19:10 +00:00
* Gets the cached , prerendered element of a renderable element from the cache .
2009-09-28 22:22:54 +00:00
*
2013-11-18 14:19:10 +00:00
* @ param array $elements
2009-08-31 17:06:10 +00:00
* A renderable array .
2011-12-05 12:52:27 +00:00
*
2013-11-18 14:19:10 +00:00
* @ return array
* A renderable array , with the original element and all its children pre -
* rendered , or FALSE if no cached copy of the element is available .
2011-12-05 12:52:27 +00:00
*
* @ see drupal_render ()
* @ see drupal_render_cache_set ()
2009-08-31 17:06:10 +00:00
*/
2013-11-18 14:19:10 +00:00
function drupal_render_cache_get ( array $elements ) {
2013-09-16 03:58:06 +00:00
if ( ! \Drupal :: request () -> isMethodSafe () || ! $cid = drupal_render_cid_create ( $elements )) {
2009-08-31 17:06:10 +00:00
return FALSE ;
}
$bin = isset ( $elements [ '#cache' ][ 'bin' ]) ? $elements [ '#cache' ][ 'bin' ] : 'cache' ;
2014-02-21 15:21:08 +00:00
if ( ! empty ( $cid ) && $cache = \Drupal :: cache ( $bin ) -> get ( $cid )) {
2013-11-18 14:19:10 +00:00
$cached_element = $cache -> data ;
2009-09-05 15:05:05 +00:00
// Add additional libraries, JavaScript, CSS and other data attached
// to this element.
2013-11-18 14:19:10 +00:00
if ( isset ( $cached_element [ '#attached' ])) {
drupal_process_attached ( $cached_element );
2009-11-16 20:31:27 +00:00
}
2013-11-18 14:19:10 +00:00
// Return the cached element.
return $cached_element ;
2009-08-31 17:06:10 +00:00
}
return FALSE ;
}
/**
2011-12-05 12:52:27 +00:00
* Caches the rendered output of a renderable element .
2009-08-31 17:06:10 +00:00
*
2011-12-05 12:52:27 +00:00
* This is called by drupal_render () if the #cache property is set on an
* element .
2009-08-31 17:06:10 +00:00
*
* @ param $markup
* The rendered output string of $elements .
2013-11-18 14:19:10 +00:00
* @ param array $elements
2009-08-31 17:06:10 +00:00
* A renderable array .
2011-12-05 12:52:27 +00:00
*
* @ see drupal_render_cache_get ()
2009-08-31 17:06:10 +00:00
*/
2013-11-18 14:19:10 +00:00
function drupal_render_cache_set ( & $markup , array $elements ) {
2009-09-28 22:22:54 +00:00
// Create the cache ID for the element.
2013-09-16 03:58:06 +00:00
if ( ! \Drupal :: request () -> isMethodSafe () || ! $cid = drupal_render_cid_create ( $elements )) {
2009-08-31 17:06:10 +00:00
return FALSE ;
}
2009-12-11 16:56:10 +00:00
// Cache implementations are allowed to modify the markup, to support
// replacing markup with edge-side include commands. The supporting cache
// backend will store the markup in some other key (like
// $data['#real-value']) and return an include command instead. When the
// ESI command is executed by the content accelerator, the real value can
// be retrieved and used.
2013-11-18 14:19:10 +00:00
$data [ '#markup' ] = $markup ;
2009-09-05 15:05:05 +00:00
// Persist attached data associated with this element.
2011-02-04 21:36:31 +00:00
$attached = drupal_render_collect_attached ( $elements , TRUE );
if ( $attached ) {
$data [ '#attached' ] = $attached ;
2009-11-16 05:11:01 +00:00
}
2013-11-18 14:19:10 +00:00
// Persist #post_render_cache callbacks associated with this element.
if ( isset ( $elements [ '#post_render_cache' ])) {
$data [ '#post_render_cache' ] = $elements [ '#post_render_cache' ];
}
2014-03-18 10:17:33 +00:00
// Persist cache tags associated with this element.
if ( isset ( $elements [ '#cache' ][ 'tags' ])) {
$data [ '#cache' ][ 'tags' ] = $elements [ '#cache' ][ 'tags' ];
}
2009-08-31 17:06:10 +00:00
$bin = isset ( $elements [ '#cache' ][ 'bin' ]) ? $elements [ '#cache' ][ 'bin' ] : 'cache' ;
2014-01-26 05:21:53 +00:00
$expire = isset ( $elements [ '#cache' ][ 'expire' ]) ? $elements [ '#cache' ][ 'expire' ] : Cache :: PERMANENT ;
2014-03-18 10:17:33 +00:00
\Drupal :: cache ( $bin ) -> set ( $cid , $data , $expire , $elements [ '#cache' ][ 'tags' ]);
2009-08-31 17:06:10 +00:00
}
2013-11-18 14:19:10 +00:00
/**
* Generates a render cache placeholder .
*
* This is used by drupal_pre_render_render_cache_placeholder () to generate
* placeholders , but should also be called by #post_render_cache callbacks that
* want to replace the placeholder with the final markup .
*
* @ param callable $callback
* The #post_render_cache callback that will replace the placeholder with its
* eventual markup .
* @ param array $context
* An array providing context for the #post_render_cache callback.
* @ param string $token
* A unique token to uniquely identify the placeholder .
*
* @ see drupal_render_cache_get ()
*/
function drupal_render_cache_generate_placeholder ( $callback , array $context , $token ) {
// Serialize the context into a HTML attribute; unserializing is unnecessary.
$context_attribute = '' ;
foreach ( $context as $key => $value ) {
$context_attribute .= $key . ':' . $value . ';' ;
}
2014-02-09 01:24:09 +00:00
return '<drupal:render-cache-placeholder callback="' . $callback . '" context="' . $context_attribute . '" token="' . $token . '" />' ;
2013-11-18 14:19:10 +00:00
}
/**
* Pre - render callback : Renders a render cache placeholder into #markup.
*
* @ param $elements
* A structured array whose keys form the arguments to l () :
* - #callback: The #post_render_cache callback that will replace the
* placeholder with its eventual markup .
* - #context: An array providing context for the #post_render_cache callback.
*
* @ return
* The passed - in element containing a render cache placeholder in '#markup'
* and a callback with context , keyed by a generated unique token in
* '#post_render_cache' .
*
* @ see drupal_render_cache_generate_placeholder ()
*/
function drupal_pre_render_render_cache_placeholder ( $element ) {
$callback = $element [ '#callback' ];
if ( ! is_callable ( $callback )) {
throw new Exception ( t ( '#callback must be a callable function.' ));
}
$context = $element [ '#context' ];
if ( ! is_array ( $context )) {
throw new Exception ( t ( '#context must be an array.' ));
}
2014-02-27 04:48:12 +00:00
$token = \Drupal\Component\Utility\Crypt :: randomBytesBase64 ( 55 );
2013-11-18 14:19:10 +00:00
// Generate placeholder markup and store #post_render_cache callback.
$element [ '#markup' ] = drupal_render_cache_generate_placeholder ( $callback , $context , $token );
$element [ '#post_render_cache' ][ $callback ][ $token ] = $context ;
return $element ;
}
/**
* Processes #post_render_cache callbacks.
*
* #post_render_cache callbacks may modify:
* - #markup: to replace placeholders
* - #attached: to add libraries or JavaScript settings
*
* Note that in either of these cases , #post_render_cache callbacks are
* implicitly idempotent : a placeholder that has been replaced can ' t be replaced
* again , and duplicate attachments are ignored .
*
* @ param array & $elements
* The structured array describing the data being rendered .
*
* @ see drupal_render ()
* @ see drupal_render_collect_post_render_cache
*/
function _drupal_render_process_post_render_cache ( array & $elements ) {
if ( isset ( $elements [ '#post_render_cache' ])) {
// Call all #post_render_cache callbacks, while passing the provided context
// and if keyed by a number, no token is passed, otherwise, the token string
// is passed to the callback as well. This token is used to uniquely
// identify the placeholder in the markup.
$modified_elements = $elements ;
foreach ( $elements [ '#post_render_cache' ] as $callback => $options ) {
foreach ( $elements [ '#post_render_cache' ][ $callback ] as $token => $context ) {
// The advanced option, when setting #post_render_cache directly.
if ( is_numeric ( $token )) {
$modified_elements = call_user_func_array ( $callback , array ( $modified_elements , $context ));
}
// The simple option, when using the standard placeholders, and hence
// also when using #type => render_cache_placeholder.
else {
// Call #post_render_cache callback to generate the element that will
// fill in the placeholder.
$generated_element = call_user_func_array ( $callback , array ( $context ));
// Update #attached based on the generated element.
if ( isset ( $generated_element [ '#attached' ])) {
if ( ! isset ( $modified_elements [ '#attached' ])) {
$modified_elements [ '#attached' ] = array ();
}
$modified_elements [ '#attached' ] = drupal_merge_attached ( $modified_elements [ '#attached' ], drupal_render_collect_attached ( $generated_element , TRUE ));
}
// Replace the placeholder with the rendered markup of the generated
// element.
$placeholder = drupal_render_cache_generate_placeholder ( $callback , $context , $token );
$modified_elements [ '#markup' ] = str_replace ( $placeholder , drupal_render ( $generated_element ), $modified_elements [ '#markup' ]);
}
}
}
// Only retain changes to the #markup and #attached properties, as would be
// the case when the render cache was actually being used.
$elements [ '#markup' ] = $modified_elements [ '#markup' ];
if ( isset ( $modified_elements [ '#attached' ])) {
$elements [ '#attached' ] = $modified_elements [ '#attached' ];
}
// Make sure that any attachments added in #post_render_cache callbacks are
// also executed.
if ( isset ( $elements [ '#attached' ])) {
drupal_process_attached ( $elements );
}
}
}
/**
* Collects #post_render_cache for an element and its children into a single
* array .
*
* When caching elements , it is necessary to collect all #post_render_cache
* callbacks into a single array , from both the element itself and all child
* elements . This allows drupal_render () to execute all of them when the element
* is retrieved from the render cache .
*
2014-02-28 10:06:00 +00:00
* Note : the theme system may render child elements directly ( e . g . rendering a
* node causes its template to be rendered , which causes the node links to be
* drupal_render () ed ) . On top of that , the theme system transforms render arrays
* into HTML strings . These two facts combined imply that it is impossible for
* #post_render_cache callbacks to bubble up to the root of the render array.
* Therefore , drupal_render_collect_post_render_cache () must be called * before *
* #theme callbacks, so that it has a chance to examine the full render array.
* In short : in order to examine the full render array for #post_render_cache
* callbacks , it must use post - order tree traversal , whereas drupal_render ()
* itself uses pre - order tree traversal .
*
* @ param array & $elements
* The element to collect #post_render_cache callbacks for.
2013-11-18 14:19:10 +00:00
* @ param array $callbacks
* Internal use only . The #post_render_callbacks array so far.
* @ param bool $is_root_element
* Internal use only . Whether the element being processed is the root or not .
*
* @ return
* The #post_render_cache array for this element and its descendants.
*
* @ see drupal_render ()
* @ see _drupal_render_process_post_render_cache ()
*/
2014-02-28 10:06:00 +00:00
function drupal_render_collect_post_render_cache ( array & $elements , array $callbacks = array (), $is_root_element = TRUE ) {
// Try to fetch the prerendered element from cache, to determine
// #post_render_cache callbacks for this element and all its children. If we
// don't do this, then the #post_render_cache tokens will be re-generated, but
// they would no longer match the tokens in the render cached markup, causing
// the render cache placeholder markup to be sent to the end user!
$retrieved_from_cache = FALSE ;
if ( ! $is_root_element && isset ( $elements [ '#cache' ])) {
$cached_element = drupal_render_cache_get ( $elements );
if ( $cached_element !== FALSE && isset ( $cached_element [ '#post_render_cache' ])) {
$elements [ '#post_render_cache' ] = $cached_element [ '#post_render_cache' ];
$retrieved_from_cache = TRUE ;
}
}
// If this is a render cache placeholder that hasn't been rendered yet, then
// render it now, because we must be able to collect its #post_render_cache
// callback.
if ( ! isset ( $elements [ '#post_render_cache' ]) && isset ( $elements [ '#type' ]) && $elements [ '#type' ] === 'render_cache_placeholder' ) {
$elements = drupal_pre_render_render_cache_placeholder ( $elements );
}
// Collect all #post_render_cache callbacks for this element.
2013-11-18 14:19:10 +00:00
if ( isset ( $elements [ '#post_render_cache' ])) {
$callbacks = NestedArray :: mergeDeep ( $callbacks , $elements [ '#post_render_cache' ]);
}
2014-02-28 10:06:00 +00:00
// Collect the #post_render_cache callbacks for all child elements, unless
// we've already collected them above by retrieving this element (and its
// children) from the render cache.
if ( ! $retrieved_from_cache && $children = element_children ( $elements )) {
2013-11-18 14:19:10 +00:00
foreach ( $children as $child ) {
$callbacks = drupal_render_collect_post_render_cache ( $elements [ $child ], $callbacks , FALSE );
}
}
return $callbacks ;
}
2011-02-04 21:36:31 +00:00
/**
2011-12-05 12:52:27 +00:00
* Collects #attached for an element and its children into a single array.
2011-02-04 21:36:31 +00:00
*
2011-02-19 00:09:11 +00:00
* When caching elements , it is necessary to collect all libraries , JavaScript
2011-02-04 21:36:31 +00:00
* and CSS into a single array , from both the element itself and all child
* elements . This allows drupal_render () to add these back to the page when the
* element is returned from cache .
*
* @ param $elements
* The element to collect #attached from.
* @ param $return
* Whether to return the attached elements and reset the internal static .
*
* @ return
* The #attached array for this element and its descendants.
*/
function drupal_render_collect_attached ( $elements , $return = FALSE ) {
$attached = & drupal_static ( __FUNCTION__ , array ());
// Collect all #attached for this element.
if ( isset ( $elements [ '#attached' ])) {
2013-10-24 15:43:00 +00:00
$attached = drupal_merge_attached ( $attached , $elements [ '#attached' ]);
2011-02-04 21:36:31 +00:00
}
if ( $children = element_children ( $elements )) {
foreach ( $children as $child ) {
drupal_render_collect_attached ( $elements [ $child ]);
}
}
// If this was the first call to the function, return all attached elements
// and reset the static cache.
if ( $return ) {
$return = $attached ;
$attached = array ();
return $return ;
}
}
2013-09-22 08:31:05 +00:00
/**
* Collects cache tags for an element and its children into a single array .
*
* The cache tags array is returned in a format that is valid for
* \Drupal\Core\Cache\CacheBackendInterface :: set () .
*
* When caching elements , it is necessary to collect all cache tags into a
* single array , from both the element itself and all child elements . This
* allows items to be invalidated based on all tags attached to the content
* they ' re constituted from .
*
* @ param array $element
* The element to collect cache tags from .
* @ param array $tags
* ( optional ) An array of already collected cache tags ( i . e . from a parent
* element ) . Defaults to an empty array .
*
* @ return array
* The cache tags array for this element and its descendants .
*/
function drupal_render_collect_cache_tags ( $element , $tags = array ()) {
if ( isset ( $element [ '#cache' ][ 'tags' ])) {
foreach ( $element [ '#cache' ][ 'tags' ] as $namespace => $values ) {
if ( is_array ( $values )) {
foreach ( $values as $value ) {
$tags [ $namespace ][ $value ] = $value ;
}
}
else {
if ( ! isset ( $tags [ $namespace ])) {
$tags [ $namespace ] = $values ;
}
}
}
}
if ( $children = element_children ( $element )) {
foreach ( $children as $child ) {
$tags = drupal_render_collect_cache_tags ( $element [ $child ], $tags );
}
}
return $tags ;
}
2013-11-01 11:15:22 +00:00
/**
* Return the cache tags that were stored during drupal_render_page () .
*
2014-01-29 10:47:12 +00:00
* @ param \Symfony\Component\HttpFoundation\Response $response
* The response object .
2013-11-01 11:15:22 +00:00
* @ return array
* An array of cache tags .
*
2014-01-29 10:47:12 +00:00
* @ see \Drupal\Core\EventSubscriber\HtmlViewSubscriber :: onHtmlPage ()
2013-11-01 11:15:22 +00:00
*/
2014-01-29 10:47:12 +00:00
function drupal_cache_tags_page_get ( Response $response ) {
if (( $tags = $response -> headers -> get ( 'cache_tags' )) && $tags = unserialize ( $tags )) {
return $tags ;
}
return array ();
2013-11-01 11:15:22 +00:00
}
2009-08-31 17:06:10 +00:00
/**
2011-12-05 12:52:27 +00:00
* Creates the cache ID for a renderable element .
2009-08-31 17:06:10 +00:00
*
* This creates the cache ID string , either by returning the #cache['cid']
2014-03-22 22:00:38 +00:00
* property if present or by building the cache ID out of the #cache['keys'].
2009-08-31 17:06:10 +00:00
*
* @ param $elements
* A renderable array .
*
* @ return
* The cache ID string , or FALSE if the element may not be cached .
*/
function drupal_render_cid_create ( $elements ) {
if ( isset ( $elements [ '#cache' ][ 'cid' ])) {
return $elements [ '#cache' ][ 'cid' ];
}
elseif ( isset ( $elements [ '#cache' ][ 'keys' ])) {
2014-03-22 22:00:38 +00:00
// Cache keys may either be static (just strings) or tokens (placeholders
// that are converted to static keys by the @cache_contexts service,
// depending on the request).
$cache_contexts = \Drupal :: service ( " cache_contexts " );
$keys = $cache_contexts -> convertTokensToKeys ( $elements [ '#cache' ][ 'keys' ]);
return implode ( ':' , $keys );
2009-08-31 17:06:10 +00:00
}
return FALSE ;
}
2009-02-03 18:55:32 +00:00
/**
2011-12-05 12:52:27 +00:00
* Retrieves the default properties for the defined element type .
2010-11-12 02:59:30 +00:00
*
* @ param $type
* An element type as defined by hook_element_info () .
2009-02-03 18:55:32 +00:00
*/
2009-05-31 07:00:12 +00:00
function element_info ( $type ) {
2010-04-17 12:35:35 +00:00
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static_fast ;
if ( ! isset ( $drupal_static_fast )) {
$drupal_static_fast [ 'cache' ] = & drupal_static ( __FUNCTION__ );
}
$cache = & $drupal_static_fast [ 'cache' ];
2009-02-03 18:55:32 +00:00
2009-05-31 07:00:12 +00:00
if ( ! isset ( $cache )) {
2013-09-16 03:58:06 +00:00
$cache = \Drupal :: moduleHandler () -> invokeAll ( 'element_info' );
2009-09-10 06:31:39 +00:00
foreach ( $cache as $element_type => $info ) {
$cache [ $element_type ][ '#type' ] = $element_type ;
2009-02-03 18:55:32 +00:00
}
2009-07-23 21:20:16 +00:00
// Allow modules to alter the element type defaults.
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'element_info' , $cache );
2009-02-03 18:55:32 +00:00
}
2009-09-10 06:31:39 +00:00
return isset ( $cache [ $type ]) ? $cache [ $type ] : array ();
2009-02-03 18:55:32 +00:00
}
2010-11-12 02:59:30 +00:00
/**
2011-12-05 12:52:27 +00:00
* Retrieves a single property for the defined element type .
2010-11-12 02:59:30 +00:00
*
* @ param $type
* An element type as defined by hook_element_info () .
* @ param $property_name
* The property within the element type that should be returned .
* @ param $default
* ( Optional ) The value to return if the element type does not specify a
* value for the property . Defaults to NULL .
*/
function element_info_property ( $type , $property_name , $default = NULL ) {
return (( $info = element_info ( $type )) && array_key_exists ( $property_name , $info )) ? $info [ $property_name ] : $default ;
}
2006-08-10 15:42:33 +00:00
/**
2011-12-05 12:52:27 +00:00
* Checks if the key is a property .
2013-12-10 21:23:03 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Core\Render\Element :: property () .
2006-08-10 15:42:33 +00:00
*/
function element_property ( $key ) {
2013-12-10 21:23:03 +00:00
return Element :: property ( $key );
2006-08-10 15:42:33 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Gets properties of a structured array element ( keys beginning with '#' ) .
2013-12-10 21:23:03 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Core\Render\Element :: properties () .
2006-08-10 15:42:33 +00:00
*/
function element_properties ( $element ) {
2013-12-10 21:23:03 +00:00
return Element :: properties ( $element );
2006-08-10 15:42:33 +00:00
}
/**
2011-12-05 12:52:27 +00:00
* Checks if the key is a child .
2013-12-10 21:23:03 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Core\Render\Element :: child () .
2006-08-10 15:42:33 +00:00
*/
function element_child ( $key ) {
2013-12-10 21:23:03 +00:00
return Element :: child ( $key );
2006-08-10 15:42:33 +00:00
}
/**
2011-10-16 08:50:06 +00:00
* Identifies the children of an element array , optionally sorted by weight .
*
* The children of a element array are those key / value pairs whose key does
* not start with a '#' . See drupal_render () for details .
2009-02-09 03:29:54 +00:00
*
* @ param $elements
2011-10-16 08:50:06 +00:00
* The element array whose children are to be identified .
2009-02-09 03:29:54 +00:00
* @ param $sort
* Boolean to indicate whether the children should be sorted by weight .
2011-12-05 12:52:27 +00:00
*
2009-02-09 03:29:54 +00:00
* @ return
* The array keys of the element ' s children .
2013-12-10 21:23:03 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Core\Render\Element :: children () .
2009-02-09 03:29:54 +00:00
*/
function element_children ( & $elements , $sort = FALSE ) {
2013-12-10 21:23:03 +00:00
return Element :: children ( $elements , $sort );
2006-08-22 11:13:04 +00:00
}
2007-04-06 13:27:23 +00:00
2010-01-10 22:45:58 +00:00
/**
2011-09-07 10:38:50 +00:00
* Returns the visible children of an element .
2010-01-10 22:45:58 +00:00
*
* @ param $elements
* The parent element .
2011-12-05 12:52:27 +00:00
*
2010-01-10 22:45:58 +00:00
* @ return
* The array keys of the element ' s visible children .
2013-12-10 21:23:03 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Core\Render\Element :: getVisibleChildren () .
2010-01-10 22:45:58 +00:00
*/
function element_get_visible_children ( array $elements ) {
2013-12-10 21:23:03 +00:00
return Element :: getVisibleChildren ( $elements );
2010-01-10 22:45:58 +00:00
}
2010-09-16 20:14:49 +00:00
/**
* Sets HTML attributes based on element properties .
*
* @ param $element
* The renderable element to process .
* @ param $map
* An associative array whose keys are element property names and whose values
* are the HTML attribute names to set for corresponding the property ; e . g . ,
* array ( '#propertyname' => 'attributename' ) . If both names are identical
* except for the leading '#' , then an attribute name value is sufficient and
* no property name needs to be specified .
2013-12-10 21:23:03 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal\Core\Render\Element :: setAttributes () .
2010-09-16 20:14:49 +00:00
*/
function element_set_attributes ( array & $element , array $map ) {
2013-12-10 21:23:03 +00:00
Element :: setAttributes ( $element , $map );
2010-09-16 20:14:49 +00:00
}
2007-04-30 11:12:35 +00:00
/**
2011-12-05 12:52:27 +00:00
* Returns a list of severity levels , as defined in RFC 3164.
2008-05-26 17:12:55 +00:00
*
2007-04-30 11:12:35 +00:00
* @ return
* Array of the possible severity levels for log messages .
*
2011-12-05 12:52:27 +00:00
* @ see http :// www . ietf . org / rfc / rfc3164 . txt
2008-05-26 17:12:55 +00:00
* @ see watchdog ()
2011-07-04 16:58:33 +00:00
* @ ingroup logging_severity_levels
2007-04-30 11:12:35 +00:00
*/
function watchdog_severity_levels () {
return array (
2013-02-18 17:15:18 +00:00
WATCHDOG_EMERGENCY => t ( 'Emergency' ),
WATCHDOG_ALERT => t ( 'Alert' ),
WATCHDOG_CRITICAL => t ( 'Critical' ),
WATCHDOG_ERROR => t ( 'Error' ),
WATCHDOG_WARNING => t ( 'Warning' ),
WATCHDOG_NOTICE => t ( 'Notice' ),
WATCHDOG_INFO => t ( 'Info' ),
WATCHDOG_DEBUG => t ( 'Debug' ),
2007-04-30 11:12:35 +00:00
);
}
2007-06-29 18:06:51 +00:00
2007-11-26 16:25:14 +00:00
/**
2012-05-03 15:09:39 +00:00
* Flushes all persistent caches , resets all variables , and rebuilds all data structures .
*
* At times , it is necessary to re - initialize the entire system to account for
* changed or new code . This function :
2013-03-22 09:36:55 +00:00
* - Clears all persistent caches :
2012-05-03 15:09:39 +00:00
* - The bootstrap cache bin containing base system , module system , and theme
* system information .
* - The common 'cache' cache bin containing arbitrary caches .
* - The page cache .
* - The URL alias path cache .
* - Resets all static variables that have been defined via drupal_static () .
* - Clears asset ( JS / CSS ) file caches .
* - Updates the system with latest information about extensions ( modules and
* themes ) .
* - Updates the bootstrap flag for modules implementing bootstrap_hooks () .
* - Rebuilds the full database schema information ( invoking hook_schema ()) .
* - Rebuilds data structures of all modules ( invoking hook_rebuild ()) . In
* core this means
* - blocks , node types , date formats and actions are synchronized with the
* database
* - The 'active' status of fields is refreshed .
* - Rebuilds the menu router .
*
* This means the entire system is reset so all caches and static variables are
* effectively empty . After that is guaranteed , information about the currently
* active code is updated , and rebuild operations are successively called in
* order to synchronize the active system according to the current information
* defined in code .
*
* All modules need to ensure that all of their caches are flushed when
* hook_cache_flush () is invoked ; any previously known information must no
* longer exist . All following hook_rebuild () operations must be based on fresh
* and current system data . All modules must be able to rely on this contract .
*
2013-03-22 09:36:55 +00:00
* @ see \Drupal\Core\Cache\CacheHelper :: getBins ()
2012-05-03 15:09:39 +00:00
* @ see hook_cache_flush ()
* @ see hook_rebuild ()
*
* This function also resets the theme , which means it is not initialized
* anymore and all previously added JavaScript and CSS is gone . Normally , this
* function is called as an end - of - POST - request operation that is followed by a
* redirect , so this effect is not visible . Since the full reset is the whole
* point of this function , callers need to take care for backing up all needed
* variables and properly restoring or re - initializing them on their own . For
* convenience , this function automatically re - initializes the maintenance theme
* if it was initialized before .
*
* @ todo Try to clear page / JS / CSS caches last , so cached pages can still be
* served during this possibly long - running operation . ( Conflict on bootstrap
* cache though . )
* @ todo Add a global lock to ensure that caches are not primed in concurrent
* requests .
2007-11-26 16:25:14 +00:00
*/
function drupal_flush_all_caches () {
2013-09-16 03:58:06 +00:00
$module_handler = \Drupal :: moduleHandler ();
2012-05-03 15:09:39 +00:00
// Flush all persistent caches.
// This is executed based on old/previously known information, which is
// sufficient, since new extensions cannot have any primed caches yet.
2013-05-19 19:32:09 +00:00
$module_handler -> invokeAll ( 'cache_flush' );
2013-03-22 09:36:55 +00:00
foreach ( Cache :: getBins () as $service_id => $cache_backend ) {
Issue #512026 by Berdir, effulgentsia, sun, marcingy, Eric_A, xjm, katbailey, Damien Tournoud, alexpott, beejeebus, pillarsdotnet: Move () storage from cache to new state/key-value system.
2013-03-27 18:57:12 +00:00
if ( $service_id != 'cache.menu' ) {
2013-03-22 09:36:55 +00:00
$cache_backend -> deleteAll ();
}
2012-05-03 15:09:39 +00:00
}
2008-01-07 19:43:29 +00:00
2012-05-03 15:09:39 +00:00
// Flush asset file caches.
2007-11-26 16:25:14 +00:00
drupal_clear_css_cache ();
drupal_clear_js_cache ();
2012-05-03 15:09:39 +00:00
_drupal_flush_css_js ();
2010-04-29 05:33:43 +00:00
2012-05-03 15:09:39 +00:00
// Reset all static caches.
drupal_static_reset ();
2012-01-18 04:02:34 +00:00
2012-05-03 15:09:39 +00:00
// Clear all non-drupal_static() static caches.
2013-09-16 03:58:06 +00:00
\Drupal :: entityManager () -> clearCachedDefinitions ();
2010-04-29 05:33:43 +00:00
2013-05-19 19:32:09 +00:00
// Wipe the PHP Storage caches.
PhpStorageFactory :: get ( 'service_container' ) -> deleteAll ();
PhpStorageFactory :: get ( 'twig' ) -> deleteAll ();
2012-08-31 10:03:05 +00:00
// Rebuild module and theme data.
2013-05-19 19:32:09 +00:00
$module_data = system_rebuild_module_data ();
2012-05-03 15:09:39 +00:00
system_rebuild_theme_data ();
2010-10-01 18:37:23 +00:00
2013-05-19 19:32:09 +00:00
// Rebuild and reboot a new kernel. A simple DrupalKernel reboot is not
// sufficient, since the list of enabled modules might have been adjusted
// above due to changed code.
$files = array ();
Issue #340723 by ParisLiakos, sun, Berdir, glennpratt, Cottser, swentel, alexpott, tstoeckler, Xano, tim.plunkett, BassistJimmyJam | beejeebus: Make modules and installation profiles only require .info.yml files.
2014-03-17 14:43:29 +00:00
foreach ( $module_data as $name => $extension ) {
if ( $extension -> status ) {
$files [ $name ] = $extension ;
2013-05-19 19:32:09 +00:00
}
}
2013-09-16 03:58:06 +00:00
\Drupal :: service ( 'kernel' ) -> updateModules ( $module_handler -> getModuleList (), $files );
2013-05-19 19:32:09 +00:00
// New container, new module handler.
2013-09-16 03:58:06 +00:00
$module_handler = \Drupal :: moduleHandler ();
2013-05-19 19:32:09 +00:00
2012-05-03 15:09:39 +00:00
// Ensure that all modules that are currently supposed to be enabled are
// actually loaded.
2013-05-19 19:32:09 +00:00
$module_handler -> loadAll ();
2010-07-29 02:00:27 +00:00
2012-05-03 15:09:39 +00:00
// Rebuild the schema and cache a fully-built schema based on new module data.
// This is necessary for any invocation of index.php, because setting cache
// table entries requires schema information and that occurs during bootstrap
// before any modules are loaded, so if there is no cached schema,
// drupal_get_schema() will try to generate one, but with no loaded modules,
// it will return nothing.
drupal_get_schema ( NULL , TRUE );
// Rebuild all information based on new module data.
2013-05-19 19:32:09 +00:00
$module_handler -> invokeAll ( 'rebuild' );
2012-05-03 15:09:39 +00:00
// Rebuild the menu router based on all rebuilt data.
// Important: This rebuild must happen last, so the menu router is guaranteed
// to be based on up to date information.
2013-09-16 03:58:06 +00:00
\Drupal :: service ( 'router.builder' ) -> rebuild ();
2012-05-03 15:09:39 +00:00
// Re-initialize the maintenance theme, if the current request attempted to
// use it. Unlike regular usages of this function, the installer and update
// scripts need to flush all caches during GET requests/page building.
if ( function_exists ( '_drupal_maintenance_theme' )) {
unset ( $GLOBALS [ 'theme' ]);
drupal_maintenance_theme ();
}
2007-11-26 16:25:14 +00:00
}
2008-01-07 19:43:29 +00:00
/**
2011-12-05 12:52:27 +00:00
* Changes the dummy query string added to all CSS and JavaScript files .
2008-01-07 19:43:29 +00:00
*
2011-12-05 12:52:27 +00:00
* Changing the dummy query string appended to CSS and JavaScript files forces
* all browsers to reload fresh files .
2008-01-07 19:43:29 +00:00
*/
function _drupal_flush_css_js () {
2010-03-23 21:44:10 +00:00
// The timestamp is converted to base 36 in order to make it more compact.
2013-09-27 12:20:32 +00:00
Drupal :: state () -> set ( 'system.css_js_query_string' , base_convert ( REQUEST_TIME , 10 , 36 ));
2008-01-07 19:43:29 +00:00
}
2009-08-13 03:03:04 +00:00
2009-08-15 06:20:20 +00:00
/**
2011-12-05 12:52:27 +00:00
* Outputs debug information .
2009-08-15 06:20:20 +00:00
*
* The debug information is passed on to trigger_error () after being converted
* to a string using _drupal_debug_message () .
*
* @ param $data
* Data to be output .
* @ param $label
* Label to prefix the data .
* @ param $print_r
* Flag to switch between print_r () and var_export () for data conversion to
* string . Set $print_r to TRUE when dealing with a recursive data structure
* as var_export () will generate an error .
*/
function debug ( $data , $label = NULL , $print_r = FALSE ) {
// Print $data contents to string.
2013-10-07 05:34:09 +00:00
$string = String :: checkPlain ( $print_r ? print_r ( $data , TRUE ) : var_export ( $data , TRUE ));
2010-10-16 00:00:17 +00:00
// Display values with pre-formatting to increase readability.
$string = '<pre>' . $string . '</pre>' ;
2009-08-15 06:20:20 +00:00
trigger_error ( trim ( $label ? " $label : $string " : $string ));
}
2009-08-13 03:03:04 +00:00
/**
2011-12-05 12:52:27 +00:00
* Checks whether a version is compatible with a given dependency .
2009-08-13 03:03:04 +00:00
*
* @ param $v
2013-01-21 19:21:34 +00:00
* A parsed dependency structure e . g . from ModuleHandler :: parseDependency () .
2009-08-13 03:03:04 +00:00
* @ param $current_version
* The version to check against ( like 4.2 ) .
2011-12-05 12:52:27 +00:00
*
2009-08-13 03:03:04 +00:00
* @ return
* NULL if compatible , otherwise the original dependency version string that
2010-01-25 10:38:35 +00:00
* caused the incompatibility .
2009-08-13 03:03:04 +00:00
*
2013-01-21 19:21:34 +00:00
* @ see \Drupal\Core\Extension\ModuleHandler :: parseDependency ()
2009-08-13 03:03:04 +00:00
*/
function drupal_check_incompatibility ( $v , $current_version ) {
if ( ! empty ( $v [ 'versions' ])) {
foreach ( $v [ 'versions' ] as $required_version ) {
if (( isset ( $required_version [ 'op' ]) && ! version_compare ( $current_version , $required_version [ 'version' ], $required_version [ 'op' ]))) {
return $v [ 'original_version' ];
}
}
}
}
2009-08-25 21:53:48 +00:00
2010-07-29 02:27:43 +00:00
/**
* Returns a string of supported archive extensions .
*
* @ return
* A space - separated string of extensions suitable for use by the file
* validation system .
*/
function archiver_get_extensions () {
$valid_extensions = array ();
2013-09-16 03:58:06 +00:00
foreach ( \Drupal :: service ( 'plugin.manager.archiver' ) -> getDefinitions () as $archive ) {
2010-07-29 02:27:43 +00:00
foreach ( $archive [ 'extensions' ] as $extension ) {
foreach ( explode ( '.' , $extension ) as $part ) {
if ( ! in_array ( $part , $valid_extensions )) {
$valid_extensions [] = $part ;
}
}
}
}
return implode ( ' ' , $valid_extensions );
}
2009-10-15 17:55:55 +00:00
/**
2011-12-05 12:52:27 +00:00
* Creates the appropriate archiver for the specified file .
2009-10-15 17:55:55 +00:00
*
* @ param $file
2011-12-05 12:52:27 +00:00
* The full path of the archive file . Note that stream wrapper paths are
* supported , but not remote ones .
*
2009-10-15 17:55:55 +00:00
* @ return
* A newly created instance of the archiver class appropriate
* for the specified file , already bound to that file .
2009-10-23 00:55:59 +00:00
* If no appropriate archiver class was found , will return FALSE .
2009-10-15 17:55:55 +00:00
*/
function archiver_get_archiver ( $file ) {
2009-10-23 00:55:59 +00:00
// Archivers can only work on local paths
$filepath = drupal_realpath ( $file );
if ( ! is_file ( $filepath )) {
throw new Exception ( t ( 'Archivers can only operate on local files: %file not supported' , array ( '%file' => $file )));
}
2013-09-16 03:58:06 +00:00
return \Drupal :: service ( 'plugin.manager.archiver' ) -> getInstance ( array ( 'filepath' => $filepath ));
2009-10-15 17:55:55 +00:00
}
2009-10-15 21:19:31 +00:00
/**
2011-12-05 12:52:27 +00:00
* Assembles the Drupal Updater registry .
2009-10-15 21:19:31 +00:00
*
* An Updater is a class that knows how to update various parts of the Drupal
* file system , for example to update modules that have newer releases , or to
* install a new theme .
*
2012-03-11 00:23:05 +00:00
* @ return array
2011-12-05 12:52:27 +00:00
* The Drupal Updater class registry .
2009-10-15 21:19:31 +00:00
*
2013-10-03 11:26:25 +00:00
* @ see \Drupal\Core\Updater\Updater
2009-10-15 21:19:31 +00:00
* @ see hook_updater_info ()
* @ see hook_updater_info_alter ()
*/
function drupal_get_updaters () {
$updaters = & drupal_static ( __FUNCTION__ );
if ( ! isset ( $updaters )) {
2013-09-16 03:58:06 +00:00
$updaters = \Drupal :: moduleHandler () -> invokeAll ( 'updater_info' );
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'updater_info' , $updaters );
2014-01-25 01:58:19 +00:00
uasort ( $updaters , array ( 'Drupal\Component\Utility\SortArray' , 'sortByWeightElement' ));
2009-10-15 21:19:31 +00:00
}
return $updaters ;
}
2010-12-01 00:23:36 +00:00
/**
2011-12-05 12:52:27 +00:00
* Assembles the Drupal FileTransfer registry .
2010-12-01 00:23:36 +00:00
*
* @ return
2011-12-05 12:52:27 +00:00
* The Drupal FileTransfer class registry .
2010-12-01 00:23:36 +00:00
*
2013-10-03 11:26:25 +00:00
* @ see \Drupal\Core\FileTransfer\FileTransfer
2010-12-01 00:23:36 +00:00
* @ see hook_filetransfer_info ()
* @ see hook_filetransfer_info_alter ()
*/
function drupal_get_filetransfer_info () {
$info = & drupal_static ( __FUNCTION__ );
if ( ! isset ( $info )) {
2013-09-16 03:58:06 +00:00
$info = \Drupal :: moduleHandler () -> invokeAll ( 'filetransfer_info' );
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'filetransfer_info' , $info );
2014-01-25 01:58:19 +00:00
uasort ( $info , array ( 'Drupal\Component\Utility\SortArray' , 'sortByWeightElement' ));
2010-12-01 00:23:36 +00:00
}
return $info ;
}
2012-03-12 03:07:39 +00:00
/**
* @ defgroup queue Queue operations
* @ {
* Queue items to allow later processing .
*
* The queue system allows placing items in a queue and processing them later .
* The system tries to ensure that only one consumer can process an item .
*
* Before a queue can be used it needs to be created by
* Drupal\Core\Queue\QueueInterface :: createQueue () .
*
* Items can be added to the queue by passing an arbitrary data object to
* Drupal\Core\Queue\QueueInterface :: createItem () .
*
* To process an item , call Drupal\Core\Queue\QueueInterface :: claimItem () and
* specify how long you want to have a lease for working on that item .
* When finished processing , the item needs to be deleted by calling
* Drupal\Core\Queue\QueueInterface :: deleteItem () . If the consumer dies , the
* item will be made available again by the Drupal\Core\Queue\QueueInterface
* implementation once the lease expires . Another consumer will then be able to
* receive it when calling Drupal\Core\Queue\QueueInterface :: claimItem () .
* Due to this , the processing code should be aware that an item might be handed
* over for processing more than once .
*
* The $item object used by the Drupal\Core\Queue\QueueInterface can contain
* arbitrary metadata depending on the implementation . Systems using the
* interface should only rely on the data property which will contain the
* information passed to Drupal\Core\Queue\QueueInterface :: createItem () .
* The full queue item returned by Drupal\Core\Queue\QueueInterface :: claimItem ()
* needs to be passed to Drupal\Core\Queue\QueueInterface :: deleteItem () once
* processing is completed .
*
* There are two kinds of queue backends available : reliable , which preserves
* the order of messages and guarantees that every item will be executed at
* least once . The non - reliable kind only does a best effort to preserve order
* in messages and to execute them at least once but there is a small chance
* that some items get lost . For example , some distributed back - ends like
* Amazon SQS will be managing jobs for a large set of producers and consumers
* where a strict FIFO ordering will likely not be preserved . Another example
* would be an in - memory queue backend which might lose items if it crashes .
* However , such a backend would be able to deal with significantly more writes
* than a reliable queue and for many tasks this is more important . See
* aggregator_cron () for an example of how to effectively utilize a
* non - reliable queue . Another example is doing Twitter statistics -- the small
* possibility of losing a few items is insignificant next to power of the
* queue being able to keep up with writes . As described in the processing
* section , regardless of the queue being reliable or not , the processing code
* should be aware that an item might be handed over for processing more than
* once ( because the processing code might time out before it finishes ) .
*/
/**
* @ } End of " defgroup queue " .
*/