26 Commits
Author SHA1 Message Date
Tessier c11935cb48 add img Online 2020-11-29 15:52:41 +01:00
Tessier 74e8ea8838 dl ressource click img 2020-11-14 16:39:23 +01:00
Tessier 43e958758d align logo footer 2020-11-14 16:20:38 +01:00
Tessier 34d706d0ca add media home 2020-11-14 16:01:37 +01:00
Tessier 8c33189167 fix img 2020-11-11 20:19:29 +01:00
Tessier 47cd70fca7 fix img 2020-11-11 20:16:47 +01:00
Tessier 6156084abf fix thumb again 2020-11-11 19:59:18 +01:00
Tessier 4e805776ed fix thumb 2020-11-11 19:53:05 +01:00
Tessier 65e37927b7 fix thumbnails programme 2020-11-11 19:48:48 +01:00
Tessier b7609524f9 modif 11_11_20 2020-11-11 19:38:54 +01:00
Tessier e45bd14b7a supp back 2020-11-11 17:59:43 +01:00
Tessier 23e66d3cb0 update 2020-11-11 17:55:34 +01:00
Tessier 981091b3f4 add second btn 2020-10-20 21:46:58 +02:00
Tessier 6368cf17ef fix ajax 2020-10-16 11:45:59 +02:00
Tessier 196f8058a8 log ajax 2020-10-16 11:28:56 +02:00
Tessier b6ada4240f log ajax 2020-10-16 11:21:48 +02:00
Tessier 3c0c530910 log ajax 2020-10-16 11:20:23 +02:00
Tessier 0d6cbda7b3 btn live responsive 2020-10-15 17:13:23 +02:00
Tessier 68ded22790 add btn live 2020-10-15 17:02:52 +02:00
Tessier c2b4c06a8f fix thumbnails participants status 2020-10-15 15:44:26 +02:00
Tessier 8a54ec0b43 change sous-titre event 2020-10-15 15:26:48 +02:00
Tessier d8b9162932 update drupal 2020-10-15 11:59:37 +02:00
Tessier ebb5db14b5 add redis 2020-10-15 11:33:59 +02:00
Tessier 3a66ee825e fix gitignore 2020-10-12 20:25:18 +02:00
Tessier 37988a3494 folder files 2020-10-12 20:24:06 +02:00
Tessier ee80899d18 embde&&_ressource_externe 2020-10-11 23:59:30 +02:00
594 changed files with 6554 additions and 5383 deletions
+4
View File
@@ -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/.*
+1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -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.
*/
+2 -2
View File
@@ -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 }
-2
View File
@@ -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
+2 -1
View File
@@ -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);
+4 -4
View File
@@ -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();
+3 -3
View File
@@ -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.
+1 -262
View File
@@ -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'];
+1 -1
View File
@@ -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")
*/
@@ -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 {
+20 -2
View File
@@ -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;
}
@@ -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);
}
/**
+2 -2
View File
@@ -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;
}
}
+1 -1
View File
@@ -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));
}
}
+1
View File
@@ -559,6 +559,7 @@
}
},
dataType: 'json',
jsonp: false,
type: 'POST',
};
+1
View File
@@ -243,6 +243,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
},
dataType: 'json',
jsonp: false,
type: 'POST'
};
+1
View File
@@ -281,6 +281,7 @@
},
ajax: {
dataType: 'json',
jsonp: false,
},
};
+2 -1
View File
@@ -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);
@@ -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');
}
}
@@ -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();
@@ -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.
@@ -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 . ')');
}
+1 -2
View File
@@ -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,
@@ -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
@@ -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.'
@@ -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;
}
}
@@ -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();
}
}
@@ -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());
}
@@ -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()) {
@@ -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