AlphaPagination.php in Views Alpha Pagination 8.2
Same filename and directory in other branches
Namespace
Drupal\alpha_paginationFile
src/AlphaPagination.phpView source
<?php
namespace Drupal\alpha_pagination;
use Drupal\alpha_pagination\Plugin\views\area\AlphaPaginationArea;
use Drupal\Component\Utility\Html;
use Drupal\Component\Transliteration\TransliterationInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Utility\Token;
use Drupal\views\Views;
use Drupal\views\Plugin\views\ViewsHandlerInterface;
/**
* A base views handler for alpha pagination.
*/
class AlphaPagination {
/**
* The AlphaPagination Views Handler.
*
* @var \Drupal\views\Plugin\views\ViewsHandlerInterface
*/
protected $handler;
/**
* The Entity Field Manager Interface.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $fieldManager;
/**
* The Language ID.
*
* @var string
*/
protected $language;
/**
* The ModuleHandler Interface.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The cache backend service.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cacheBackend;
/**
* The Transliteration Interface.
*
* @var \Drupal\Component\Transliteration\TransliterationInterface
*/
protected $transliteration;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The token replacement instance.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* The url used for links.
*
* @var \Drupal\Core\Url
*/
protected $url;
/**
* Contructs the AlphaPagination object.
*
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager
* The Entity Field Manager Interface.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The ModuleHander Interface.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* The cache backend service.
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
* A PHPTransliteration object.
* @param \Drupal\Core\Database\Connection $database
* The database connection.
* @param \Drupal\Core\Utility\Token $token
* The token service.
*/
public function __construct(EntityFieldManagerInterface $field_manager, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, TransliterationInterface $transliteration, Connection $database, Token $token) {
$this->fieldManager = $field_manager;
$this->language = $language_manager
->getCurrentLanguage()
->getId();
$this->moduleHandler = $module_handler;
$this->cacheBackend = $cache_backend;
$this->transliteration = $transliteration;
$this->database = $database;
$this->token = $token;
}
/**
* Sets the view handler.
*
* @param \Drupal\views\Plugin\views\ViewsHandlerInterface $handler
* The views handler.
*/
public function setHandler(ViewsHandlerInterface $handler) {
$this->handler = $handler;
}
/**
* {@inheritdoc}
*/
public function __sleep() {
$this->_handler = implode(':', [
$this->handler->view
->id(),
$this->handler->view->current_display,
$this->handler->areaType,
$this->handler->realField ?: $this->handler->field,
$this->language,
]);
return [
'_handler',
];
}
/**
* {@inheritdoc}
*/
public function __wakeup() {
list($name, $display_id, $type, $id, $language) = explode(':', $this->_handler);
$view = Views::getView($name);
$view
->setDisplay($display_id);
$this->handler = $view->display_handler
->getHandler($type, $id);
$this->language = $language;
unset($this->_handler);
}
/**
* Add classes to an attributes array from a view option.
*
* @param string[]|string $classes
* An array of classes or a string of classes.
* @param array $attributes
* An attributes array to add the classes to, passed by reference.
*
* @return array
* An array of classes to be used in a render array.
*/
public function addClasses($classes, array &$attributes) {
$processed = [];
// Sanitize any classes provided for the item list.
foreach ((array) $classes as $v) {
foreach (array_filter(explode(' ', $v)) as $vv) {
$processed[] = Html::cleanCssIdentifier($vv);
}
}
// Don't add any classes if it's empty, which will add an empty attribute.
if ($processed) {
if (!isset($attributes['class'])) {
$attributes['class'] = [];
}
$attributes['class'] = array_unique(array_merge($attributes['class'], $processed));
}
return $classes;
}
/**
* Builds a render array for displaying tokens.
*
* @param string $fieldset
* The #fieldset name to assign.
*
* @return array
* The render array for the token info.
*/
public function buildTokenTree($fieldset = NULL) {
static $build;
if (!isset($build)) {
if ($this->moduleHandler
->moduleExists('token')) {
$build = [
'#type' => 'container',
'#title' => t('Browse available tokens'),
];
$build['help'] = [
'#theme' => 'token_tree_link',
'#token_types' => [
'alpha_pagination',
],
'#global_types' => TRUE,
'#dialog' => TRUE,
];
}
else {
$build = [
'#type' => 'fieldset',
'#title' => 'Available tokens',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
];
$items = [];
$token_info = alpha_pagination_token_info();
foreach ($token_info['tokens'] as $_type => $_tokens) {
foreach ($_tokens as $_token => $_data) {
$items[] = "[{$_type}:{$_token}] - {$_data['description']}";
}
}
$build['help'] = [
'#theme' => 'item_list',
'#items' => $items,
];
}
}
return isset($fieldset) ? [
'#fieldset' => $fieldset,
] + $build : $build;
}
/**
* Extract the SQL query from the query information.
*
* Once extracted, place it into the options array so it is passed to the
* render function. This code was lifted nearly verbatim from the views
* module where the query is constructed for the ui to show the query in the
* administrative area.
*
* @todo Need to make this better somehow?
*/
public function ensureQuery() {
if (!$this
->getOption('query') && !empty($this->handler->view->build_info['query'])) {
/** @var \SelectQuery $query */
$query = $this->handler->view->build_info['query'];
$quoted = $query
->getArguments();
foreach ($quoted as $key => $val) {
if (is_array($val)) {
$quoted[$key] = implode(', ', array_map([
$this->database,
'quote',
], $val));
}
else {
$quoted[$key] = $this->database
->quote($val);
}
}
$this->handler->options['query'] = Html::escape(strtr($query, $quoted));
}
}
/**
* Retrieves alphabet characters, based on langcode.
*
* Note: Do not use range(); always be explicit when defining an alphabet.
* This is necessary as you cannot rely on the server language to construct
* proper alphabet characters.
*
* @param string $langcode
* The langcode to return. If the langcode does not exist, it will default
* to English.
*
* @return array
* An indexed array of alphabet characters, based on langcode.
*
* @see hook_alpha_pagination_alphabet_alter()
*/
public function getAlphabet($langcode = NULL) {
// Default (English).
static $default = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
];
static $alphabets;
// If the langcode is not explicitly specified, default to global langcode.
if (!isset($langcode)) {
$langcode = $this->language;
}
// Retrieve alphabets.
if (!isset($alphabets)) {
// Attempt to retrieve from database cache.
$cid = "alpha_pagination:alphabets";
if (($cache = $this->cacheBackend
->get($cid)) && !empty($cache->data)) {
$alphabets = $cache->data;
}
else {
// Arabic.
$alphabets['ar'] = [
'ا',
'ب',
'ت',
'ث',
'ج',
'ح',
'خ',
'د',
'ذ',
'ر',
'ز',
'س',
'ش',
'ص',
'ض',
'ط',
'ظ',
'ع',
'غ',
'ف',
'ق',
'ك',
'ل',
'م',
'ن',
'و',
'ه',
'ي',
];
// English. Initially the default value, but can be modified in alter.
$alphabets['en'] = $default;
// Русский (Russian).
$alphabets['ru'] = [
'А',
'Б',
'В',
'Г',
'Д',
'Е',
'Ё',
'Ж',
'З',
'И',
'Й',
'К',
'Л',
'М',
'Н',
'О',
'П',
'Р',
'С',
'Т',
'У',
'Ф',
'Х',
'Ц',
'Ч',
'Ш',
'Щ',
'Ы',
'Э',
'Ю',
'Я',
];
// Allow modules and themes to alter alphabets.
$this->moduleHandler
->alter('alpha_pagination_alphabet', $alphabets, $this);
// Cache the alphabets.
$this->cacheBackend
->set($cid, $alphabets);
}
}
// Return alphabet based on langcode.
return isset($alphabets[$langcode]) ? $alphabets[$langcode] : $default;
}
/**
* Retrieves all available alpha pagination areas.
*
* @param array $types
* The handler types to search.
*
* @return \Drupal\alpha_pagination\Plugin\views\area\AlphaPaginationArea[]
* An array of alpha pagination areas.
*/
public function getAreaHandlers(array $types = [
'header',
'footer',
]) {
$areas = [];
foreach ($types as $type) {
foreach ($this->handler->displayHandler
->getHandlers($type) as $handler) {
if ($handler instanceof AlphaPaginationArea) {
$areas[] = $handler;
}
}
}
return $areas;
}
/**
* Retrieves the characters used to populate the pagination item list.
*
* @return \Drupal\alpha_pagination\AlphaPaginationCharacter[]
* An associative array containing AlphaPaginationCharacter objects, keyed
* by its value.
*/
public function getCharacters() {
/** @var \Drupal\alpha_pagination\AlphaPaginationCharacter[] $characters */
static $characters;
if (!isset($characters)) {
$all = $this
->getOption('paginate_all_display') === '1' ? $this
->getOption('paginate_all_label', t('All')) : '';
$all_value = $this
->getOption('paginate_all_value', 'all');
$numeric_label = $this
->getOption('paginate_numeric_label');
$numeric_type = $this
->getOption('paginate_view_numbers', '0');
$numeric_value = $this
->getOption('paginate_numeric_value');
$numeric_divider = $numeric_type !== '2' && $this
->getOption('paginate_numeric_divider') ? [
'-' => '',
] : [];
// Check to see if this query is cached. If it is, then just pull our
// results set from it so that things can move quickly through here. We're
// caching in the event the view has a very large result set.
$cid = $this
->getCid();
if (($cache = $this->cacheBackend
->get($cid)) && !empty($cache->data)) {
$characters = $cache->data;
}
else {
// Add alphabet characters.
foreach ($this
->getAlphabet() as $value) {
$characters[$value] = $value;
}
// Append or prepend numeric item(s).
$numeric = [];
if ($numeric_type !== '0') {
// Determine type of numeric items.
if ($numeric_type === '2') {
$numeric[$numeric_value] = Html::escape($numeric_label);
}
else {
foreach ($this
->getNumbers() as $value) {
$numeric[$value] = $value;
}
}
// Merge in numeric items.
if ($this
->getOption('paginate_numeric_position') === 'after') {
$characters = array_merge($characters, $numeric_divider, $numeric);
}
else {
$characters = array_merge($numeric, $numeric_divider, $characters);
}
}
// Append or prepend the "all" item.
if ($all) {
if ($this
->getOption('paginate_all_position') === 'before') {
$characters = [
$all_value => $all,
] + $characters;
}
else {
$characters[$all_value] = $all;
}
}
// Convert characters to objects.
foreach ($characters as $value => $label) {
$characters[$value] = new AlphaPaginationCharacter($this, $label, $value);
}
// Determine enabled prefixes.
$prefixes = $this
->getEntityPrefixes();
foreach ($prefixes as $value) {
// Ensure numeric prefixes use the numeric label, if necessary.
if ($this
->isNumeric($value) && $numeric_type === '2') {
$value = $numeric_value;
}
if (isset($characters[$value])) {
$characters[$value]
->setEnabled(TRUE);
}
}
// Remove all empty prefixes.
if (!$this
->getOption('paginate_toggle_empty')) {
// Ensure "all" and numeric divider objects aren't removed.
if ($all) {
$prefixes[] = $all_value;
}
if ($numeric_divider) {
$prefixes[] = '-';
}
// Determine if numeric results are not empty.
$characters = array_filter(array_intersect_key($characters, array_flip($prefixes)));
}
// Remove all numeric values if they're all empty.
if ($this
->getOption('paginate_numeric_hide_empty')) {
// Determine if numeric results are not empty.
$numeric_results = array_filter(array_intersect_key($characters, array_flip($numeric)));
if (!$numeric_results) {
$characters = array_diff_key($characters, array_flip($numeric));
}
}
// Cache the results.
$this->cacheBackend
->set($cid, $characters);
}
// Default current value to "all", if enabled, or the first character.
$current = $all ? $all_value : '';
// Attempt to determine if a valid argument was provided.
$arg_count = count($this->handler->view->args);
if ($arg_count) {
$arg = $this->handler->view->args[$arg_count - 1];
if ($arg && in_array($arg, array_keys($characters))) {
$current = $arg;
}
}
// Determine the first active character.
if ($current) {
foreach ($characters as $character) {
if ($character
->isNumeric() && $numeric_type === '2' ? $numeric_value === $current : $character
->getValue() === $current) {
$character
->setActive(TRUE);
break;
}
}
}
}
return $characters;
}
/**
* Retrieves a cache identifier for the view, display and query, if set.
*
* @return string
* A cache identifier.
*/
public function getCid() {
$this
->ensureQuery();
$data = [
'langcode' => $this->language,
'view' => $this->handler->view
->id(),
'display' => $this->handler->view
->getDisplay()
->getPluginId(),
'query' => $this
->getOption('query') ? md5($this
->getOption('query')) : '',
'options' => $this->handler->options,
];
return 'alpha_pagination:' . Crypt::hashBase64(serialize($data));
}
/**
* Construct the actual SQL query for the view being generated.
*
* Then parse it to short-circuit certain conditions that may exist and
* make any alterations. This is not the most elegant of solutions, but it
* is very effective.
*
* @return array
* An indexed array of entity identifiers.
*/
public function getEntityIds() {
$this
->ensureQuery();
$query_parts = explode("\n", $this
->getOption('query'));
// Get the base field. This will change depending on the type of view we
// are putting the paginator on and eventually if we are using a
// relationship to access it.
$relationship = $this
->getOption('paginate_view_relationship');
if ($relationship == 'none') {
$base_field = $this->handler->view->storage
->get('base_field');
}
else {
// Inspired from core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
// buildForm further exploration needed when chaining relationships.
$relationship_handler = $this->handler->view
->getHandler($this->handler->view->current_display, 'relationship', $relationship);
$data = Views::viewsData()
->get($relationship_handler['table']);
if (isset($data[$relationship_handler['field']]['relationship']['base']) && $this->handler->view->storage
->get('base_table') == $data[$relationship_handler['field']]['relationship']['base']) {
$base_field = implode('_', [
$data[$relationship_handler['field']]['relationship']['base'],
$relationship_handler['table'],
$data[$relationship_handler['field']]['relationship']['base field'],
]);
}
}
// If we are dealing with a substring, then short circuit it as we are most
// likely dealing with a glossary contextual filter.
foreach ($query_parts as $k => $part) {
if ($position = strpos($part, "SUBSTRING")) {
$part = substr($part, 0, $position) . " 1 OR " . substr($part, $position);
$query_parts[$k] = $part;
}
}
// Evaluate the last line looking for anything which may limit the result
// set as we need results against the entire set of data and not just what
// is configured in the view.
$last_line = array_pop($query_parts);
if (substr($last_line, 0, 5) != "LIMIT") {
$query_parts[] = $last_line;
}
// Construct the query from the array and change the single quotes from
// HTML special characters back into single quotes.
$query = implode("\n", $query_parts);
$query = str_replace("'", '\'', $query);
$query = str_replace("&", '&', $query);
$query = str_replace("<", '<', $query);
$query = str_replace(">", '>', $query);
$query = str_replace(""", '', $query);
// Based on our query, get the list of entity identifiers that are affected.
// These will be used to generate the pagination items.
$entity_ids = [];
$result = $this->database
->query($query);
while ($data = $result
->fetchObject()) {
$entity_ids[] = $data->{$base_field};
}
return $entity_ids;
}
/**
* Retrieve the distinct first character prefix from the field tables.
*
* Mark them as TRUE so their pagination item is represented properly.
*
* Note that the node title is a special case that we have to take from the
* node table as opposed to the body or any custom fields.
*
* @todo This should be cleaned up more and fixed "properly".
*
* @return array
* An indexed array containing a unique array of entity prefixes.
*/
public function getEntityPrefixes() {
$prefixes = [];
if ($entity_ids = $this
->getEntityIds()) {
switch ($this
->getOption('paginate_view_field')) {
case 'name':
$table = $this->handler->view->storage
->get('base_table');
$where = $this->handler->view->storage
->get('base_field');
// Extract the "name" field from the entity property info.
$entity_type = $this->handler->view->getBaseEntityType
->id();
$entity_info = $this->fieldManager
->getBaseFieldDefinitions($entity_type);
$field = isset($entity_info['properties']['name']['schema field']) ? $entity_info['properties']['name']['schema field'] : 'name';
break;
case 'title':
$table = $this->handler->view->storage
->get('base_table');
$where = $this->handler->view->storage
->get('base_field');
// Extract the "title" field from the entity property info.
$entity_type = $this->handler->view
->getBaseEntityType()
->id();
$entity_info = $this->fieldManager
->getBaseFieldDefinitions($entity_type);
$field = isset($entity_info['properties']['title']['schema field']) ? $entity_info['properties']['title']['schema field'] : 'title';
break;
default:
if (strpos($this
->getOption('paginate_view_field'), ':') === FALSE) {
// Format field name and table for single value fields.
list($entityType, $field_name) = explode('__', $this
->getOption('paginate_view_field'), 2);
$field = $field_name . '_value';
$table = $this
->getOption('paginate_view_field');
}
else {
// Format field name and table for compound value fields.
list($entityType, $field_name) = explode('__', $this
->getOption('paginate_view_field'), 2);
$field = str_replace(':', '_', $field_name);
$field_name_components = explode(':', $field_name);
$table = $field_name_components[0];
}
$where = 'entity_id';
break;
}
$result = $this->database
->query('SELECT DISTINCT(SUBSTR(' . $field . ', 1, 1)) AS prefix
FROM {' . $table . '}
WHERE ' . $where . ' IN ( :nids[] )', [
':nids[]' => $entity_ids,
]);
while ($data = $result
->fetchObject()) {
$prefixes[] = is_numeric($data->prefix) ? $data->prefix : mb_strtoupper($this->transliteration
->transliterate($data->prefix));
}
}
return array_unique(array_filter($prefixes));
}
/**
* Retrieves the proper label for a character.
*
* @param mixed $value
* The value of the label to retrieve.
*
* @return string
* The label.
*/
public function getLabel($value) {
$characters = $this
->getCharacters();
// Return an appropriate numeric label.
if ($this
->getOption('paginate_view_numbers') === '2' && $this
->isNumeric($value)) {
return $characters[$this
->getOption('paginate_numeric_value')]
->getLabel();
}
elseif (isset($characters[$value])) {
return $characters[$value]
->getLabel();
}
// Return the original value.
return $value;
}
/**
* Retrieves numeric characters, based on langcode.
*
* Note: Do not use range(); always be explicit when defining numbers.
* This is necessary as you cannot rely on the server language to construct
* proper numeric characters.
*
* @param string $langcode
* The langcode to return. If the langcode does not exist, it will default
* to English.
*
* @return array
* An indexed array of numeric characters, based on langcode.
*
* @see hook_alpha_pagination_numbers_alter()
*/
public function getNumbers($langcode = NULL) {
// Default (English).
static $default = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
];
static $numbers;
// If the langcode is not explicitly specified, default to global langcode.
if (!isset($langcode)) {
$langcode = $this->language;
}
// Retrieve numbers.
if (!isset($numbers)) {
// Attempt to retrieve from database cache.
$cid = "alpha_pagination:numbers";
if (($cache = $this->cacheBackend
->get($cid)) && !empty($cache->data)) {
$numbers = $cache->data;
}
else {
// English. Initially the default value, but can be modified in alter.
$numbers['en'] = $default;
// Allow modules and themes to alter numbers.
$this->moduleHandler
->alter('alpha_pagination_numbers', $numbers, $this);
// Cache the numbers.
$this->cacheBackend
->set($cid, $numbers);
}
}
// Return numbers based on langcode.
return isset($numbers[$langcode]) ? $numbers[$langcode] : $default;
}
/**
* Retrieves an option from the view handler.
*
* @param string $name
* The option name to retrieve.
* @param mixed $default
* The default value to return if not set.
*
* @return string
* The option value or $default if not set.
*/
public function getOption($name, $default = '') {
return (string) (isset($this->handler->options[$name]) ? $this->handler->options[$name] : $default);
}
/**
* Provides the token data that is passed when during replacement.
*
* @param string $value
* The current character value being processed.
*
* @return array
* Token data.
*
* @see alpha_pagination_token_info()
* @see alpha_pagination_tokens()
*/
public function getTokens($value = NULL) {
return [
'alpha_pagination' => [
'path' => $this
->getUrl(),
'value' => $value,
],
];
}
/**
* Retrieves the URL for the current view.
*
* Note: this follows very similarly to \view::get_url to process arguments,
* however it is in fact severely modified to account for characters appended
* by this module.
*
* @return string
* The URL for the view or current_path().
*/
public function getUrl() {
if (empty($this->url)) {
if (!empty($this->handler->view->override_url)) {
$this->url = $this->handler->view->override_url;
return $this->url;
}
$path = $this->handler->view
->getPath();
$args = $this->handler->view->args;
// Exclude arguments that were computed, not passed on the URL.
$position = 0;
if (!empty($this->handler->view->argument)) {
foreach ($this->handler->view->argument as $argument_id => $argument) {
if (!empty($argument->options['default_argument_skip_url'])) {
unset($args[$position]);
}
$position++;
}
}
// Don't bother working if there's nothing to do:
if (empty($path) || empty($args) && strpos($path, '%') === FALSE) {
$path = \Drupal::service('path.current')
->getPath();
$pieces = explode('/', $path);
// If getPath returns heading slash, remove it as it will ba
// added later.
if ($pieces[0] == '') {
array_shift($pieces);
}
if (array_key_exists(end($pieces), $this
->getCharacters())) {
array_pop($pieces);
}
$this->url = implode('/', $pieces);
return $this->url;
}
$pieces = [];
$argument_keys = isset($this->handler->view->argument) ? array_keys($this->handler->view->argument) : [];
$id = current($argument_keys);
foreach (explode('/', $path) as $piece) {
if ($piece != '%') {
$pieces[] = $piece;
}
else {
if (empty($args)) {
// Try to never put % in a url; use the wildcard instead.
if ($id && !empty($this->handler->view->argument[$id]->options['exception']['value'])) {
$pieces[] = $this->handler->view->argument[$id]->options['exception']['value'];
}
else {
// Gotta put something if there just isn't one.
$pieces[] = '*';
}
}
else {
$pieces[] = array_shift($args);
}
if ($id) {
$id = next($argument_keys);
}
}
}
// Just return the computed pieces, don't merge any extra remaining args.
$this->url = implode('/', $pieces);
}
return $this->url;
}
/**
* Retrieves the proper value for a character.
*
* @param mixed $value
* The value to retrieve.
*
* @return string
* The value.
*/
public function getValue($value) {
$characters = $this
->getCharacters();
// Return an appropriate numeric label.
if ($this
->getOption('paginate_view_numbers') === '2' && $this
->isNumeric($value)) {
return $characters[$this
->getOption('paginate_numeric_value')]
->getValue();
}
elseif (isset($characters[$value])) {
return $characters[$value]
->getLabel();
}
// Return the original value.
return $value;
}
/**
* Determines if value is "numeric".
*
* @param string $value
* The value to test.
*
* @return bool
* TRUE or FALSE
*/
public function isNumeric($value) {
return $this
->getOption('paginate_view_numbers') === '2' && $value === $this
->getOption('paginate_numeric_value') || in_array($value, $this
->getNumbers());
}
/**
* Parses an attribute string saved in the UI.
*
* @param string $string
* The attribute string to parse.
* @param array $tokens
* An associative array of token data to use.
*
* @return array
* A parsed attributes array.
*/
public function parseAttributes($string = NULL, array $tokens = []) {
$attributes = [];
if (!empty($string)) {
$parts = explode(',', $string);
foreach ($parts as $attribute) {
if (strpos($attribute, '|') !== FALSE) {
list($key, $value) = explode('|', $this->token
->replace($attribute, $tokens, [
'clear' => TRUE,
]));
$attributes[$key] = $value;
}
}
}
return $attributes;
}
/**
* {@inheritdoc}
*/
public function validate() {
$name = $this->handler->view
->id();
$display_id = $this->handler->view->current_display;
// Immediately return if display doesn't have the handler in question.
$items = $this->handler->view
->getHandlers($this->handler->areaType, $display_id);
$field = $this->handler->realField ?: $this->handler->field;
if (!isset($items[$field])) {
return [];
}
static $errors = [];
if (!isset($errors["{$name}:{$display_id}"])) {
$errors["{$name}:{$display_id}"] = [];
// Show an error if not found.
$areas = $this
->getAreaHandlers();
if (!$areas) {
$errors["{$name}:{$display_id}"][] = t('The view "@name:@display" must have at least one configured alpha pagination area in either the header or footer to use "@field".', [
'@field' => $field,
'@name' => $this->handler->view
->id(),
'@display' => $this->handler->view->current_display,
]);
}
elseif (count($areas) > 1) {
$errors["{$name}:{$display_id}"][] = t('The view "@name:@display" can only have one configured alpha pagination area in either the header or footer.', [
'@name' => $this->handler->view
->id(),
'@display' => $this->handler->view->current_display,
]);
}
}
return $errors["{$name}:{$display_id}"];
}
}
Classes
Name | Description |
---|---|
AlphaPagination | A base views handler for alpha pagination. |