Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c11935cb48 | ||
|
|
74e8ea8838 | ||
|
|
43e958758d | ||
|
|
34d706d0ca | ||
|
|
8c33189167 | ||
|
|
47cd70fca7 | ||
|
|
6156084abf | ||
|
|
4e805776ed | ||
|
|
65e37927b7 | ||
|
|
b7609524f9 | ||
|
|
e45bd14b7a | ||
|
|
23e66d3cb0 | ||
|
|
981091b3f4 | ||
|
|
6368cf17ef | ||
|
|
196f8058a8 | ||
|
|
b6ada4240f | ||
|
|
3c0c530910 | ||
|
|
0d6cbda7b3 | ||
|
|
68ded22790 | ||
|
|
c2b4c06a8f | ||
|
|
8a54ec0b43 | ||
|
|
d8b9162932 | ||
|
|
ebb5db14b5 | ||
|
|
3a66ee825e | ||
|
|
37988a3494 | ||
|
|
ee80899d18 |
@@ -7,6 +7,10 @@ web/sites/default/files/*
|
||||
web/sites/default/files/.*
|
||||
web/sites/default/settings.php
|
||||
web/sites/*/files
|
||||
web/sites/development.services.yml
|
||||
web/sites/development.services.yml
|
||||
web/sites/default/online_settings.php
|
||||
web/.htaccess
|
||||
|
||||
web/themes/custom/popsu_colloque/node_modules/*
|
||||
web/themes/custom/popsu_colloque/node_modules/.*
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"drupal/pathauto": "^1.8",
|
||||
"drupal/redirect": "^1.6",
|
||||
"drupal/redirect_after_login": "^2.6",
|
||||
"drupal/redis": "^1.4",
|
||||
"drupal/schema_metatag": "^1.5",
|
||||
"drupal/site_settings": "^1.19",
|
||||
"drupal/subpathauto": "^1.1",
|
||||
|
||||
Generated
+304
-204
File diff suppressed because it is too large
Load Diff
+1
-5
@@ -109,7 +109,7 @@ AddEncoding gzip svgz
|
||||
# VirtualDocumentRoot and the rewrite rules are not working properly.
|
||||
# For example if your site is at http://example.com/drupal uncomment and
|
||||
# modify the following line:
|
||||
RewriteBase /
|
||||
# RewriteBase /drupal
|
||||
#
|
||||
# If your site is running in a VirtualDocumentRoot at http://example.com/,
|
||||
# uncomment the following line:
|
||||
@@ -180,7 +180,3 @@ AddEncoding gzip svgz
|
||||
# Disable Proxy header, since it's an attack vector.
|
||||
RequestHeader unset Proxy
|
||||
</IfModule>
|
||||
|
||||
#RewriteEngine On
|
||||
#RewriteCond %{SERVER_PORT} 80
|
||||
#RewriteRule ^(.*)$ https://www.yourdomain.com/$1 [R,L]
|
||||
|
||||
@@ -781,10 +781,13 @@ $settings['migrate_node_migrate_type_classic'] = FALSE;
|
||||
/**
|
||||
* Load local development override configuration, if available.
|
||||
*
|
||||
* Use settings.local.php to override variables on secondary (staging,
|
||||
* development, etc) installations of this site. Typically used to disable
|
||||
* caching, JavaScript/CSS compression, re-routing of outgoing emails, and
|
||||
* other things that should not happen on development and testing sites.
|
||||
* Create a settings.local.php file to override variables on secondary (staging,
|
||||
* development, etc.) installations of this site.
|
||||
*
|
||||
* Typical uses of settings.local.php include:
|
||||
* - Disabling caching.
|
||||
* - Disabling JavaScript/CSS compression.
|
||||
* - Rerouting outgoing emails.
|
||||
*
|
||||
* Keep this code block at the end of this file to take full effect.
|
||||
*/
|
||||
|
||||
@@ -25,10 +25,10 @@ classList:
|
||||
|
||||
ckeditor:
|
||||
remote: https://github.com/ckeditor/ckeditor-dev
|
||||
version: "4.14.0"
|
||||
version: "4.14.1"
|
||||
license:
|
||||
name: GNU-GPL-2.0-or-later
|
||||
url: https://github.com/ckeditor/ckeditor4/blob/4.14.0/LICENSE.md
|
||||
url: https://github.com/ckeditor/ckeditor4/blob/4.14.1/LICENSE.md
|
||||
gpl-compatible: true
|
||||
js:
|
||||
assets/vendor/ckeditor/ckeditor.js: { preprocess: false, minified: true }
|
||||
|
||||
@@ -5,8 +5,6 @@ build:
|
||||
assessment:
|
||||
validate_codebase:
|
||||
phplint:
|
||||
csslint:
|
||||
halt-on-fail: false
|
||||
eslint:
|
||||
# A test must pass eslinting standards check in order to continue processing.
|
||||
halt-on-fail: false
|
||||
|
||||
@@ -233,7 +233,8 @@ function entity_load_unchanged($entity_type, $id) {
|
||||
* An array of entity IDs of the entities to delete.
|
||||
*
|
||||
* @deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use
|
||||
* the entity storage's delete() method to delete multiple entities:
|
||||
* the entity storage's \Drupal\Core\Entity\EntityStorageInterface::delete()
|
||||
* method to delete multiple entities:
|
||||
* @code
|
||||
* $storage_handler = \Drupal::entityTypeManager()->getStorage($entity_type);
|
||||
* $entities = $storage_handler->loadMultiple($ids);
|
||||
|
||||
@@ -26,13 +26,13 @@ use Drupal\Component\Utility\Html;
|
||||
* displays the third page of search results at that URL.
|
||||
*
|
||||
* @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use
|
||||
* \Drupal\Core\Pager\RequestPagerInterface->findPage() instead.
|
||||
* \Drupal\Core\Pager\PagerParametersInterface->findPage() instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2779457
|
||||
* @see \Drupal\Core\Pager\PagerParametersInterface::findPage()
|
||||
*/
|
||||
function pager_find_page($element = 0) {
|
||||
@trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Pager\RequestPagerInterface->findPage() instead. See https://www.drupal.org/node/2779457', E_USER_DEPRECATED);
|
||||
@trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Pager\PagerParametersInterface->findPage() instead. See https://www.drupal.org/node/2779457', E_USER_DEPRECATED);
|
||||
/* @var $pager_parameters \Drupal\Core\Pager\PagerParametersInterface */
|
||||
$pager_parameters = \Drupal::service('pager.parameters');
|
||||
return $pager_parameters->findPage($element);
|
||||
@@ -150,13 +150,13 @@ function pager_default_initialize($total, $limit, $element = 0) {
|
||||
* page request except for those pertaining to paging.
|
||||
*
|
||||
* @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use
|
||||
* \Drupal\Core\Pager\RequestPagerInterface->getQueryParameters() instead.
|
||||
* \Drupal\Core\Pager\PagerParametersInterface->getQueryParameters() instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2779457
|
||||
* @see \Drupal\Core\Pager\PagerParametersInterface::getQueryParameters()
|
||||
*/
|
||||
function pager_get_query_parameters() {
|
||||
@trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Pager\RequestPagerInterface->getQueryParameters() instead. See https://www.drupal.org/node/2779457', E_USER_DEPRECATED);
|
||||
@trigger_error(__FUNCTION__ . ' is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Pager\PagerParametersInterface->getQueryParameters() instead. See https://www.drupal.org/node/2779457', E_USER_DEPRECATED);
|
||||
/* @var $pager_params \Drupal\Core\Pager\PagerParametersInterface */
|
||||
$pager_params = \Drupal::service('pager.parameters');
|
||||
return $pager_params->getQueryParameters();
|
||||
|
||||
@@ -82,7 +82,7 @@ class Drupal {
|
||||
/**
|
||||
* The current system version.
|
||||
*/
|
||||
const VERSION = '8.9.2';
|
||||
const VERSION = '8.9.7';
|
||||
|
||||
/**
|
||||
* Core API compatibility.
|
||||
@@ -606,8 +606,8 @@ class Drupal {
|
||||
* This method is a convenience wrapper for the link generator service's
|
||||
* generate() method.
|
||||
*
|
||||
* @param string $text
|
||||
* The link text for the anchor tag.
|
||||
* @param string|array|\Drupal\Component\Render\MarkupInterface $text
|
||||
* The link text for the anchor tag as a translated string or render array.
|
||||
* @param \Drupal\Core\Url $url
|
||||
* The URL object used for the link.
|
||||
*
|
||||
|
||||
@@ -624,11 +624,10 @@ class DateTimePlus {
|
||||
$valid_date = FALSE;
|
||||
$valid_time = TRUE;
|
||||
// Check for a valid date using checkdate(). Only values that
|
||||
// meet that test are valid.
|
||||
if (array_key_exists('year', $array) && array_key_exists('month', $array) && array_key_exists('day', $array)) {
|
||||
if (@checkdate($array['month'], $array['day'], $array['year'])) {
|
||||
$valid_date = TRUE;
|
||||
}
|
||||
// meet that test are valid. An empty value, either a string or a 0, is not
|
||||
// a valid value.
|
||||
if (!empty($array['year']) && !empty($array['month']) && !empty($array['day'])) {
|
||||
$valid_date = checkdate($array['month'], $array['day'], $array['year']);
|
||||
}
|
||||
// Testing for valid time is reversed. Missing time is OK,
|
||||
// but incorrect values are not.
|
||||
|
||||
@@ -58,6 +58,21 @@ class PhpTransliteration implements TransliterationInterface {
|
||||
*/
|
||||
protected $genericMap = [];
|
||||
|
||||
/**
|
||||
* Special characters for ::removeDiacritics().
|
||||
*
|
||||
* Characters which have accented variants but their base character
|
||||
* transliterates to more than one ASCII character require special
|
||||
* treatment: we want to remove their accent and use the un-
|
||||
* transliterated base character.
|
||||
*/
|
||||
protected $fixTransliterateForRemoveDiacritics = [
|
||||
'AE' => 'Æ',
|
||||
'ae' => 'æ',
|
||||
'ZH' => 'Ʒ',
|
||||
'zh' => 'ʒ',
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructs a transliteration object.
|
||||
*
|
||||
@@ -93,6 +108,9 @@ class PhpTransliteration implements TransliterationInterface {
|
||||
if (strlen($to_add) === 1) {
|
||||
$replacement = $to_add;
|
||||
}
|
||||
elseif (isset($this->fixTransliterateForRemoveDiacritics[$to_add])) {
|
||||
$replacement = $this->fixTransliterateForRemoveDiacritics[$to_add];
|
||||
}
|
||||
}
|
||||
|
||||
$result .= $replacement;
|
||||
|
||||
@@ -35,7 +35,8 @@ class Bytes {
|
||||
return round($size * pow(self::KILOBYTE, stripos('bkmgtpezy', $unit[0])));
|
||||
}
|
||||
else {
|
||||
return round($size);
|
||||
// Ensure size is a proper number type.
|
||||
return round((float) $size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,6 @@ class Image {
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $dimensions was modified, FALSE otherwise.
|
||||
*
|
||||
* @see image_scale()
|
||||
*/
|
||||
public static function scaleDimensions(array &$dimensions, $width = NULL, $height = NULL, $upscale = FALSE) {
|
||||
$aspect = $dimensions['height'] / $dimensions['width'];
|
||||
|
||||
@@ -537,16 +537,16 @@ EOD;
|
||||
*/
|
||||
public static function mimeHeaderDecode($header) {
|
||||
$callback = function ($matches) {
|
||||
$data = ($matches[2] == 'B') ? base64_decode($matches[3]) : str_replace('_', ' ', quoted_printable_decode($matches[3]));
|
||||
$data = (strtolower($matches[2]) == 'b') ? base64_decode($matches[3]) : str_replace('_', ' ', quoted_printable_decode($matches[3]));
|
||||
if (strtolower($matches[1]) != 'utf-8') {
|
||||
$data = static::convertToUtf8($data, $matches[1]);
|
||||
}
|
||||
return $data;
|
||||
};
|
||||
// First step: encoded chunks followed by other encoded chunks (need to collapse whitespace)
|
||||
$header = preg_replace_callback('/=\?([^?]+)\?(Q|B)\?([^?]+|\?(?!=))\?=\s+(?==\?)/', $callback, $header);
|
||||
$header = preg_replace_callback('/=\?([^?]+)\?([Qq]|[Bb])\?([^?]+|\?(?!=))\?=\s+(?==\?)/', $callback, $header);
|
||||
// Second step: remaining chunks (do not collapse whitespace)
|
||||
return preg_replace_callback('/=\?([^?]+)\?(Q|B)\?([^?]+|\?(?!=))\?=/', $callback, $header);
|
||||
return preg_replace_callback('/=\?([^?]+)\?([Qq]|[Bb])\?([^?]+|\?(?!=))\?=/', $callback, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -345,7 +345,7 @@ class LibraryDiscoveryParser {
|
||||
$library_file = $path . '/' . $extension . '.libraries.yml';
|
||||
if (file_exists($this->root . '/' . $library_file)) {
|
||||
try {
|
||||
$libraries = Yaml::decode(file_get_contents($this->root . '/' . $library_file));
|
||||
$libraries = Yaml::decode(file_get_contents($this->root . '/' . $library_file)) ?? [];
|
||||
}
|
||||
catch (InvalidDataTypeException $e) {
|
||||
// Rethrow a more helpful exception to provide context.
|
||||
|
||||
@@ -2,18 +2,10 @@
|
||||
|
||||
namespace Drupal\Core\Block;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Messenger\MessengerTrait;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginBase;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Plugin\PluginWithFormsInterface;
|
||||
use Drupal\Core\Plugin\PluginWithFormsTrait;
|
||||
use Drupal\Core\Render\PreviewFallbackInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
|
||||
/**
|
||||
* Defines a base block implementation that most blocks plugins will extend.
|
||||
@@ -26,260 +18,7 @@ use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
*/
|
||||
abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface, PreviewFallbackInterface {
|
||||
|
||||
use BlockPluginTrait;
|
||||
use ContextAwarePluginAssignmentTrait;
|
||||
use MessengerTrait;
|
||||
use PluginWithFormsTrait;
|
||||
|
||||
/**
|
||||
* The transliteration service.
|
||||
*
|
||||
* @var \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected $transliteration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function label() {
|
||||
if (!empty($this->configuration['label'])) {
|
||||
return $this->configuration['label'];
|
||||
}
|
||||
|
||||
$definition = $this->getPluginDefinition();
|
||||
// Cast the admin label to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
return (string) $definition['admin_label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->setConfiguration($configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfiguration() {
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConfiguration(array $configuration) {
|
||||
$this->configuration = NestedArray::mergeDeep(
|
||||
$this->baseConfigurationDefaults(),
|
||||
$this->defaultConfiguration(),
|
||||
$configuration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns generic default configuration for block plugins.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with the default configuration.
|
||||
*/
|
||||
protected function baseConfigurationDefaults() {
|
||||
return [
|
||||
'id' => $this->getPluginId(),
|
||||
'label' => '',
|
||||
'provider' => $this->pluginDefinition['provider'],
|
||||
'label_display' => static::BLOCK_LABEL_VISIBLE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConfigurationValue($key, $value) {
|
||||
$this->configuration[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(AccountInterface $account, $return_as_object = FALSE) {
|
||||
$access = $this->blockAccess($account);
|
||||
return $return_as_object ? $access : $access->isAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the block should be shown.
|
||||
*
|
||||
* Blocks with specific access checking should override this method rather
|
||||
* than access(), in order to avoid repeating the handling of the
|
||||
* $return_as_object argument.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user session for which to check access.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResult
|
||||
* The access result.
|
||||
*
|
||||
* @see self::access()
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
// By default, the block is visible.
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Creates a generic configuration form for all block types. Individual
|
||||
* block plugins can add elements to this form by overriding
|
||||
* BlockBase::blockForm(). Most block plugins should not override this
|
||||
* method unless they need to alter the generic form elements.
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::blockForm()
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$definition = $this->getPluginDefinition();
|
||||
$form['provider'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $definition['provider'],
|
||||
];
|
||||
|
||||
$form['admin_label'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->t('Block description'),
|
||||
'#plain_text' => $definition['admin_label'],
|
||||
];
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Title'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $this->label(),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['label_display'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Display title'),
|
||||
'#default_value' => ($this->configuration['label_display'] === static::BLOCK_LABEL_VISIBLE),
|
||||
'#return_value' => static::BLOCK_LABEL_VISIBLE,
|
||||
];
|
||||
|
||||
// Add context mapping UI form elements.
|
||||
$contexts = $form_state->getTemporaryValue('gathered_contexts') ?: [];
|
||||
$form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts);
|
||||
// Add plugin-specific settings for this block type.
|
||||
$form += $this->blockForm($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Most block plugins should not override this method. To add validation
|
||||
* for a specific block type, override BlockBase::blockValidate().
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::blockValidate()
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
// Remove the admin_label form item element value so it will not persist.
|
||||
$form_state->unsetValue('admin_label');
|
||||
|
||||
$this->blockValidate($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockValidate($form, FormStateInterface $form_state) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Most block plugins should not override this method. To add submission
|
||||
* handling for a specific block type, override BlockBase::blockSubmit().
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::blockSubmit()
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
// Process the block's submission handling if no errors occurred only.
|
||||
if (!$form_state->getErrors()) {
|
||||
$this->configuration['label'] = $form_state->getValue('label');
|
||||
$this->configuration['label_display'] = $form_state->getValue('label_display');
|
||||
$this->configuration['provider'] = $form_state->getValue('provider');
|
||||
$this->blockSubmit($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMachineNameSuggestion() {
|
||||
$definition = $this->getPluginDefinition();
|
||||
$admin_label = $definition['admin_label'];
|
||||
|
||||
// @todo This is basically the same as what is done in
|
||||
// \Drupal\system\MachineNameController::transliterate(), so it might make
|
||||
// sense to provide a common service for the two.
|
||||
$transliterated = $this->transliteration()->transliterate($admin_label, LanguageInterface::LANGCODE_DEFAULT, '_');
|
||||
$transliterated = mb_strtolower($transliterated);
|
||||
|
||||
$transliterated = preg_replace('@[^a-z0-9_.]+@', '', $transliterated);
|
||||
|
||||
return $transliterated;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPreviewFallbackString() {
|
||||
return $this->t('"@block" block', ['@block' => $this->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the transliteration service.
|
||||
*
|
||||
* @return \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected function transliteration() {
|
||||
if (!$this->transliteration) {
|
||||
$this->transliteration = \Drupal::transliteration();
|
||||
}
|
||||
return $this->transliteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transliteration service.
|
||||
*
|
||||
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
|
||||
* The transliteration service.
|
||||
*/
|
||||
public function setTransliteration(TransliterationInterface $transliteration) {
|
||||
$this->transliteration = $transliteration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Core\Block;
|
||||
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Messenger\MessengerTrait;
|
||||
use Drupal\Core\Plugin\PluginWithFormsTrait;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Provides the base implementation of a block plugin.
|
||||
*
|
||||
* @internal
|
||||
* This trait is used internally by the block system. Block plugins should
|
||||
* extend \Drupal\Core\Block\BlockBase.
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase
|
||||
* @see \Drupal\Core\Block\BlockPluginInterface
|
||||
*
|
||||
* @ingroup block_api
|
||||
*/
|
||||
trait BlockPluginTrait {
|
||||
|
||||
use StringTranslationTrait;
|
||||
use MessengerTrait;
|
||||
use PluginWithFormsTrait;
|
||||
|
||||
/**
|
||||
* The transliteration service.
|
||||
*
|
||||
* @var \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected $transliteration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function label() {
|
||||
if (!empty($this->configuration['label'])) {
|
||||
return $this->configuration['label'];
|
||||
}
|
||||
|
||||
$definition = $this->getPluginDefinition();
|
||||
// Cast the admin label to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
return (string) $definition['admin_label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->setConfiguration($configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfiguration() {
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConfiguration(array $configuration) {
|
||||
$this->configuration = NestedArray::mergeDeep(
|
||||
$this->baseConfigurationDefaults(),
|
||||
$this->defaultConfiguration(),
|
||||
$configuration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns generic default configuration for block plugins.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with the default configuration.
|
||||
*/
|
||||
protected function baseConfigurationDefaults() {
|
||||
return [
|
||||
'id' => $this->getPluginId(),
|
||||
'label' => '',
|
||||
'provider' => $this->pluginDefinition['provider'],
|
||||
'label_display' => BlockPluginInterface::BLOCK_LABEL_VISIBLE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConfigurationValue($key, $value) {
|
||||
$this->configuration[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(AccountInterface $account, $return_as_object = FALSE) {
|
||||
$access = $this->blockAccess($account);
|
||||
return $return_as_object ? $access : $access->isAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the block should be shown.
|
||||
*
|
||||
* Blocks with specific access checking should override this method rather
|
||||
* than access(), in order to avoid repeating the handling of the
|
||||
* $return_as_object argument.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user session for which to check access.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResult
|
||||
* The access result.
|
||||
*
|
||||
* @see self::access()
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
// By default, the block is visible.
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Creates a generic configuration form for all block types. Individual
|
||||
* block plugins can add elements to this form by overriding
|
||||
* BlockBase::blockForm(). Most block plugins should not override this
|
||||
* method unless they need to alter the generic form elements.
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::blockForm()
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$definition = $this->getPluginDefinition();
|
||||
$form['provider'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $definition['provider'],
|
||||
];
|
||||
|
||||
$form['admin_label'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->t('Block description'),
|
||||
'#plain_text' => $definition['admin_label'],
|
||||
];
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Title'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $this->label(),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['label_display'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Display title'),
|
||||
'#default_value' => ($this->configuration['label_display'] === BlockPluginInterface::BLOCK_LABEL_VISIBLE),
|
||||
'#return_value' => BlockPluginInterface::BLOCK_LABEL_VISIBLE,
|
||||
];
|
||||
|
||||
// Add context mapping UI form elements.
|
||||
$contexts = $form_state->getTemporaryValue('gathered_contexts') ?: [];
|
||||
$form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts);
|
||||
// Add plugin-specific settings for this block type.
|
||||
$form += $this->blockForm($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Most block plugins should not override this method. To add validation
|
||||
* for a specific block type, override BlockBase::blockValidate().
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::blockValidate()
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
// Remove the admin_label form item element value so it will not persist.
|
||||
$form_state->unsetValue('admin_label');
|
||||
|
||||
$this->blockValidate($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockValidate($form, FormStateInterface $form_state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Most block plugins should not override this method. To add submission
|
||||
* handling for a specific block type, override BlockBase::blockSubmit().
|
||||
*
|
||||
* @see \Drupal\Core\Block\BlockBase::blockSubmit()
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
// Process the block's submission handling if no errors occurred only.
|
||||
if (!$form_state->getErrors()) {
|
||||
$this->configuration['label'] = $form_state->getValue('label');
|
||||
$this->configuration['label_display'] = $form_state->getValue('label_display');
|
||||
$this->configuration['provider'] = $form_state->getValue('provider');
|
||||
$this->blockSubmit($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMachineNameSuggestion() {
|
||||
$definition = $this->getPluginDefinition();
|
||||
$admin_label = $definition['admin_label'];
|
||||
|
||||
// @todo This is basically the same as what is done in
|
||||
// \Drupal\system\MachineNameController::transliterate(), so it might make
|
||||
// sense to provide a common service for the two.
|
||||
$transliterated = $this->transliteration()->transliterate($admin_label, LanguageInterface::LANGCODE_DEFAULT, '_');
|
||||
$transliterated = mb_strtolower($transliterated);
|
||||
|
||||
$transliterated = preg_replace('@[^a-z0-9_.]+@', '', $transliterated);
|
||||
|
||||
return $transliterated;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPreviewFallbackString() {
|
||||
return $this->t('"@block" block', ['@block' => $this->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the transliteration service.
|
||||
*
|
||||
* @return \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected function transliteration() {
|
||||
if (!$this->transliteration) {
|
||||
$this->transliteration = \Drupal::transliteration();
|
||||
}
|
||||
return $this->transliteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transliteration service.
|
||||
*
|
||||
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
|
||||
* The transliteration service.
|
||||
*/
|
||||
public function setTransliteration(TransliterationInterface $transliteration) {
|
||||
$this->transliteration = $transliteration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace Drupal\Core\Block\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\Core\Block\BlockPluginTrait;
|
||||
use Drupal\Core\Cache\CacheableDependencyTrait;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
|
||||
/**
|
||||
* Defines a fallback plugin for missing block plugins.
|
||||
@@ -14,7 +17,10 @@ use Drupal\Core\Form\FormStateInterface;
|
||||
* category = @Translation("Block"),
|
||||
* )
|
||||
*/
|
||||
class Broken extends BlockBase {
|
||||
class Broken extends PluginBase implements BlockPluginInterface {
|
||||
|
||||
use BlockPluginTrait;
|
||||
use CacheableDependencyTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -121,7 +121,7 @@ final class ConfigEvents {
|
||||
* fire the event again to continue processing missing content dependencies.
|
||||
*
|
||||
* @see \Drupal\Core\Config\ConfigImporter::processMissingContent()
|
||||
* @see \Drupal\Core\Config\MissingContentEvent
|
||||
* @see \Drupal\Core\Config\Importer\MissingContentEvent
|
||||
*/
|
||||
const IMPORT_MISSING_CONTENT = 'config.importer.missing_content';
|
||||
|
||||
|
||||
@@ -130,6 +130,11 @@ class Condition extends ConditionBase {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
// If the parent does not exist, it's safe to say the actual property
|
||||
// we're checking for is also NULL.
|
||||
elseif ($condition['operator'] === 'IS NULL') {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
// Only try to match a scalar if there are no remaining keys in
|
||||
// $needs_matching as this indicates that we are looking for a specific
|
||||
|
||||
@@ -89,7 +89,14 @@ class Query extends QueryBase implements QueryInterface {
|
||||
$direction = $sort['direction'] == 'ASC' ? -1 : 1;
|
||||
$field = $sort['field'];
|
||||
uasort($result, function ($a, $b) use ($field, $direction) {
|
||||
return ($a[$field] <= $b[$field]) ? $direction : -$direction;
|
||||
$properties = explode('.', $field);
|
||||
foreach ($properties as $property) {
|
||||
if (isset($a[$property]) || isset($b[$property])) {
|
||||
$a = isset($a[$property]) ? $a[$property] : NULL;
|
||||
$b = isset($b[$property]) ? $b[$property] : NULL;
|
||||
}
|
||||
}
|
||||
return ($a <= $b) ? $direction : -$direction;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use Symfony\Component\EventDispatcher\Event;
|
||||
/**
|
||||
* Wraps a configuration event for event listeners.
|
||||
*
|
||||
* @see \Drupal\Core\Config\Config\ConfigEvents::IMPORT_MISSING_CONTENT
|
||||
* @see \Drupal\Core\Config\ConfigEvents::IMPORT_MISSING_CONTENT
|
||||
*/
|
||||
class MissingContentEvent extends Event {
|
||||
|
||||
|
||||
@@ -1501,8 +1501,8 @@ abstract class Connection {
|
||||
/**
|
||||
* Prepares a statement for execution and returns a statement object
|
||||
*
|
||||
* Emulated prepared statements does not communicate with the database server
|
||||
* so this method does not check the statement.
|
||||
* Emulated prepared statements do not communicate with the database server so
|
||||
* this method does not check the statement.
|
||||
*
|
||||
* @param string $statement
|
||||
* This must be a valid SQL statement for the target database server.
|
||||
|
||||
@@ -686,11 +686,11 @@ class Schema extends DatabaseSchema {
|
||||
$condition->condition('column_name', $column);
|
||||
$condition->compile($this->connection, $this);
|
||||
// Don't use {} around information_schema.columns table.
|
||||
return $this->connection->query("SELECT column_comment as column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
|
||||
return $this->connection->query("SELECT column_comment AS column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
|
||||
}
|
||||
$condition->compile($this->connection, $this);
|
||||
// Don't use {} around information_schema.tables table.
|
||||
$comment = $this->connection->query("SELECT table_comment as table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
|
||||
$comment = $this->connection->query("SELECT table_comment AS table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
|
||||
// Work-around for MySQL 5.0 bug http://bugs.mysql.com/bug.php?id=11379
|
||||
return preg_replace('/; InnoDB free:.*$/', '', $comment);
|
||||
}
|
||||
|
||||
@@ -814,13 +814,16 @@ class Select extends Query implements SelectInterface {
|
||||
$fields = [];
|
||||
foreach ($this->tables as $alias => $table) {
|
||||
if (!empty($table['all_fields'])) {
|
||||
$fields[] = $this->connection->escapeTable($alias) . '.*';
|
||||
$fields[] = $this->connection->escapeAlias($alias) . '.*';
|
||||
}
|
||||
}
|
||||
foreach ($this->fields as $field) {
|
||||
// Note that $field['table'] holds the table alias.
|
||||
// @see \Drupal\Core\Database\Query\Select::addField
|
||||
$table = isset($field['table']) ? $this->connection->escapeAlias($field['table']) . '.' : '';
|
||||
// Always use the AS keyword for field aliases, as some
|
||||
// databases require it (e.g., PostgreSQL).
|
||||
$fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
|
||||
$fields[] = $table . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
|
||||
}
|
||||
foreach ($this->expressions as $expression) {
|
||||
$fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']);
|
||||
@@ -852,7 +855,7 @@ class Select extends Query implements SelectInterface {
|
||||
|
||||
// Don't use the AS keyword for table aliases, as some
|
||||
// databases don't support it (e.g., Oracle).
|
||||
$query .= $table_string . ' ' . $this->connection->escapeTable($table['alias']);
|
||||
$query .= $table_string . ' ' . $this->connection->escapeAlias($table['alias']);
|
||||
|
||||
if (!empty($table['condition'])) {
|
||||
$query .= ' ON ' . (string) $table['condition'];
|
||||
|
||||
@@ -200,7 +200,7 @@ abstract class Schema implements PlaceholderInterface {
|
||||
// couldn't use \Drupal::database()->select() here because it would prefix
|
||||
// information_schema.tables and the query would fail.
|
||||
// Don't use {} around information_schema.tables table.
|
||||
$results = $this->connection->query("SELECT table_name as table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments());
|
||||
$results = $this->connection->query("SELECT table_name AS table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments());
|
||||
foreach ($results as $table) {
|
||||
// Take into account tables that have an individual prefix.
|
||||
if (isset($individually_prefixed_tables[$table->table_name])) {
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Drupal\Core\DependencyInjection;
|
||||
trait DeprecatedServicePropertyTrait {
|
||||
|
||||
/**
|
||||
* Alows to access deprecated/removed properties.
|
||||
* Allows to access deprecated/removed properties.
|
||||
*
|
||||
* This method must be public.
|
||||
*/
|
||||
|
||||
@@ -70,7 +70,7 @@ interface ContentEntityFormInterface extends EntityFormInterface {
|
||||
* For more information about entity validation, see
|
||||
* https://www.drupal.org/node/2015613.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityTypeInterface
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
* The built entity.
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state);
|
||||
|
||||
@@ -14,8 +14,54 @@ use Drupal\Core\Site\Settings;
|
||||
/**
|
||||
* Provides an entity autocomplete form element.
|
||||
*
|
||||
* The #default_value accepted by this element is either an entity object or an
|
||||
* array of entity objects.
|
||||
* The autocomplete form element allows users to select one or multiple
|
||||
* entities, which can come from all or specific bundles of an entity type.
|
||||
*
|
||||
* Properties:
|
||||
* - #target_type: (required) The ID of the target entity type.
|
||||
* - #tags: (optional) TRUE if the element allows multiple selection. Defaults
|
||||
* to FALSE.
|
||||
* - #default_value: (optional) The default entity or an array of default
|
||||
* entities, depending on the value of #tags.
|
||||
* - #selection_handler: (optional) The plugin ID of the entity reference
|
||||
* selection handler (a plugin of type EntityReferenceSelection). The default
|
||||
* value is the lowest-weighted plugin that is compatible with #target_type.
|
||||
* - #selection_settings: (optional) An array of settings for the selection
|
||||
* handler. Settings for the default selection handler
|
||||
* \Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection are:
|
||||
* - target_bundles: Array of bundles to allow (omit to allow all bundles).
|
||||
* - sort: Array with 'field' and 'direction' keys, determining how results
|
||||
* will be sorted. Defaults to unsorted.
|
||||
* - #autocreate: (optional) Array of settings used to auto-create entities
|
||||
* that do not exist (omit to not auto-create entities). Elements:
|
||||
* - bundle: (required) Bundle to use for auto-created entities.
|
||||
* - uid: User ID to use as the author of auto-created entities. Defaults to
|
||||
* the current user.
|
||||
* - #process_default_value: (optional) Set to FALSE if the #default_value
|
||||
* property is processed and access checked elsewhere (such as by a Field API
|
||||
* widget). Defaults to TRUE.
|
||||
* - #validate_reference: (optional) Set to FALSE if validation of the selected
|
||||
* entities is performed elsewhere. Defaults to TRUE.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* $form['my_element'] = [
|
||||
* '#type' => 'entity_autocomplete',
|
||||
* '#target_type' => 'node',
|
||||
* '#tags' => TRUE,
|
||||
* '#default_value' => $node,
|
||||
* '#selection_handler' => 'default',
|
||||
* '#selection_settings' => [
|
||||
* 'target_bundles' => ['article', 'page'],
|
||||
* ],
|
||||
* '#autocreate' => [
|
||||
* 'bundle' => 'article',
|
||||
* 'uid' => <a valid user ID>,
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection
|
||||
*
|
||||
* @FormElement("entity_autocomplete")
|
||||
*/
|
||||
|
||||
+9
-6
@@ -395,13 +395,16 @@ class DefaultSelection extends SelectionPluginBase implements ContainerFactoryPl
|
||||
*/
|
||||
public function createNewEntity($entity_type_id, $bundle, $label, $uid) {
|
||||
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
|
||||
$bundle_key = $entity_type->getKey('bundle');
|
||||
$label_key = $entity_type->getKey('label');
|
||||
|
||||
$entity = $this->entityTypeManager->getStorage($entity_type_id)->create([
|
||||
$bundle_key => $bundle,
|
||||
$label_key => $label,
|
||||
]);
|
||||
$values = [
|
||||
$entity_type->getKey('label') => $label,
|
||||
];
|
||||
|
||||
if ($bundle_key = $entity_type->getKey('bundle')) {
|
||||
$values[$bundle_key] = $bundle;
|
||||
}
|
||||
|
||||
$entity = $this->entityTypeManager->getStorage($entity_type_id)->create($values);
|
||||
|
||||
if ($entity instanceof EntityOwnerInterface) {
|
||||
$entity->setOwnerId($uid);
|
||||
|
||||
@@ -846,8 +846,19 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
|
||||
|
||||
// Add the bundle column.
|
||||
if ($bundle = $this->entityType->getKey('bundle')) {
|
||||
if ($base_table) {
|
||||
$select->join($base_table, 'base_table', "entity_table.{$this->entityType->getKey('id')} = %alias.{$this->entityType->getKey('id')}");
|
||||
// The bundle field is not stored in the revision table, so we need to
|
||||
// join the data (or base) table and retrieve it from there.
|
||||
if ($base_table && $base_table !== $table_name) {
|
||||
$join_condition = "entity_table.{$this->entityType->getKey('id')} = %alias.{$this->entityType->getKey('id')}";
|
||||
|
||||
// If the entity type is translatable, we also need to add the langcode
|
||||
// to the join, otherwise we'll get duplicate rows for each language.
|
||||
if ($this->entityType->isTranslatable()) {
|
||||
$langcode = $this->entityType->getKey('langcode');
|
||||
$join_condition .= " AND entity_table.{$langcode} = %alias.{$langcode}";
|
||||
}
|
||||
|
||||
$select->join($base_table, 'base_table', $join_condition);
|
||||
$select->addField('base_table', $bundle, 'bundle');
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -616,6 +616,18 @@ use Drupal\node\Entity\NodeType;
|
||||
* are invoked are hook_entity_create_access() and
|
||||
* hook_ENTITY_TYPE_create_access() instead.
|
||||
*
|
||||
* The access to an entity can be influenced in several ways:
|
||||
* - To explicitly allow access, return an AccessResultInterface object with
|
||||
* isAllowed() returning TRUE. Other modules can override this access by
|
||||
* returning TRUE for isForbidden().
|
||||
* - To explicitly forbid access, return an AccessResultInterface object with
|
||||
* isForbidden() returning TRUE. Access will be forbidden even if your module
|
||||
* (or another module) also returns TRUE for isNeutral() or isAllowed().
|
||||
* - To neither allow nor explicitly forbid access, return an
|
||||
* AccessResultInterface object with isNeutral() returning TRUE.
|
||||
* - If your module does not return an AccessResultInterface object, neutral
|
||||
* access will be assumed.
|
||||
*
|
||||
* The Node entity type has a complex system for determining access, which
|
||||
* developers can interact with. This is described in the
|
||||
* @link node_access Node access topic. @endlink
|
||||
@@ -643,7 +655,10 @@ use Drupal\node\Entity\NodeType;
|
||||
* @param string $operation
|
||||
* The operation that is to be performed on $entity.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The account trying to access the entity.
|
||||
* The account trying to access the entity. Usually one of:
|
||||
* - "view"
|
||||
* - "update"
|
||||
* - "delete"
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result. The final result is calculated by using
|
||||
@@ -677,7 +692,10 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to check access to.
|
||||
* @param string $operation
|
||||
* The operation that is to be performed on $entity.
|
||||
* The operation that is to be performed on $entity. Usually one of:
|
||||
* - "view"
|
||||
* - "update"
|
||||
* - "delete"
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The account trying to access the entity.
|
||||
*
|
||||
|
||||
@@ -42,6 +42,7 @@ class ExceptionLoggingSubscriber implements EventSubscriberInterface {
|
||||
// why access was denied.
|
||||
$exception = $event->getException();
|
||||
$error = Error::decodeException($exception);
|
||||
unset($error['@backtrace_string']);
|
||||
$error['@uri'] = $event->getRequest()->getRequestUri();
|
||||
$this->logger->get('access denied')->warning('Path: @uri. %type: @message in %function (line %line of %file).', $error);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class BooleanCheckboxWidget extends WidgetBase {
|
||||
$summary = [];
|
||||
|
||||
$display_label = $this->getSetting('display_label');
|
||||
$summary[] = t('Use field label: @display_label', ['@display_label' => ($display_label ? t('Yes') : 'No')]);
|
||||
$summary[] = t('Use field label: @display_label', ['@display_label' => ($display_label ? t('Yes') : t('No'))]);
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
+12
-5
@@ -117,7 +117,7 @@ class EntityReferenceAutocompleteWidget extends WidgetBase {
|
||||
'#placeholder' => $this->getSetting('placeholder'),
|
||||
];
|
||||
|
||||
if ($this->getSelectionHandlerSetting('auto_create') && ($bundle = $this->getAutocreateBundle())) {
|
||||
if ($bundle = $this->getAutocreateBundle()) {
|
||||
$element['#autocreate'] = [
|
||||
'bundle' => $bundle,
|
||||
'uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
|
||||
@@ -154,16 +154,23 @@ class EntityReferenceAutocompleteWidget extends WidgetBase {
|
||||
* Returns the name of the bundle which will be used for autocreated entities.
|
||||
*
|
||||
* @return string
|
||||
* The bundle name.
|
||||
* The bundle name. If autocreate is not active, NULL will be returned.
|
||||
*/
|
||||
protected function getAutocreateBundle() {
|
||||
$bundle = NULL;
|
||||
if ($this->getSelectionHandlerSetting('auto_create') && $target_bundles = $this->getSelectionHandlerSetting('target_bundles')) {
|
||||
if ($this->getSelectionHandlerSetting('auto_create')) {
|
||||
$target_bundles = $this->getSelectionHandlerSetting('target_bundles');
|
||||
// If there's no target bundle at all, use the target_type. It's the
|
||||
// default for bundleless entity types.
|
||||
if (empty($target_bundles)) {
|
||||
$bundle = $this->getFieldSetting('target_type');
|
||||
}
|
||||
// If there's only one target bundle, use it.
|
||||
if (count($target_bundles) == 1) {
|
||||
elseif (count($target_bundles) == 1) {
|
||||
$bundle = reset($target_bundles);
|
||||
}
|
||||
// Otherwise use the target bundle stored in selection handler settings.
|
||||
// If there's more than one target bundle, use the autocreate bundle
|
||||
// stored in selection handler settings.
|
||||
elseif (!$bundle = $this->getSelectionHandlerSetting('auto_create_bundle')) {
|
||||
// If no bundle has been set as auto create target means that there is
|
||||
// an inconsistency in entity reference field settings.
|
||||
|
||||
@@ -861,7 +861,8 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
|
||||
// https://www.drupal.org/node/2504709.
|
||||
$parsed = UrlHelper::parse($request_uri);
|
||||
unset($parsed['query'][static::AJAX_FORM_REQUEST], $parsed['query'][MainContentViewSubscriber::WRAPPER_FORMAT]);
|
||||
return $parsed['path'] . ($parsed['query'] ? ('?' . UrlHelper::buildQuery($parsed['query'])) : '');
|
||||
$action = $parsed['path'] . ($parsed['query'] ? ('?' . UrlHelper::buildQuery($parsed['query'])) : '');
|
||||
return UrlHelper::filterBadProtocol($action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,8 +66,8 @@ class Link implements RenderableInterface {
|
||||
/**
|
||||
* Creates a Link object from a given Url object.
|
||||
*
|
||||
* @param string $text
|
||||
* The text of the link.
|
||||
* @param string|array|\Drupal\Component\Render\MarkupInterface $text
|
||||
* The link text for the anchor tag as a translated string or render array.
|
||||
* @param \Drupal\Core\Url $url
|
||||
* The Url to create the link for.
|
||||
*
|
||||
|
||||
@@ -10,13 +10,13 @@ use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
* Logging severity levels as defined in RFC 5424.
|
||||
*
|
||||
* The constant definitions of this class correspond to the logging severity
|
||||
* levels defined in RFC 5424, section 4.1.1. PHP supplies predefined LOG_*
|
||||
* levels defined in RFC 5424, section 6.2.1. PHP supplies predefined LOG_*
|
||||
* constants for use in the syslog() function, but their values on Windows
|
||||
* builds do not correspond to RFC 5424. The associated PHP bug report was
|
||||
* closed with the comment, "And it's also not a bug, as Windows just have less
|
||||
* log levels," and "So the behavior you're seeing is perfectly normal."
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc5424
|
||||
* @see https://tools.ietf.org/html/rfc5424#section-6.2.1
|
||||
* @see http://bugs.php.net/bug.php?id=18090
|
||||
* @see http://php.net/manual/function.syslog.php
|
||||
* @see http://php.net/manual/network.constants.php
|
||||
|
||||
@@ -15,14 +15,14 @@ use Drupal\Core\Render\Element;
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* $form['email'] = array(
|
||||
* $form['email'] = [
|
||||
* '#type' => 'email',
|
||||
* '#title' => $this->t('Email'),
|
||||
* '#pattern' => '*@example.com',
|
||||
* );
|
||||
* @end
|
||||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\Core\Render\Element\Render\Textfield
|
||||
* @see \Drupal\Core\Render\Element\Textfield
|
||||
*
|
||||
* @FormElement("email")
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,7 @@ class StatusReport extends RenderElement {
|
||||
// Order the grouped requirements by a set order.
|
||||
$order = array_flip($element['#priorities']);
|
||||
uksort($grouped_requirements, function ($a, $b) use ($order) {
|
||||
return $order[$a] > $order[$b];
|
||||
return $order[$a] <=> $order[$b];
|
||||
});
|
||||
|
||||
$element['#grouped_requirements'] = $grouped_requirements;
|
||||
|
||||
@@ -414,13 +414,16 @@
|
||||
* render array contained:
|
||||
* @code
|
||||
* $build['my_element'] = [
|
||||
* '#attached' => ['placeholders' => ['@foo' => 'replacement']],
|
||||
* '#markup' => ['Something about @foo'],
|
||||
* '#markup' => 'Something about @foo',
|
||||
* '#attached' => [
|
||||
* 'placeholders' => [
|
||||
* '@foo' => ['#markup' => 'replacement'],
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
* then #markup would end up containing 'Something about replacement'.
|
||||
*
|
||||
* Note that each placeholder value can itself be a render array, which will be
|
||||
* Note that each placeholder value *must* itself be a render array. It will be
|
||||
* rendered, and any cache tags generated during rendering will be added to the
|
||||
* cache tags for the markup.
|
||||
*
|
||||
|
||||
@@ -60,8 +60,8 @@ class PharExtensionInterceptor implements Assertable {
|
||||
return FALSE;
|
||||
}
|
||||
// If the stream wrapper is registered by invoking a phar file that does
|
||||
// not not have .phar extension then this should be allowed. For
|
||||
// example, some CLI tools recommend removing the extension.
|
||||
// not have .phar extension then this should be allowed. For example, some
|
||||
// CLI tools recommend removing the extension.
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
// Find the last entry in the backtrace containing a 'file' key as
|
||||
// sometimes the last caller is executed outside the scope of a file. For
|
||||
|
||||
@@ -26,7 +26,7 @@ class AttributeHelper {
|
||||
* An Attribute object or an array of attributes.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the attibute exists, FALSE otherwise.
|
||||
* TRUE if the attribute exists, FALSE otherwise.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* When the input $collection is neither an Attribute object nor an array.
|
||||
|
||||
@@ -205,7 +205,7 @@ class PhpUnitTestRunner implements ContainerInjectionInterface {
|
||||
*/
|
||||
public function runTests($test_id, array $unescaped_test_classnames, &$status = NULL) {
|
||||
$phpunit_file = $this->xmlLogFilePath($test_id);
|
||||
// Store ouptut from our test run.
|
||||
// Store output from our test run.
|
||||
$output = [];
|
||||
$this->runCommand($unescaped_test_classnames, $phpunit_file, $status, $output);
|
||||
|
||||
@@ -217,7 +217,7 @@ class PhpUnitTestRunner implements ContainerInjectionInterface {
|
||||
'test_id' => $test_id,
|
||||
'test_class' => implode(",", $unescaped_test_classnames),
|
||||
'status' => TestStatus::label($status),
|
||||
'message' => 'PHPunit Test failed to complete; Error: ' . implode("\n", $output),
|
||||
'message' => 'PHPUnit Test failed to complete; Error: ' . implode("\n", $output),
|
||||
'message_group' => 'Other',
|
||||
'function' => implode(",", $unescaped_test_classnames),
|
||||
'line' => '0',
|
||||
|
||||
@@ -169,7 +169,15 @@ class TypedDataManager extends DefaultPluginManager implements TypedDataManagerI
|
||||
$parts[] = json_encode($settings);
|
||||
}
|
||||
// Property path for the requested data object.
|
||||
$parts[] = $object->getPropertyPath() . '.' . $property_name;
|
||||
$parts[] = $object->getPropertyPath();
|
||||
// Only property instances of complex data types should be cached by the
|
||||
// property name, as they represent different properties. Properties of list
|
||||
// data types are the items of the list and the property name represents
|
||||
// only the delta in that list and not an unique property, which is why all
|
||||
// items should use the same prototype.
|
||||
if ($object instanceof ComplexDataInterface) {
|
||||
$parts[] = $property_name;
|
||||
}
|
||||
$key = implode(':', $parts);
|
||||
|
||||
// Create the prototype if needed.
|
||||
|
||||
@@ -27,16 +27,28 @@ class UpdateCompilerPass implements CompilerPassInterface {
|
||||
do {
|
||||
$has_changed = FALSE;
|
||||
foreach ($container->getDefinitions() as $key => $definition) {
|
||||
// Ensure all the definition's arguments are valid.
|
||||
foreach ($definition->getArguments() as $argument) {
|
||||
if ($argument instanceof Reference) {
|
||||
$argument_id = (string) $argument;
|
||||
if (!$container->has($argument_id) && $argument->getInvalidBehavior() === ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
|
||||
// If the container does not have the argument and would throw an
|
||||
// exception, remove the service.
|
||||
if ($this->isArgumentMissingService($argument, $container)) {
|
||||
$container->removeDefinition($key);
|
||||
$container->log($this, sprintf('Removed service "%s"; reason: depends on non-existent service "%s".', $key, (string) $argument));
|
||||
$has_changed = TRUE;
|
||||
$process_aliases = TRUE;
|
||||
// Process the next definition.
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure all the method call arguments are valid.
|
||||
foreach ($definition->getMethodCalls() as $call) {
|
||||
foreach ($call[1] as $argument) {
|
||||
if ($this->isArgumentMissingService($argument, $container)) {
|
||||
$container->removeDefinition($key);
|
||||
$container->log($this, sprintf('Removed service "%s"; reason: depends on non-existent service "%s".', $key, $argument_id));
|
||||
$container->log($this, sprintf('Removed service "%s"; reason: method call "%s" depends on non-existent service "%s".', $key, $call[0], (string) $argument));
|
||||
$has_changed = TRUE;
|
||||
$process_aliases = TRUE;
|
||||
// Process the next definition.
|
||||
continue 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,4 +70,26 @@ class UpdateCompilerPass implements CompilerPassInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a reference argument is to a missing service.
|
||||
*
|
||||
* @param mixed $argument
|
||||
* The argument to check.
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* The container.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the argument is a reference to a service that is missing from the
|
||||
* container and the reference is required, FALSE if not.
|
||||
*/
|
||||
private function isArgumentMissingService($argument, ContainerBuilder $container) {
|
||||
if ($argument instanceof Reference) {
|
||||
$argument_id = (string) $argument;
|
||||
if (!$container->has($argument_id) && $argument->getInvalidBehavior() === ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ class Url implements TrustedCallbackInterface {
|
||||
// Extract query parameters and fragment and merge them into $uri_options,
|
||||
// but preserve the original $options for the fallback case.
|
||||
$uri_options = $options;
|
||||
if (isset($uri_parts['fragment'])) {
|
||||
if (isset($uri_parts['fragment']) && $uri_parts['fragment'] !== '') {
|
||||
$uri_options += ['fragment' => $uri_parts['fragment']];
|
||||
unset($uri_parts['fragment']);
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ class ProjectInfo {
|
||||
* @param bool $status
|
||||
* Boolean that controls what status (enabled or uninstalled) to process out
|
||||
* of the $list and add to the $projects array.
|
||||
* @param array $additional_whitelist
|
||||
* @param array $additional_elements
|
||||
* (optional) Array of additional elements to be collected from the .info.yml
|
||||
* file. Defaults to array().
|
||||
*/
|
||||
public function processInfoList(array &$projects, array $list, $project_type, $status, array $additional_whitelist = []) {
|
||||
public function processInfoList(array &$projects, array $list, $project_type, $status, array $additional_elements = []) {
|
||||
foreach ($list as $file) {
|
||||
// Just projects with a matching status should be listed.
|
||||
if ($file->status != $status) {
|
||||
@@ -111,7 +111,7 @@ class ProjectInfo {
|
||||
'name' => $project_name,
|
||||
// Only save attributes from the .info.yml file we care about so we do
|
||||
// not bloat our RAM usage needlessly.
|
||||
'info' => $this->filterProjectInfo($file->info, $additional_whitelist),
|
||||
'info' => $this->filterProjectInfo($file->info, $additional_elements),
|
||||
'datestamp' => $file->info['datestamp'],
|
||||
'includes' => [$file->getName() => $file->info['name']],
|
||||
'project_type' => $project_display_type,
|
||||
@@ -165,7 +165,7 @@ class ProjectInfo {
|
||||
* @param array $info
|
||||
* Array of .info.yml file data as returned by
|
||||
* \Drupal\Core\Extension\InfoParser.
|
||||
* @param $additional_whitelist
|
||||
* @param $additional_elements
|
||||
* (optional) Array of additional elements to be collected from the .info.yml
|
||||
* file. Defaults to array().
|
||||
*
|
||||
@@ -174,8 +174,8 @@ class ProjectInfo {
|
||||
*
|
||||
* @see \Drupal\Core\Utility\ProjectInfo::processInfoList()
|
||||
*/
|
||||
public function filterProjectInfo($info, $additional_whitelist = []) {
|
||||
$whitelist = [
|
||||
public function filterProjectInfo($info, $additional_elements = []) {
|
||||
$elements = [
|
||||
'_info_file_ctime',
|
||||
'datestamp',
|
||||
'major',
|
||||
@@ -185,8 +185,8 @@ class ProjectInfo {
|
||||
'project status url',
|
||||
'version',
|
||||
];
|
||||
$whitelist = array_merge($whitelist, $additional_whitelist);
|
||||
return array_intersect_key($info, array_combine($whitelist, $whitelist));
|
||||
$elements = array_merge($elements, $additional_elements);
|
||||
return array_intersect_key($info, array_combine($elements, $elements));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -559,6 +559,7 @@
|
||||
}
|
||||
},
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
type: 'POST',
|
||||
};
|
||||
|
||||
|
||||
@@ -243,6 +243,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
|
||||
},
|
||||
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
type: 'POST'
|
||||
};
|
||||
|
||||
|
||||
@@ -281,6 +281,7 @@
|
||||
},
|
||||
ajax: {
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -156,7 +156,8 @@
|
||||
isComposing: false
|
||||
},
|
||||
ajax: {
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
jsonp: false
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -197,11 +197,8 @@ abstract class AggregatorTestBase extends BrowserTestBase {
|
||||
$this->clickLink('Update items');
|
||||
|
||||
// Ensure we have the right number of items.
|
||||
$iids = \Drupal::entityQuery('aggregator_item')->condition('fid', $feed->id())->execute();
|
||||
$feed->items = [];
|
||||
foreach ($iids as $iid) {
|
||||
$feed->items[] = $iid;
|
||||
}
|
||||
$item_ids = \Drupal::entityQuery('aggregator_item')->condition('fid', $feed->id())->execute();
|
||||
$feed->items = array_values($item_ids);
|
||||
|
||||
if ($expected_count !== NULL) {
|
||||
$feed->item_count = count($feed->items);
|
||||
|
||||
@@ -64,16 +64,16 @@ class FeedParserTest extends AggregatorTestBase {
|
||||
$this->assertText('Atom-Powered Robots Run Amok');
|
||||
$this->assertLinkByHref('http://example.org/2003/12/13/atom03');
|
||||
$this->assertText('Some text.');
|
||||
$iids = \Drupal::entityQuery('aggregator_item')->condition('link', 'http://example.org/2003/12/13/atom03')->execute();
|
||||
$item = Item::load(array_values($iids)[0]);
|
||||
$item_ids = \Drupal::entityQuery('aggregator_item')->condition('link', 'http://example.org/2003/12/13/atom03')->execute();
|
||||
$item = Item::load(array_values($item_ids)[0]);
|
||||
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', $item->getGuid(), 'Atom entry id element is parsed correctly.');
|
||||
|
||||
// Check for second feed entry.
|
||||
$this->assertText('We tried to stop them, but we failed.');
|
||||
$this->assertLinkByHref('http://example.org/2003/12/14/atom03');
|
||||
$this->assertText('Some other text.');
|
||||
$iids = \Drupal::entityQuery('aggregator_item')->condition('link', 'http://example.org/2003/12/14/atom03')->execute();
|
||||
$item = Item::load(array_values($iids)[0]);
|
||||
$item_ids = \Drupal::entityQuery('aggregator_item')->condition('link', 'http://example.org/2003/12/14/atom03')->execute();
|
||||
$item = Item::load(array_values($item_ids)[0]);
|
||||
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-bbbb-80da344efa6a', $item->getGuid(), 'Atom entry id element is parsed correctly.');
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ class UpdateFeedItemTest extends AggregatorTestBase {
|
||||
$feed = Feed::load(array_values($fids)[0]);
|
||||
|
||||
$feed->refreshItems();
|
||||
$iids = \Drupal::entityQuery('aggregator_item')->condition('fid', $feed->id())->execute();
|
||||
$before = Item::load(array_values($iids)[0])->getPostedTime();
|
||||
$item_ids = \Drupal::entityQuery('aggregator_item')->condition('fid', $feed->id())->execute();
|
||||
$before = Item::load(array_values($item_ids)[0])->getPostedTime();
|
||||
|
||||
// Sleep for 3 second.
|
||||
sleep(3);
|
||||
@@ -67,7 +67,7 @@ class UpdateFeedItemTest extends AggregatorTestBase {
|
||||
->save();
|
||||
$feed->refreshItems();
|
||||
|
||||
$after = Item::load(array_values($iids)[0])->getPostedTime();
|
||||
$after = Item::load(array_values($item_ids)[0])->getPostedTime();
|
||||
$this->assertTrue($before === $after, new FormattableMarkup('Publish timestamp of feed item was not updated (@before === @after)', ['@before' => $before, '@after' => $after]));
|
||||
|
||||
// Make sure updating items works even after uninstalling a module
|
||||
|
||||
@@ -39,7 +39,7 @@ class IpAddressBlockingTest extends BrowserTestBase {
|
||||
$edit = [];
|
||||
$edit['ip'] = '1.2.3.3';
|
||||
$this->drupalPostForm('admin/config/people/ban', $edit, t('Add'));
|
||||
$ip = $connection->query("SELECT iid from {ban_ip} WHERE ip = :ip", [':ip' => $edit['ip']])->fetchField();
|
||||
$ip = $connection->select('ban_ip', 'bi')->fields('bi', ['iid'])->condition('ip', $edit['ip'])->execute()->fetchField();
|
||||
$this->assertNotEmpty($ip, 'IP address found in database.');
|
||||
$this->assertRaw(t('The IP address %ip has been banned.', ['%ip' => $edit['ip']]), 'IP address was banned.');
|
||||
|
||||
@@ -70,7 +70,7 @@ class IpAddressBlockingTest extends BrowserTestBase {
|
||||
// Pass an IP address as a URL parameter and submit it.
|
||||
$submit_ip = '1.2.3.4';
|
||||
$this->drupalPostForm('admin/config/people/ban/' . $submit_ip, [], t('Add'));
|
||||
$ip = $connection->query("SELECT iid from {ban_ip} WHERE ip = :ip", [':ip' => $submit_ip])->fetchField();
|
||||
$ip = $connection->select('ban_ip', 'bi')->fields('bi', ['iid'])->condition('ip', $submit_ip)->execute()->fetchField();
|
||||
$this->assertNotEmpty($ip, 'IP address found in database');
|
||||
$this->assertRaw(t('The IP address %ip has been banned.', ['%ip' => $submit_ip]), 'IP address was banned.');
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ class BigPipeStrategy implements PlaceholderStrategyInterface {
|
||||
'library' => [
|
||||
'big_pipe/big_pipe',
|
||||
],
|
||||
// Inform BigPipe' JavaScript known BigPipe placeholder IDs (a whitelist).
|
||||
// Inform BigPipe' JavaScript known BigPipe placeholder IDs.
|
||||
'drupalSettings' => [
|
||||
'bigPipePlaceholderIds' => [$big_pipe_placeholder_id => TRUE],
|
||||
],
|
||||
|
||||
@@ -153,7 +153,7 @@ class BigPipeTest extends BrowserTestBase {
|
||||
$this->assertBigPipeNoJsCookieExists(FALSE);
|
||||
|
||||
$connection = Database::getConnection();
|
||||
$log_count = $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
|
||||
$log_count = $connection->select('watchdog')->countQuery()->execute()->fetchField();
|
||||
|
||||
// By not calling performMetaRefresh() here, we simulate JavaScript being
|
||||
// enabled, because as far as the BigPipe module is concerned, JavaScript is
|
||||
@@ -186,15 +186,16 @@ class BigPipeTest extends BrowserTestBase {
|
||||
|
||||
$this->assertRaw('</body>', 'Closing body tag present.');
|
||||
|
||||
$this->pass('Verifying BigPipe assets are present…', 'Debug');
|
||||
// Verifying BigPipe assets are present.
|
||||
$this->assertFalse(empty($this->getDrupalSettings()), 'drupalSettings present.');
|
||||
$this->assertContains('big_pipe/big_pipe', explode(',', $this->getDrupalSettings()['ajaxPageState']['libraries']), 'BigPipe asset library is present.');
|
||||
|
||||
// Verify that the two expected exceptions are logged as errors.
|
||||
$this->assertEqual($log_count + 2, $connection->query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), 'Two new watchdog entries.');
|
||||
// Using the method queryRange() allows contrib database drivers the ability
|
||||
// to insert their own limit and offset functionality.
|
||||
$records = $connection->queryRange('SELECT * FROM {watchdog} ORDER BY wid DESC', 0, 2)->fetchAll();
|
||||
$this->assertEqual($log_count + 2, (int) $connection->select('watchdog')->countQuery()->execute()->fetchField(), 'Two new watchdog entries.');
|
||||
// Using dynamic select queries with the method range() allows contrib
|
||||
// database drivers the ability to insert their own limit and offset
|
||||
// functionality.
|
||||
$records = $connection->select('watchdog', 'w')->fields('w')->orderBy('wid', 'DESC')->range(0, 2)->execute()->fetchAll();
|
||||
$this->assertEqual(RfcLogLevel::ERROR, $records[0]->severity);
|
||||
$this->assertStringContainsString('Oh noes!', (string) unserialize($records[0]->variables)['@message']);
|
||||
$this->assertEqual(RfcLogLevel::ERROR, $records[1]->severity);
|
||||
@@ -205,7 +206,8 @@ class BigPipeTest extends BrowserTestBase {
|
||||
$this->drupalGet(Url::fromUri('base:non-existing-path'));
|
||||
|
||||
// Simulate development.
|
||||
$this->pass('Verifying BigPipe provides useful error output when an error occurs while rendering a placeholder if verbose error logging is enabled.', 'Debug');
|
||||
// Verifying BigPipe provides useful error output when an error occurs
|
||||
// while rendering a placeholder if verbose error logging is enabled.
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test'));
|
||||
// The 'edge_case__html_exception' case throws an exception.
|
||||
@@ -259,13 +261,13 @@ class BigPipeTest extends BrowserTestBase {
|
||||
$cases['exception__embedded_response']->bigPipePlaceholderId => NULL,
|
||||
]);
|
||||
|
||||
$this->pass('Verifying there are no BigPipe placeholders & replacements…', 'Debug');
|
||||
// Verifying there are no BigPipe placeholders & replacements.
|
||||
$this->assertEqual('<none>', $this->drupalGetHeader('BigPipe-Test-Placeholders'));
|
||||
$this->pass('Verifying BigPipe start/stop signals are absent…', 'Debug');
|
||||
// Verifying BigPipe start/stop signals are absent.
|
||||
$this->assertNoRaw(BigPipe::START_SIGNAL, 'BigPipe start signal absent.');
|
||||
$this->assertNoRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal absent.');
|
||||
|
||||
$this->pass('Verifying BigPipe assets are absent…', 'Debug');
|
||||
// Verifying BigPipe assets are absent.
|
||||
$this->assertTrue(!isset($this->getDrupalSettings()['bigPipePlaceholderIds']) && empty($this->getDrupalSettings()['ajaxPageState']), 'BigPipe drupalSettings and BigPipe asset library absent.');
|
||||
$this->assertRaw('</body>', 'Closing body tag present.');
|
||||
|
||||
@@ -274,7 +276,8 @@ class BigPipeTest extends BrowserTestBase {
|
||||
$this->drupalGet(Url::fromUri('base:non-existing-path'));
|
||||
|
||||
// Simulate development.
|
||||
$this->pass('Verifying BigPipe provides useful error output when an error occurs while rendering a placeholder if verbose error logging is enabled.', 'Debug');
|
||||
// Verifying BigPipe provides useful error output when an error occurs
|
||||
// while rendering a placeholder if verbose error logging is enabled.
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
|
||||
$this->drupalGet(Url::fromRoute('big_pipe_test'));
|
||||
// The 'edge_case__html_exception' case throws an exception.
|
||||
@@ -322,7 +325,6 @@ class BigPipeTest extends BrowserTestBase {
|
||||
}
|
||||
|
||||
protected function assertBigPipeResponseHeadersPresent() {
|
||||
$this->pass('Verifying BigPipe response headers…', 'Debug');
|
||||
// Check that Cache-Control header set to "private".
|
||||
$this->assertSession()->responseHeaderContains('Cache-Control', 'private');
|
||||
$this->assertEqual('no-store, content="BigPipe/1.0"', $this->drupalGetHeader('Surrogate-Control'));
|
||||
@@ -337,10 +339,10 @@ class BigPipeTest extends BrowserTestBase {
|
||||
* markup.
|
||||
*/
|
||||
protected function assertBigPipeNoJsPlaceholders(array $expected_big_pipe_nojs_placeholders) {
|
||||
$this->pass('Verifying BigPipe no-JS placeholders & replacements…', 'Debug');
|
||||
$this->assertSetsEqual(array_keys($expected_big_pipe_nojs_placeholders), array_map('rawurldecode', explode(' ', $this->drupalGetHeader('BigPipe-Test-No-Js-Placeholders'))));
|
||||
foreach ($expected_big_pipe_nojs_placeholders as $big_pipe_nojs_placeholder => $expected_replacement) {
|
||||
$this->pass('Checking whether the replacement for the BigPipe no-JS placeholder "' . $big_pipe_nojs_placeholder . '" is present:');
|
||||
// Checking whether the replacement for the BigPipe no-JS placeholder
|
||||
// $big_pipe_nojs_placeholder is present.
|
||||
$this->assertNoRaw($big_pipe_nojs_placeholder);
|
||||
if ($expected_replacement !== NULL) {
|
||||
$this->assertRaw($expected_replacement);
|
||||
@@ -358,12 +360,10 @@ class BigPipeTest extends BrowserTestBase {
|
||||
* defined in the order that they are expected to be rendered & streamed.
|
||||
*/
|
||||
protected function assertBigPipePlaceholders(array $expected_big_pipe_placeholders, array $expected_big_pipe_placeholder_stream_order) {
|
||||
$this->pass('Verifying BigPipe placeholders & replacements…', 'Debug');
|
||||
$this->assertSetsEqual(array_keys($expected_big_pipe_placeholders), explode(' ', $this->drupalGetHeader('BigPipe-Test-Placeholders')));
|
||||
$placeholder_positions = [];
|
||||
$placeholder_replacement_positions = [];
|
||||
foreach ($expected_big_pipe_placeholders as $big_pipe_placeholder_id => $expected_ajax_response) {
|
||||
$this->pass('BigPipe placeholder: ' . $big_pipe_placeholder_id, 'Debug');
|
||||
// Verify expected placeholder.
|
||||
$expected_placeholder_html = '<span data-big-pipe-placeholder-id="' . $big_pipe_placeholder_id . '"></span>';
|
||||
$this->assertRaw($expected_placeholder_html, 'BigPipe placeholder for placeholder ID "' . $big_pipe_placeholder_id . '" found.');
|
||||
@@ -396,14 +396,15 @@ class BigPipeTest extends BrowserTestBase {
|
||||
$this->assertSetsEqual(array_keys($expected_big_pipe_placeholders_with_replacements), array_values($placeholder_replacement_positions));
|
||||
$this->assertEqual(count($expected_big_pipe_placeholders_with_replacements), preg_match_all('/' . preg_quote('<script type="application/vnd.drupal-ajax" data-big-pipe-replacement-for-placeholder-with-id="', '/') . '/', $this->getSession()->getPage()->getContent()));
|
||||
|
||||
$this->pass('Verifying BigPipe start/stop signals…', 'Debug');
|
||||
// Verifying BigPipe start/stop signals.
|
||||
$this->assertRaw(BigPipe::START_SIGNAL, 'BigPipe start signal present.');
|
||||
$this->assertRaw(BigPipe::STOP_SIGNAL, 'BigPipe stop signal present.');
|
||||
$start_signal_position = strpos($this->getSession()->getPage()->getContent(), BigPipe::START_SIGNAL);
|
||||
$stop_signal_position = strpos($this->getSession()->getPage()->getContent(), BigPipe::STOP_SIGNAL);
|
||||
$this->assertTrue($start_signal_position < $stop_signal_position, 'BigPipe start signal appears before stop signal.');
|
||||
|
||||
$this->pass('Verifying BigPipe placeholder replacements and start/stop signals were streamed in the correct order…', 'Debug');
|
||||
// Verifying BigPipe placeholder replacements and start/stop signals were
|
||||
// streamed in the correct order.
|
||||
$expected_stream_order = array_keys($expected_big_pipe_placeholders_with_replacements);
|
||||
array_unshift($expected_stream_order, BigPipe::START_SIGNAL);
|
||||
array_push($expected_stream_order, BigPipe::STOP_SIGNAL);
|
||||
|
||||
@@ -292,7 +292,6 @@ class BlockViewBuilderTest extends KernelTestBase {
|
||||
|
||||
// Check that the expected cacheability metadata is present in:
|
||||
// - the built render array;
|
||||
$this->pass('Built render array');
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertIdentical($expected_keys, $build['#cache']['keys']);
|
||||
$this->assertIdentical($expected_contexts, $build['#cache']['contexts']);
|
||||
@@ -300,10 +299,8 @@ class BlockViewBuilderTest extends KernelTestBase {
|
||||
$this->assertIdentical($expected_max_age, $build['#cache']['max-age']);
|
||||
$this->assertFalse(isset($build['#create_placeholder']));
|
||||
// - the rendered render array;
|
||||
$this->pass('Rendered render array');
|
||||
$this->renderer->renderRoot($build);
|
||||
// - the render cache item.
|
||||
$this->pass('Render cache item');
|
||||
$final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
|
||||
$cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys());
|
||||
$cache_item = $this->container->get('cache.render')->get($cid);
|
||||
|
||||
+6
-6
@@ -37,7 +37,7 @@ class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformNoData() {
|
||||
$transformed_value = $this->plugin->transform([0, '', []], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$transformed_value = $this->plugin->transform([0, '', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertEmpty($transformed_value);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformSinglePageWithFront() {
|
||||
$visibility = $this->plugin->transform([0, '<front>', []], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$visibility = $this->plugin->transform([0, '<front>', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame('request_path', $visibility['request_path']['id']);
|
||||
$this->assertTrue($visibility['request_path']['negate']);
|
||||
$this->assertSame('<front>', $visibility['request_path']['pages']);
|
||||
@@ -55,7 +55,7 @@ class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformMultiplePagesWithFront() {
|
||||
$visibility = $this->plugin->transform([1, "foo\n/bar\rbaz\r\n<front>", []], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$visibility = $this->plugin->transform([1, "foo\n/bar\rbaz\r\n<front>", []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame('request_path', $visibility['request_path']['id']);
|
||||
$this->assertFalse($visibility['request_path']['negate']);
|
||||
$this->assertSame("/foo\n/bar\n/baz\n<front>", $visibility['request_path']['pages']);
|
||||
@@ -66,7 +66,7 @@ class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
*/
|
||||
public function testTransformPhpEnabled() {
|
||||
$this->moduleHandler->moduleExists('php')->willReturn(TRUE);
|
||||
$visibility = $this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$visibility = $this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame('php', $visibility['php']['id']);
|
||||
$this->assertFalse($visibility['php']['negate']);
|
||||
$this->assertSame('<?php', $visibility['php']['php']);
|
||||
@@ -77,7 +77,7 @@ class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
*/
|
||||
public function testTransformPhpDisabled() {
|
||||
$this->moduleHandler->moduleExists('php')->willReturn(FALSE);
|
||||
$transformed_value = $this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$transformed_value = $this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertEmpty($transformed_value);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
$this->plugin = new BlockVisibility(['skip_php' => TRUE], 'block_visibility_pages', [], $this->moduleHandler->reveal(), $migrate_lookup->reveal());
|
||||
$this->expectException(MigrateSkipRowException::class);
|
||||
$this->expectExceptionMessage("The block with bid '99' from module 'foobar' will have no PHP or request_path visibility configuration.");
|
||||
$this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ class BlockCustomTranslation extends DrupalSqlBase {
|
||||
|
||||
// Add in the property, which is either title or body. Cast the bid to text
|
||||
// so PostgreSQL can make the join.
|
||||
$query->leftJoin(static::I18N_STRING_TABLE, 'i18n', 'i18n.objectid = CAST(b.bid as CHAR(255))');
|
||||
$query->leftJoin(static::I18N_STRING_TABLE, 'i18n', 'i18n.objectid = CAST(b.bid AS CHAR(255))');
|
||||
$query->condition('i18n.type', 'block');
|
||||
|
||||
// Add in the translation for the property.
|
||||
|
||||
@@ -204,7 +204,7 @@ class BlockContentCreationTest extends BlockContentTestBase {
|
||||
$this->fail('Expected exception has not been thrown.');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->pass('Expected exception has been thrown.');
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
+1
-3
@@ -145,12 +145,10 @@ class BlockContentTranslationUITest extends ContentTranslationUITestBase {
|
||||
$entity->addTranslation('it', $values);
|
||||
|
||||
try {
|
||||
$message = 'Blocks can have translations with the same "info" value.';
|
||||
$entity->save();
|
||||
$this->pass($message);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->fail($message);
|
||||
$this->fail('Blocks can have translations with the same "info" value.');
|
||||
}
|
||||
|
||||
// Check that the translate operation link is shown.
|
||||
|
||||
+4
-9
@@ -33,15 +33,10 @@ class MigrateBlockContentStubTest extends MigrateDrupalTestBase {
|
||||
* Tests creation of block content stubs with no block_content_type available.
|
||||
*/
|
||||
public function testStubFailure() {
|
||||
$message = 'Expected MigrateException thrown when no bundles exist.';
|
||||
try {
|
||||
$this->createEntityStub('block_content');
|
||||
$this->fail($message);
|
||||
}
|
||||
catch (MigrateException $e) {
|
||||
$this->pass($message);
|
||||
$this->assertEqual('Stubbing failed, no bundles available for entity type: block_content', $e->getMessage());
|
||||
}
|
||||
// Expected MigrateException thrown when no bundles exist.
|
||||
$this->expectException(MigrateException::class);
|
||||
$this->expectExceptionMessage('Stubbing failed, no bundles available for entity type: block_content');
|
||||
$this->createEntityStub('block_content');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,6 @@ class BookSettingsForm extends ConfigFormBase {
|
||||
'#options' => $types,
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['array_filter'] = ['#type' => 'value', '#value' => TRUE];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
@@ -56,7 +55,7 @@ class BookSettingsForm extends ConfigFormBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$child_type = $form_state->getValue('book_child_type');
|
||||
$child_type = array_filter($form_state->getValue('book_child_type'));
|
||||
if ($form_state->isValueEmpty(['book_allowed_types', $child_type])) {
|
||||
$form_state->setErrorByName('book_child_type', $this->t('The content type for the %add-child link must be one of those selected as an allowed book outline type.', ['%add-child' => $this->t('Add child page')]));
|
||||
}
|
||||
@@ -76,7 +75,7 @@ class BookSettingsForm extends ConfigFormBase {
|
||||
$this->config('book.settings')
|
||||
// Remove unchecked types.
|
||||
->set('allowed_types', $allowed_types)
|
||||
->set('child_type', $form_state->getValue('book_child_type'))
|
||||
->set('child_type', array_filter($form_state->getValue('book_child_type')))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
@@ -95,7 +95,7 @@ trait BookTestTrait {
|
||||
|
||||
// Check outline structure.
|
||||
if ($nodes !== NULL) {
|
||||
$this->assertPattern($this->generateOutlinePattern($nodes), new FormattableMarkup('Node @number outline confirmed.', ['@number' => $number]));
|
||||
$this->assertPattern($this->generateOutlinePattern($nodes));
|
||||
}
|
||||
else {
|
||||
$this->pass(new FormattableMarkup('Node %number does not have outline.', ['%number' => $number]));
|
||||
|
||||
@@ -215,6 +215,11 @@
|
||||
'figcaption',
|
||||
);
|
||||
|
||||
const captionFilter = new CKEDITOR.filter(
|
||||
widgetDefinition.editables.caption.allowedContent,
|
||||
);
|
||||
captionFilter.applyTo(caption);
|
||||
|
||||
// Use Drupal's data-placeholder attribute to insert a CSS-based,
|
||||
// translation-ready placeholder for empty captions. Note that it
|
||||
// also must to be done for new instances (see
|
||||
|
||||
@@ -139,6 +139,9 @@
|
||||
var figure = new CKEDITOR.htmlParser.element('figure');
|
||||
caption = new CKEDITOR.htmlParser.fragment.fromHtml(caption, 'figcaption');
|
||||
|
||||
var captionFilter = new CKEDITOR.filter(widgetDefinition.editables.caption.allowedContent);
|
||||
captionFilter.applyTo(caption);
|
||||
|
||||
caption.attributes['data-placeholder'] = placeholderText;
|
||||
|
||||
element.replaceWith(figure);
|
||||
|
||||
@@ -122,7 +122,7 @@ class CKEditorPluginManager extends DefaultPluginManager {
|
||||
$toolbar_rows = [];
|
||||
$settings = $editor->getSettings();
|
||||
foreach ($settings['toolbar']['rows'] as $row_number => $row) {
|
||||
$toolbar_rows[] = array_reduce($settings['toolbar']['rows'][$row_number], function (&$result, $button_group) {
|
||||
$toolbar_rows[] = array_reduce($settings['toolbar']['rows'][$row_number], function ($result, $button_group) {
|
||||
return array_merge($result, $button_group['items']);
|
||||
}, []);
|
||||
}
|
||||
|
||||
@@ -120,8 +120,9 @@ class ColorTest extends BrowserTestBase {
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$stylesheets = $this->config('color.theme.' . $theme)->get('stylesheets');
|
||||
// Make sure the color stylesheet is included in the content.
|
||||
foreach ($stylesheets as $stylesheet) {
|
||||
$this->assertPattern('|' . file_url_transform_relative(file_create_url($stylesheet)) . '|', 'Make sure the color stylesheet is included in the content. (' . $theme . ')');
|
||||
$this->assertPattern('|' . file_url_transform_relative(file_create_url($stylesheet)) . '|');
|
||||
$stylesheet_content = implode("\n", file($stylesheet));
|
||||
$this->assertStringContainsString('color: #123456', $stylesheet_content, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
|
||||
}
|
||||
|
||||
@@ -694,9 +694,8 @@ function template_preprocess_comment(&$variables) {
|
||||
|
||||
$variables['submitted'] = t('Submitted by @username on @datetime', ['@username' => $variables['author'], '@datetime' => $variables['created']]);
|
||||
|
||||
if ($comment->hasParentComment()) {
|
||||
if ($comment_parent = $comment->getParentComment()) {
|
||||
// Fetch and store the parent comment information for use in templates.
|
||||
$comment_parent = $comment->getParentComment();
|
||||
$account_parent = $comment_parent->getOwner();
|
||||
$variables['parent_comment'] = $comment_parent;
|
||||
$username = [
|
||||
|
||||
@@ -144,9 +144,9 @@ class CommentLazyBuilders implements TrustedCallbackInterface {
|
||||
if (!$is_in_preview) {
|
||||
/** @var \Drupal\comment\CommentInterface $entity */
|
||||
$entity = $this->entityTypeManager->getStorage('comment')->load($comment_entity_id);
|
||||
$commented_entity = $entity->getCommentedEntity();
|
||||
|
||||
$links['comment'] = $this->buildLinks($entity, $commented_entity);
|
||||
if ($commented_entity = $entity->getCommentedEntity()) {
|
||||
$links['comment'] = $this->buildLinks($entity, $commented_entity);
|
||||
}
|
||||
|
||||
// Allow other modules to alter the comment links.
|
||||
$hook_context = [
|
||||
|
||||
@@ -80,9 +80,11 @@ class CommentViewBuilder extends EntityViewBuilder {
|
||||
|
||||
/** @var \Drupal\comment\CommentInterface $entity */
|
||||
// Store a threading field setting to use later in self::buildComponents().
|
||||
$build['#comment_threaded'] = $entity->getCommentedEntity()
|
||||
->getFieldDefinition($entity->getFieldName())
|
||||
->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED;
|
||||
$commented_entity = $entity->getCommentedEntity();
|
||||
$build['#comment_threaded'] =
|
||||
is_null($commented_entity)
|
||||
|| $commented_entity->getFieldDefinition($entity->getFieldName())
|
||||
->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED;
|
||||
// If threading is enabled, don't render cache individual comments, but do
|
||||
// keep the cacheability metadata, so it can bubble up.
|
||||
if ($build['#comment_threaded']) {
|
||||
@@ -140,10 +142,12 @@ class CommentViewBuilder extends EntityViewBuilder {
|
||||
|
||||
// Commented entities already loaded after self::getBuildDefaults().
|
||||
$commented_entity = $entity->getCommentedEntity();
|
||||
// Set defaults if the commented_entity does not exist.
|
||||
$bundle = $commented_entity ? $commented_entity->bundle() : '';
|
||||
$is_node = $commented_entity ? $commented_entity->getEntityTypeId() === 'node' : NULL;
|
||||
|
||||
$build[$id]['#entity'] = $entity;
|
||||
$build[$id]['#theme'] = 'comment__' . $entity->getFieldName() . '__' . $commented_entity->bundle();
|
||||
|
||||
$build[$id]['#theme'] = 'comment__' . $entity->getFieldName() . '__' . $bundle;
|
||||
$display = $displays[$entity->bundle()];
|
||||
if ($display->getComponent('links')) {
|
||||
$build[$id]['links'] = [
|
||||
@@ -164,7 +168,7 @@ class CommentViewBuilder extends EntityViewBuilder {
|
||||
$build[$id]['#attached'] = [];
|
||||
}
|
||||
$build[$id]['#attached']['library'][] = 'comment/drupal.comment-by-viewer';
|
||||
if ($attach_history && $commented_entity->getEntityTypeId() === 'node') {
|
||||
if ($attach_history && $is_node) {
|
||||
$build[$id]['#attached']['library'][] = 'comment/drupal.comment-new-indicator';
|
||||
|
||||
// Embed the metadata for the comment "new" indicators on this node.
|
||||
|
||||
@@ -250,7 +250,7 @@ class CommentViewsData extends EntityViewsData {
|
||||
// the same two tables is not supported.
|
||||
if (\Drupal::service('comment.manager')->getFields($type)) {
|
||||
$data['comment_entity_statistics']['table']['join'][$entity_type->getDataTable() ?: $entity_type->getBaseTable()] = [
|
||||
'type' => 'INNER',
|
||||
'type' => 'LEFT',
|
||||
'left_field' => $entity_type->getKey('id'),
|
||||
'field' => 'entity_id',
|
||||
'extra' => [
|
||||
|
||||
@@ -404,7 +404,8 @@ class Comment extends ContentEntityBase implements CommentInterface {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuthorName() {
|
||||
if ($this->get('uid')->target_id) {
|
||||
// If their is a valid user id and the user entity exists return the label.
|
||||
if ($this->get('uid')->target_id && $this->get('uid')->entity) {
|
||||
return $this->get('uid')->entity->label();
|
||||
}
|
||||
return $this->get('name')->value ?: \Drupal::config('user.settings')->get('anonymous');
|
||||
@@ -510,8 +511,8 @@ class Comment extends ContentEntityBase implements CommentInterface {
|
||||
*/
|
||||
public static function preCreate(EntityStorageInterface $storage, array &$values) {
|
||||
if (empty($values['comment_type']) && !empty($values['field_name']) && !empty($values['entity_type'])) {
|
||||
$field_storage = FieldStorageConfig::loadByName($values['entity_type'], $values['field_name']);
|
||||
$values['comment_type'] = $field_storage->getSetting('comment_type');
|
||||
$fields = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($values['entity_type']);
|
||||
$values['comment_type'] = $fields[$values['field_name']]->getSetting('comment_type');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ class NodeNewComments extends NumericField {
|
||||
}
|
||||
|
||||
if ($nids) {
|
||||
$result = $this->database->query("SELECT n.nid, COUNT(c.cid) as num_comments FROM {node} n INNER JOIN {comment_field_data} c ON n.nid = c.entity_id AND c.entity_type = 'node' AND c.default_langcode = 1
|
||||
$result = $this->database->query("SELECT n.nid, COUNT(c.cid) AS num_comments FROM {node} n INNER JOIN {comment_field_data} c ON n.nid = c.entity_id AND c.entity_type = 'node' AND c.default_langcode = 1
|
||||
LEFT JOIN {history} h ON h.nid = n.nid AND h.uid = :h_uid WHERE n.nid IN ( :nids[] )
|
||||
AND c.changed > GREATEST(COALESCE(h.timestamp, :timestamp1), :timestamp2) AND c.status = :status GROUP BY n.nid", [
|
||||
':status' => CommentInterface::PUBLISHED,
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
name: 'Comment base field test'
|
||||
type: module
|
||||
description: 'Test comment as a base field'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- drupal:comment
|
||||
- drupal:entity_test
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
langcode: en
|
||||
status: true
|
||||
id: test_comment_type
|
||||
label: Test comment type
|
||||
target_entity_type_id: comment_test_base_field
|
||||
description: 'Test comment type.'
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\comment_base_field_test\Entity;
|
||||
|
||||
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
|
||||
/**
|
||||
* Defines a test entity class for comment as a base field.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "comment_test_base_field",
|
||||
* label = @Translation("Test comment - base field"),
|
||||
* base_table = "comment_test_base_field",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "uuid" = "uuid",
|
||||
* "bundle" = "type"
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class CommentTestBaseField extends EntityTest {
|
||||
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
$fields['test_comment'] = BaseFieldDefinition::create('comment')
|
||||
->setLabel(t('A comment field'))
|
||||
->setSetting('comment_type', 'test_comment_type')
|
||||
->setDefaultValue([
|
||||
'status' => CommentItemInterface::OPEN,
|
||||
]);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_comment_count
|
||||
label: 'test comment count'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: ‹‹
|
||||
next: ››
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
settings:
|
||||
link_to_entity: true
|
||||
plugin_id: field
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
comment_count:
|
||||
id: comment_count
|
||||
table: comment_entity_statistics
|
||||
field: comment_count
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
set_precision: false
|
||||
precision: 0
|
||||
decimal: .
|
||||
separator: ''
|
||||
format_plural: false
|
||||
format_plural_string: !!binary MQNAY291bnQ=
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
plugin_id: numeric
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
operator_limit_selection: false
|
||||
operator_list: { }
|
||||
group: 1
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
entity_type: node
|
||||
entity_field: created
|
||||
plugin_id: date
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test-comment-count
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
@@ -188,7 +188,8 @@ class CommentAnonymousTest extends CommentTestBase {
|
||||
'skip comment approval' => FALSE,
|
||||
]);
|
||||
$this->drupalGet('node/' . $this->node->id());
|
||||
$this->assertPattern('@<h2[^>]*>Comments</h2>@', 'Comments were displayed.');
|
||||
// Verify that the comment field title is displayed.
|
||||
$this->assertPattern('@<h2[^>]*>Comments</h2>@');
|
||||
$this->assertSession()->linkExists('Log in', 1, 'Link to login was found.');
|
||||
$this->assertSession()->linkExists('register', 1, 'Link to register was found.');
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class CommentInterfaceTest extends CommentTestBase {
|
||||
|
||||
// Test the comment field title is displayed when there's comments.
|
||||
$this->drupalGet($this->node->toUrl());
|
||||
$this->assertPattern('@<h2[^>]*>Comments</h2>@', 'Comments title is displayed.');
|
||||
$this->assertPattern('@<h2[^>]*>Comments</h2>@');
|
||||
|
||||
// Set comments to have subject and preview to required.
|
||||
$this->drupalLogout();
|
||||
|
||||
@@ -370,7 +370,8 @@ class CommentNonNodeTest extends BrowserTestBase {
|
||||
'skip comment approval' => FALSE,
|
||||
]);
|
||||
$this->drupalGet('entity_test/' . $this->entity->id());
|
||||
$this->assertPattern('@<h2[^>]*>Comments</h2>@', 'Comments were displayed.');
|
||||
// Verify that the comment field title is displayed.
|
||||
$this->assertPattern('@<h2[^>]*>Comments</h2>@');
|
||||
$this->assertSession()->linkExists('Log in', 0, 'Link to login was found.');
|
||||
$this->assertSession()->linkExists('register', 0, 'Link to register was found.');
|
||||
$this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
|
||||
|
||||
@@ -429,7 +429,6 @@ class CommentPagerTest extends CommentTestBase {
|
||||
$urls = $this->xpath($xpath, $arguments);
|
||||
if (isset($urls[$index])) {
|
||||
$url_target = $this->getAbsoluteUrl($urls[$index]->getAttribute('href'));
|
||||
$this->pass(new FormattableMarkup('Clicked link %label (@url_target) from @url_before', ['%label' => $xpath, '@url_target' => $url_target, '@url_before' => $url_before]), 'Browser');
|
||||
return $this->drupalGet($url_target);
|
||||
}
|
||||
$this->fail(new FormattableMarkup('Link %label does not exist on @url_before', ['%label' => $xpath, '@url_before' => $url_before]), 'Browser');
|
||||
|
||||
@@ -45,7 +45,8 @@ class CommentTitleTest extends CommentTestBase {
|
||||
$regex = '/<article(.*?)id="comment-' . $comment->id() . '"(.*?)';
|
||||
$regex .= $comment->comment_body->value . '(.*?)';
|
||||
$regex .= '/s';
|
||||
$this->assertPattern($regex, 'Comment is created successfully');
|
||||
// Verify that the comment is created successfully.
|
||||
$this->assertPattern($regex);
|
||||
// Tests that markup is not generated for the comment without header.
|
||||
$this->assertSession()->responseNotMatches('|<h3[^>]*></h3>|', 'Comment title H3 element not found when title is an empty string.');
|
||||
}
|
||||
@@ -76,7 +77,7 @@ class CommentTitleTest extends CommentTestBase {
|
||||
// Confirm that the comment was created.
|
||||
$this->assertTrue($this->commentExists($comment1), 'Comment #1. Comment found.');
|
||||
// Tests that markup is created for comment with heading.
|
||||
$this->assertPattern('|<h3[^>]*><a[^>]*>' . $subject_text . '</a></h3>|', 'Comment title is rendered in h3 when title populated.');
|
||||
$this->assertPattern('|<h3[^>]*><a[^>]*>' . $subject_text . '</a></h3>|');
|
||||
// Tests that the comment's title link is the permalink of the comment.
|
||||
$comment_permalink = $this->cssSelect('.permalink');
|
||||
$comment_permalink = $comment_permalink[0]->getAttribute('href');
|
||||
|
||||
@@ -186,7 +186,7 @@ class CommentTypeTest extends CommentTestBase {
|
||||
$this->fail('Exception not thrown.');
|
||||
}
|
||||
catch (\InvalidArgumentException $e) {
|
||||
$this->pass('Exception thrown if attempting to re-use comment-type from another entity type.');
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Delete the comment type.
|
||||
|
||||
@@ -26,7 +26,7 @@ class NodeCommentsTest extends CommentTestBase {
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_new_comments'];
|
||||
public static $testViews = ['test_new_comments', 'test_comment_count'];
|
||||
|
||||
/**
|
||||
* Test the new comments field plugin.
|
||||
@@ -38,4 +38,30 @@ class NodeCommentsTest extends CommentTestBase {
|
||||
$this->assertCount(1, $new_comments, 'Found the number of new comments for a certain node.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the comment count field.
|
||||
*/
|
||||
public function testCommentCount() {
|
||||
$this->drupalGet('test-comment-count');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertCount(2, $this->cssSelect('.views-row'));
|
||||
$comment_count_with_comment = $this->cssSelect(".views-field-comment-count span:contains('1')");
|
||||
$this->assertCount(1, $comment_count_with_comment);
|
||||
$comment_count_without_comment = $this->cssSelect(".views-field-comment-count span:contains('0')");
|
||||
$this->assertCount(1, $comment_count_without_comment);
|
||||
|
||||
// Create a content type with no comment field, and add a node.
|
||||
$this->drupalCreateContentType(['type' => 'no_comment', 'name' => t('No comment page')]);
|
||||
$this->nodeUserPosted = $this->drupalCreateNode(['type' => 'no_comment']);
|
||||
$this->drupalGet('test-comment-count');
|
||||
|
||||
// Test that the node with no comment field is also shown.
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertCount(3, $this->cssSelect('.views-row'));
|
||||
$comment_count_with_comment = $this->cssSelect(".views-field-comment-count span:contains('1')");
|
||||
$this->assertCount(1, $comment_count_with_comment);
|
||||
$comment_count_without_comment = $this->cssSelect(".views-field-comment-count span:contains('0')");
|
||||
$this->assertCount(2, $comment_count_without_comment);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\comment\Kernel;
|
||||
|
||||
use Drupal\comment\CommentInterface;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
|
||||
use Drupal\comment_base_field_test\Entity\CommentTestBaseField;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests that comment as a base field.
|
||||
*
|
||||
* @group comment
|
||||
*/
|
||||
class CommentBaseFieldTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'system',
|
||||
'user',
|
||||
'comment',
|
||||
'comment_base_field_test',
|
||||
];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('comment_test_base_field');
|
||||
$this->installEntitySchema('comment');
|
||||
$this->installSchema('system', ['sequences']);
|
||||
$this->installEntitySchema('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests comment as a base field.
|
||||
*/
|
||||
public function testCommentBaseField() {
|
||||
// Verify entity creation.
|
||||
$entity = CommentTestBaseField::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'test_comment' => CommentItemInterface::OPEN,
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
$comment = Comment::create([
|
||||
'entity_id' => $entity->id(),
|
||||
'entity_type' => 'comment_test_base_field',
|
||||
'field_name' => 'test_comment',
|
||||
'pid' => 0,
|
||||
'uid' => 0,
|
||||
'status' => CommentInterface::PUBLISHED,
|
||||
'subject' => $this->randomMachineName(),
|
||||
'hostname' => '127.0.0.1',
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'comment_body' => [['value' => $this->randomMachineName()]],
|
||||
]);
|
||||
$comment->save();
|
||||
$this->assertEquals('test_comment_type', $comment->bundle());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\comment\Kernel;
|
||||
|
||||
use Drupal\Core\Datetime\Entity\DateFormat;
|
||||
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
|
||||
use Drupal\Tests\EntityViewTrait;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests loading and rendering orphan comments.
|
||||
*
|
||||
* @group comment
|
||||
*/
|
||||
class CommentOrphanTest extends EntityKernelTestBase {
|
||||
|
||||
use EntityViewTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['comment', 'node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('date_format');
|
||||
$this->installEntitySchema('comment');
|
||||
$this->installSchema('comment', ['comment_entity_statistics']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loading/deleting/rendering orphaned comments.
|
||||
*
|
||||
* @dataProvider providerTestOrphan
|
||||
*/
|
||||
public function testOrphan($property) {
|
||||
|
||||
DateFormat::create([
|
||||
'id' => 'fallback',
|
||||
'label' => 'Fallback',
|
||||
'pattern' => 'Y-m-d',
|
||||
])->save();
|
||||
|
||||
$comment_storage = $this->entityTypeManager->getStorage('comment');
|
||||
$node_storage = $this->entityTypeManager->getStorage('node');
|
||||
|
||||
// Create a page node type.
|
||||
$this->entityTypeManager->getStorage('node_type')->create([
|
||||
'type' => 'page',
|
||||
'name' => 'page',
|
||||
])->save();
|
||||
|
||||
$node = $node_storage->create([
|
||||
'type' => 'page',
|
||||
'title' => 'test',
|
||||
]);
|
||||
$node->save();
|
||||
|
||||
// Create comment field.
|
||||
$this->entityTypeManager->getStorage('field_storage_config')->create([
|
||||
'type' => 'text_long',
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment',
|
||||
])->save();
|
||||
|
||||
// Add comment field to page content.
|
||||
$this->entityTypeManager->getStorage('field_config')->create([
|
||||
'field_storage' => FieldStorageConfig::loadByName('node', 'comment'),
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
'label' => 'Comment',
|
||||
])->save();
|
||||
|
||||
// Make two comments
|
||||
$comment1 = $comment_storage->create([
|
||||
'field_name' => 'comment',
|
||||
'comment_body' => 'test',
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'comment_type' => 'default',
|
||||
])->save();
|
||||
|
||||
$comment_storage->create([
|
||||
'field_name' => 'comment',
|
||||
'comment_body' => 'test',
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'comment_type' => 'default',
|
||||
'pid' => $comment1,
|
||||
])->save();
|
||||
|
||||
// Render the comments.
|
||||
$renderer = \Drupal::service('renderer');
|
||||
$comments = $comment_storage->loadMultiple();
|
||||
foreach ($comments as $comment) {
|
||||
$built = $this->buildEntityView($comment, 'full', NULL);
|
||||
$renderer->renderPlain($built);
|
||||
}
|
||||
|
||||
// Make comment 2 an orphan by setting the property to an invalid value.
|
||||
\Drupal::database()->update('comment_field_data')
|
||||
->fields([$property => 10])
|
||||
->condition('cid', 2)
|
||||
->execute();
|
||||
$comment_storage->resetCache();
|
||||
$node_storage->resetCache();
|
||||
|
||||
// Render the comments with an orphan comment.
|
||||
$comments = $comment_storage->loadMultiple();
|
||||
foreach ($comments as $comment) {
|
||||
$built = $this->buildEntityView($comment, 'full', NULL);
|
||||
$renderer->renderPlain($built);
|
||||
}
|
||||
|
||||
$node = $node_storage->load($node->id());
|
||||
$built = $this->buildEntityView($node, 'full', NULL);
|
||||
$renderer->renderPlain($built);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for testOrphan.
|
||||
*/
|
||||
public function providerTestOrphan() {
|
||||
return [
|
||||
['entity_id'],
|
||||
['uid'],
|
||||
['pid'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,28 +40,23 @@ class CommentStringIdEntitiesTest extends KernelTestBase {
|
||||
* Tests that comment fields cannot be added entities with non-integer IDs.
|
||||
*/
|
||||
public function testCommentFieldNonStringId() {
|
||||
try {
|
||||
$bundle = CommentType::create([
|
||||
'id' => 'foo',
|
||||
'label' => 'foo',
|
||||
'description' => '',
|
||||
'target_entity_type_id' => 'entity_test_string_id',
|
||||
]);
|
||||
$bundle->save();
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'foo',
|
||||
'entity_type' => 'entity_test_string_id',
|
||||
'settings' => [
|
||||
'comment_type' => 'entity_test_string_id',
|
||||
],
|
||||
'type' => 'comment',
|
||||
]);
|
||||
$field_storage->save();
|
||||
$this->fail('Did not throw an exception as expected.');
|
||||
}
|
||||
catch (\UnexpectedValueException $e) {
|
||||
$this->pass('Exception thrown when trying to create comment field on Entity Type with string ID.');
|
||||
}
|
||||
$this->expectException(\UnexpectedValueException::class);
|
||||
$bundle = CommentType::create([
|
||||
'id' => 'foo',
|
||||
'label' => 'foo',
|
||||
'description' => '',
|
||||
'target_entity_type_id' => 'entity_test_string_id',
|
||||
]);
|
||||
$bundle->save();
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'foo',
|
||||
'entity_type' => 'entity_test_string_id',
|
||||
'settings' => [
|
||||
'comment_type' => 'entity_test_string_id',
|
||||
],
|
||||
'type' => 'comment',
|
||||
]);
|
||||
$field_storage->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -77,6 +77,7 @@ class MigrateCommentFieldInstanceTest extends MigrateDrupal7TestBase {
|
||||
$this->assertEntity('book', 'comment_node_book', 2, 1, 50, 0, TRUE, 1);
|
||||
$this->assertEntity('forum', 'comment_forum', 2, 1, 50, 0, TRUE, 1);
|
||||
$this->assertEntity('test_content_type', 'comment_node_test_content_type', 2, 1, 30, 0, TRUE, 1);
|
||||
$this->assertEntity('et', 'comment_node_et', 2, 1, 50, 0, FALSE, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class MigrateCommentFieldTest extends MigrateDrupal7TestBase {
|
||||
$this->assertEntity('comment_node_book');
|
||||
$this->assertEntity('comment_forum');
|
||||
$this->assertEntity('comment_node_test_content_type');
|
||||
$this->assertEntity('comment_node_et');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ class ConfigSingleImportForm extends ConfirmFormBase {
|
||||
}
|
||||
|
||||
// Validate for config entities.
|
||||
if ($form_state->getValue('config_type') !== 'system.simple') {
|
||||
if ($form_state->getValue('config_type') && $form_state->getValue('config_type') !== 'system.simple') {
|
||||
$definition = $this->entityTypeManager->getDefinition($form_state->getValue('config_type'));
|
||||
$id_key = $definition->getKey('id');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
function config_schema_test_config_schema_info_alter(&$definitions) {
|
||||
if (\Drupal::state()->get('config_schema_test_exception_add')) {
|
||||
$definitions['config_schema_test.hook_added_defintion'] = $definitions['config_schema_test.hook'];
|
||||
$definitions['config_schema_test.hook_added_definition'] = $definitions['config_schema_test.hook'];
|
||||
}
|
||||
if (\Drupal::state()->get('config_schema_test_exception_remove')) {
|
||||
unset($definitions['config_schema_test.hook']);
|
||||
|
||||
@@ -69,7 +69,7 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
$this->fail('EntityMalformedException was thrown.');
|
||||
}
|
||||
catch (EntityMalformedException $e) {
|
||||
$this->pass('EntityMalformedException was thrown.');
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Verify that an empty entity cannot be saved.
|
||||
@@ -78,7 +78,7 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
$this->fail('EntityMalformedException was thrown.');
|
||||
}
|
||||
catch (EntityMalformedException $e) {
|
||||
$this->pass('EntityMalformedException was thrown.');
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Verify that an entity with an empty ID string is considered empty, too.
|
||||
@@ -91,7 +91,7 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
$this->fail('EntityMalformedException was thrown.');
|
||||
}
|
||||
catch (EntityMalformedException $e) {
|
||||
$this->pass('EntityMalformedException was thrown.');
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Verify properties on a newly created entity.
|
||||
@@ -116,7 +116,6 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
// Verify that the entity can be saved.
|
||||
try {
|
||||
$status = $config_test->save();
|
||||
$this->pass('EntityMalformedException was not thrown.');
|
||||
}
|
||||
catch (EntityMalformedException $e) {
|
||||
$this->fail('EntityMalformedException was not thrown.');
|
||||
@@ -151,9 +150,6 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
]);
|
||||
try {
|
||||
$id_length_config_test->save();
|
||||
$this->pass(new FormattableMarkup("config_test entity with ID length @length was saved.", [
|
||||
'@length' => strlen($id_length_config_test->id()),
|
||||
]));
|
||||
}
|
||||
catch (ConfigEntityIdLengthException $e) {
|
||||
$this->fail($e->getMessage());
|
||||
@@ -165,9 +161,6 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
]);
|
||||
try {
|
||||
$id_length_config_test->save();
|
||||
$this->pass(new FormattableMarkup("config_test entity with ID length @length was saved.", [
|
||||
'@length' => strlen($id_length_config_test->id()),
|
||||
]));
|
||||
}
|
||||
catch (ConfigEntityIdLengthException $e) {
|
||||
$this->fail($e->getMessage());
|
||||
@@ -185,10 +178,7 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
]));
|
||||
}
|
||||
catch (ConfigEntityIdLengthException $e) {
|
||||
$this->pass(new FormattableMarkup("config_test entity with ID length @length exceeding the maximum allowed length of @max failed to save", [
|
||||
'@length' => strlen($id_length_config_test->id()),
|
||||
'@max' => static::MAX_ID_LENGTH,
|
||||
]));
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Ensure that creating an entity with the same id as an existing one is not
|
||||
@@ -202,7 +192,7 @@ class ConfigEntityTest extends BrowserTestBase {
|
||||
$this->fail('Not possible to overwrite an entity entity.');
|
||||
}
|
||||
catch (EntityStorageException $e) {
|
||||
$this->pass('Not possible to overwrite an entity entity.');
|
||||
// Expected exception; just continue testing.
|
||||
}
|
||||
|
||||
// Verify that renaming the ID returns correct status and properties.
|
||||
|
||||
@@ -231,6 +231,10 @@ EOD;
|
||||
$this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
|
||||
$this->assertText(t('Can not uninstall the Configuration module as part of a configuration synchronization through the user interface.'));
|
||||
|
||||
// Try to import without any values.
|
||||
$this->drupalPostForm('admin/config/development/configuration/single/import', [], t('Import'));
|
||||
$this->assertText('Configuration type field is required.');
|
||||
$this->assertText('Paste your configuration here field is required.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,38 +29,32 @@ class SchemaConfigListenerWebTest extends BrowserTestBase {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
|
||||
|
||||
// Test a non-existing schema.
|
||||
$msg = 'Expected SchemaIncompleteException thrown';
|
||||
try {
|
||||
$this->config('config_schema_test.schemaless')->set('foo', 'bar')->save();
|
||||
$this->fail($msg);
|
||||
$this->fail('Expected SchemaIncompleteException thrown');
|
||||
}
|
||||
catch (SchemaIncompleteException $e) {
|
||||
$this->pass($msg);
|
||||
$this->assertEquals('No schema for config_schema_test.schemaless', $e->getMessage());
|
||||
}
|
||||
|
||||
// Test a valid schema.
|
||||
$msg = 'Unexpected SchemaIncompleteException thrown';
|
||||
$config = $this->config('config_test.types')->set('int', 10);
|
||||
try {
|
||||
$config->save();
|
||||
$this->pass($msg);
|
||||
}
|
||||
catch (SchemaIncompleteException $e) {
|
||||
$this->fail($msg);
|
||||
$this->fail('Unexpected SchemaIncompleteException thrown');
|
||||
}
|
||||
|
||||
// Test an invalid schema.
|
||||
$msg = 'Expected SchemaIncompleteException thrown';
|
||||
$config = $this->config('config_test.types')
|
||||
->set('foo', 'bar')
|
||||
->set('array', 1);
|
||||
try {
|
||||
$config->save();
|
||||
$this->fail($msg);
|
||||
$this->fail('Expected SchemaIncompleteException thrown');
|
||||
}
|
||||
catch (SchemaIncompleteException $e) {
|
||||
$this->pass($msg);
|
||||
$this->assertEquals('Schema errors for config_test.types with the following errors: config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence, config_test.types:foo missing schema', $e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -35,6 +35,10 @@ trait ModerationStateJoinViewsHandlerTrait {
|
||||
'field' => 'content_entity_type_id',
|
||||
'value' => $left_entity_type->id(),
|
||||
],
|
||||
[
|
||||
'field' => 'content_entity_id',
|
||||
'left_field' => $left_entity_type->getKey('id'),
|
||||
],
|
||||
],
|
||||
];
|
||||
if ($left_entity_type->isTranslatable()) {
|
||||
|
||||
+12
-3
@@ -123,6 +123,7 @@ class ModerationStateFilter extends InOperator implements DependentWithRemovalPl
|
||||
$this->ensureMyTable();
|
||||
|
||||
$entity_type = $this->entityTypeManager->getDefinition($this->getEntityType());
|
||||
$bundle_condition = NULL;
|
||||
if ($entity_type->hasKey('bundle')) {
|
||||
// Get a list of bundles that are being moderated by the workflows
|
||||
// configured in this filter.
|
||||
@@ -137,7 +138,7 @@ class ModerationStateFilter extends InOperator implements DependentWithRemovalPl
|
||||
// If we have a list of moderated bundles, restrict the query to show only
|
||||
// entities in those bundles.
|
||||
if ($moderated_bundles) {
|
||||
$entity_base_table_alias = $this->table;
|
||||
$entity_base_table_alias = $this->relationship ?: $this->table;
|
||||
|
||||
// The bundle field of an entity type is not revisionable so we need to
|
||||
// join the base table.
|
||||
@@ -156,7 +157,8 @@ class ModerationStateFilter extends InOperator implements DependentWithRemovalPl
|
||||
$entity_base_table_alias = $this->query->addRelationship($entity_base_table, $join, $entity_revision_base_table);
|
||||
}
|
||||
|
||||
$this->query->addWhere($this->options['group'], "$entity_base_table_alias.{$entity_type->getKey('bundle')}", $moderated_bundles, 'IN');
|
||||
$bundle_condition = new Condition('AND');
|
||||
$bundle_condition->condition("$entity_base_table_alias.{$entity_type->getKey('bundle')}", $moderated_bundles, 'IN');
|
||||
}
|
||||
// Otherwise, force the query to return an empty result.
|
||||
else {
|
||||
@@ -186,7 +188,14 @@ class ModerationStateFilter extends InOperator implements DependentWithRemovalPl
|
||||
$field->condition($and);
|
||||
}
|
||||
|
||||
$this->query->addWhere($this->options['group'], $field);
|
||||
if ($bundle_condition) {
|
||||
// The query must match the bundle AND the workflow/state conditions.
|
||||
$bundle_condition->condition($field);
|
||||
$this->query->addWhere($this->options['group'], $bundle_condition);
|
||||
}
|
||||
else {
|
||||
$this->query->addWhere($this->options['group'], $field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user