summaryrefslogtreecommitdiffstatshomepage
path: root/core/modules
diff options
context:
space:
mode:
Diffstat (limited to 'core/modules')
-rw-r--r--core/modules/block_content/src/Hook/BlockContentHooks.php10
-rw-r--r--core/modules/file/src/Plugin/Field/FieldType/FileItem.php5
-rw-r--r--core/modules/file/tests/src/Kernel/FileItemTest.php44
-rw-r--r--core/modules/image/src/Plugin/Field/FieldType/ImageItem.php4
-rw-r--r--core/modules/image/tests/src/Kernel/ImageItemTest.php42
-rw-r--r--core/modules/locale/locale.install6
-rw-r--r--core/modules/locale/src/LocaleTranslation.php13
-rw-r--r--core/modules/locale/tests/src/Functional/LocaleInstallTest.php48
-rw-r--r--core/modules/locale/tests/src/Kernel/LocaleTranslationTest.php18
-rw-r--r--core/modules/system/tests/src/Functional/FileTransfer/FileTransferTest.php24
10 files changed, 132 insertions, 82 deletions
diff --git a/core/modules/block_content/src/Hook/BlockContentHooks.php b/core/modules/block_content/src/Hook/BlockContentHooks.php
index bd1cfd608f14..4eef9bb8580c 100644
--- a/core/modules/block_content/src/Hook/BlockContentHooks.php
+++ b/core/modules/block_content/src/Hook/BlockContentHooks.php
@@ -29,11 +29,11 @@ class BlockContentHooks {
$field_ui = \Drupal::moduleHandler()->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
$output = '';
$output .= '<h2>' . $this->t('About') . '</h2>';
- $output .= '<p>' . $this->t('The Block Content module allows you to create and manage custom <em>block types</em> and <em>content-containing blocks</em>. For more information, see the <a href=":online-help">online documentation for the Block Content module</a>.', [':online-help' => 'https://www.drupal.org/documentation/modules/block_content']) . '</p>';
+ $output .= '<p>' . $this->t('The Block Content module manages the creation, editing, and deletion of content blocks. Content blocks are field-able content entities managed by the <a href=":field">Field module</a>. For more information, see the <a href=":block-content">online documentation for the Block Content module</a>.', [':block-content' => 'https://www.drupal.org/documentation/modules/block_content', ':field' => Url::fromRoute('help.page', ['name' => 'field'])->toString()]) . '</p>';
$output .= '<h2>' . $this->t('Uses') . '</h2>';
$output .= '<dl>';
$output .= '<dt>' . $this->t('Creating and managing block types') . '</dt>';
- $output .= '<dd>' . $this->t('Users with the <em>Administer blocks</em> permission can create and edit block types with fields and display settings, from the <a href=":types">Block types</a> page under the Structure menu. For more information about managing fields and display settings, see the <a href=":field-ui">Field UI module help</a> and <a href=":field">Field module help</a>.', [
+ $output .= '<dd>' . $this->t('Users with the <em>Administer block types</em> permission can create and edit block types with fields and display settings, from the <a href=":types">Block types</a> page under the Structure menu. For more information about managing fields and display settings, see the <a href=":field-ui">Field UI module help</a> and <a href=":field">Field module help</a>.', [
':types' => Url::fromRoute('entity.block_content_type.collection')->toString(),
':field-ui' => $field_ui,
':field' => Url::fromRoute('help.page', [
@@ -41,9 +41,9 @@ class BlockContentHooks {
])->toString(),
]) . '</dd>';
$output .= '<dt>' . $this->t('Creating content blocks') . '</dt>';
- $output .= '<dd>' . $this->t('Users with the <em>Administer blocks</em> permission can create, edit, and delete content blocks of each defined block type, from the <a href=":block-library">Content blocks page</a>. After creating a block, place it in a region from the <a href=":blocks">Block layout page</a>, just like blocks provided by other modules.', [
- ':blocks' => Url::fromRoute('block.admin_display')->toString(),
- ':block-library' => Url::fromRoute('entity.block_content.collection')->toString(),
+ $output .= '<dd>' . $this->t('Users with the <em>Administer block content</em> or <em>Create new content block</em> permissions for an individual block type are able to add content blocks. These can be created on the <a href=":add-content-block">Add content block page</a> or on the <em>Place block</em> modal on the <a href=":block-layout">Block Layout page</a> and are reusable across the entire site. Content blocks created in Layout Builder for a content type or individual node layouts are not reusable and also called inline blocks.', [
+ ':add-content-block' => Url::fromRoute('block_content.add_page')->toString(),
+ ':block-layout' => Url::fromRoute('block.admin_display')->toString(),
]) . '</dd>';
$output .= '</dl>';
return $output;
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index f09740667e32..2e9be38dacb6 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -360,8 +360,11 @@ class FileItem extends EntityReferenceItem {
$dirname = static::doGetUploadLocation($settings);
\Drupal::service('file_system')->prepareDirectory($dirname, FileSystemInterface::CREATE_DIRECTORY);
+ // Ensure directory ends with a slash.
+ $dirname .= str_ends_with($dirname, '/') ? '' : '/';
+
// Generate a file entity.
- $destination = $dirname . '/' . $random->name(10, TRUE) . '.txt';
+ $destination = $dirname . $random->name(10) . '.txt';
$data = $random->paragraphs(3);
/** @var \Drupal\file\FileRepositoryInterface $file_repository */
$file_repository = \Drupal::service('file.repository');
diff --git a/core/modules/file/tests/src/Kernel/FileItemTest.php b/core/modules/file/tests/src/Kernel/FileItemTest.php
index 09a28b68f0f1..c01cf28a1151 100644
--- a/core/modules/file/tests/src/Kernel/FileItemTest.php
+++ b/core/modules/file/tests/src/Kernel/FileItemTest.php
@@ -6,12 +6,14 @@ namespace Drupal\Tests\file\Kernel;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\file\Entity\File;
+use Drupal\file\Plugin\Field\FieldType\FileItem;
use Drupal\user\Entity\Role;
/**
@@ -155,6 +157,48 @@ class FileItemTest extends FieldKernelTestBase {
\Drupal::service('renderer')->renderRoot($output);
$this->assertTrue(!empty($entity->file_test->entity));
$this->assertEquals($uri, $entity->file_test->entity->getFileUri());
+
+ // Test file URIs with empty and custom directories.
+ $this->validateFileUriForDirectory(
+ '', 'public://'
+ );
+ $this->validateFileUriForDirectory(
+ 'custom_directory/subdir', 'public://custom_directory/subdir/'
+ );
+ }
+
+ /**
+ * Tests file URIs generated for a given file directory.
+ *
+ * @param string $file_directory
+ * The file directory to test (e.g., empty or 'custom_directory/subdir').
+ * @param string $expected_start
+ * The expected starting string of the file URI (e.g., 'public://').
+ */
+ private function validateFileUriForDirectory(string $file_directory, string $expected_start): void {
+ // Mock the field definition with the specified file directory.
+ $definition = $this->createMock(FieldDefinitionInterface::class);
+ $definition->expects($this->any())
+ ->method('getSettings')
+ ->willReturn([
+ 'file_extensions' => 'txt',
+ 'file_directory' => $file_directory,
+ 'uri_scheme' => 'public',
+ 'display_default' => TRUE,
+ ]);
+
+ // Generate a sample file value.
+ $value = FileItem::generateSampleValue($definition);
+ $this->assertNotEmpty($value);
+
+ // Load the file entity and get its URI.
+ $fid = $value['target_id'];
+ $file = File::load($fid);
+ $fileUri = $file->getFileUri();
+
+ // Verify the file URI starts with the expected protocol and structure.
+ $this->assertStringStartsWith($expected_start, $fileUri);
+ $this->assertMatchesRegularExpression('#^' . preg_quote($expected_start, '#') . '[^/]+#', $fileUri);
}
}
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index 7ed6b0d3371c..72937d4e79a3 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -389,7 +389,9 @@ class ImageItem extends FileItem {
$image->setFileName($file_system->basename($path));
$destination_dir = static::doGetUploadLocation($settings);
$file_system->prepareDirectory($destination_dir, FileSystemInterface::CREATE_DIRECTORY);
- $destination = $destination_dir . '/' . basename($path);
+ // Ensure directory ends with a slash.
+ $destination_dir .= str_ends_with($destination_dir, '/') ? '' : '/';
+ $destination = $destination_dir . basename($path);
$file = \Drupal::service('file.repository')->move($image, $destination);
$images[$extension][$min_resolution][$max_resolution][$file->id()] = $file;
}
diff --git a/core/modules/image/tests/src/Kernel/ImageItemTest.php b/core/modules/image/tests/src/Kernel/ImageItemTest.php
index 0598b25e9db8..55f2503686d4 100644
--- a/core/modules/image/tests/src/Kernel/ImageItemTest.php
+++ b/core/modules/image/tests/src/Kernel/ImageItemTest.php
@@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -19,6 +20,7 @@ use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\file\Entity\File;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
+use Drupal\image\Plugin\Field\FieldType\ImageItem;
use Drupal\user\Entity\Role;
/**
@@ -208,6 +210,14 @@ class ImageItemTest extends FieldKernelTestBase {
}
/**
+ * Tests image URIs for empty and custom directories.
+ */
+ public function testImageUriDirectories(): void {
+ $this->validateImageUriForDirectory('', 'public://');
+ $this->validateImageUriForDirectory('custom_directory/subdir', 'public://custom_directory/subdir/');
+ }
+
+ /**
* Tests display_default.
*/
public function testDisplayDefaultValue(): void {
@@ -225,4 +235,36 @@ class ImageItemTest extends FieldKernelTestBase {
self::assertEquals(1, $form_state->getValue(['image_test', 0, 'display']));
}
+ /**
+ * Validates the image file URI generated for a given file directory.
+ *
+ * @param string $file_directory
+ * The file directory to test (e.g., empty or 'custom_directory/subdir').
+ * @param string $expected_start
+ * The expected starting string of the file URI (e.g., 'public://').
+ */
+ private function validateImageUriForDirectory(string $file_directory, string $expected_start): void {
+ // Mock the field definition with the specified file directory.
+ $definition = $this->createMock(FieldDefinitionInterface::class);
+ $definition->expects($this->any())
+ ->method('getSettings')
+ ->willReturn([
+ 'file_extensions' => 'jpg',
+ 'file_directory' => $file_directory,
+ 'uri_scheme' => 'public',
+ ]);
+ // Generate sample value and check the URI format.
+ $value = ImageItem::generateSampleValue($definition);
+ $this->assertNotEmpty($value);
+
+ // Load the file entity and get its URI.
+ $fid = $value['target_id'];
+ $file = File::load($fid);
+ $fileUri = $file->getFileUri();
+
+ // Verify the file URI starts with the expected protocol and structure.
+ $this->assertStringStartsWith($expected_start, $fileUri);
+ $this->assertMatchesRegularExpression('#^' . preg_quote($expected_start, '#') . '[^/]+#', $fileUri);
+ }
+
}
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 457d37890fa0..d3377f3773eb 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -21,12 +21,6 @@ function locale_install(): void {
\Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save();
}
\Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
-
- $t_args = [
- ':translate_status' => base_path() . 'admin/reports/translations/check?destination=' . urlencode(base_path() . 'admin/reports/translations'),
- ];
- $message = t('Check <a href=":translate_status">available translations</a> for your language(s).', $t_args);
- \Drupal::messenger()->addStatus($message);
}
/**
diff --git a/core/modules/locale/src/LocaleTranslation.php b/core/modules/locale/src/LocaleTranslation.php
index a9ccc93626f0..99e852650ee6 100644
--- a/core/modules/locale/src/LocaleTranslation.php
+++ b/core/modules/locale/src/LocaleTranslation.php
@@ -20,7 +20,9 @@ use Symfony\Component\HttpFoundation\RequestStack;
*/
class LocaleTranslation implements TranslatorInterface, DestructableInterface {
- use DependencySerializationTrait;
+ use DependencySerializationTrait {
+ __sleep as traitSleep;
+ }
/**
* Storage for strings.
@@ -161,4 +163,13 @@ class LocaleTranslation implements TranslatorInterface, DestructableInterface {
}
}
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep(): array {
+ // ::$translations is an array of LocaleLookup objects, which have the
+ // database service injected and therefore cannot be serialized safely.
+ return array_diff($this->traitSleep(), ['translations']);
+ }
+
}
diff --git a/core/modules/locale/tests/src/Functional/LocaleInstallTest.php b/core/modules/locale/tests/src/Functional/LocaleInstallTest.php
deleted file mode 100644
index fc81fdb19b52..000000000000
--- a/core/modules/locale/tests/src/Functional/LocaleInstallTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\locale\Functional;
-
-use Drupal\Tests\BrowserTestBase;
-
-/**
- * Test installation of Locale module.
- *
- * @group locale
- */
-class LocaleInstallTest extends BrowserTestBase {
-
- /**
- * {@inheritdoc}
- */
- protected static $modules = [
- 'system',
- 'file',
- 'language',
- ];
-
- /**
- * {@inheritdoc}
- */
- protected $defaultTheme = 'stark';
-
- /**
- * Tests Locale install message.
- */
- public function testLocaleInstallMessage(): void {
- $admin_user = $this->drupalCreateUser([
- 'access administration pages',
- 'administer modules',
- ]);
- $this->drupalLogin($admin_user);
-
- $edit = [];
- $edit['modules[locale][enable]'] = 'locale';
- $this->drupalGet('admin/modules');
- $this->submitForm($edit, 'Install');
-
- $this->assertSession()->statusMessageContains('available translations', 'status');
- }
-
-}
diff --git a/core/modules/locale/tests/src/Kernel/LocaleTranslationTest.php b/core/modules/locale/tests/src/Kernel/LocaleTranslationTest.php
index 316384330f8b..b52d29348253 100644
--- a/core/modules/locale/tests/src/Kernel/LocaleTranslationTest.php
+++ b/core/modules/locale/tests/src/Kernel/LocaleTranslationTest.php
@@ -21,11 +21,29 @@ class LocaleTranslationTest extends KernelTestBase {
];
/**
+ * {@inheritdoc}
+ */
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->installSchema('locale', [
+ 'locales_location',
+ 'locales_source',
+ 'locales_target',
+ ]);
+ }
+
+ /**
* Tests that \Drupal\locale\LocaleTranslation is serializable.
*/
public function testSerializable(): void {
+ /** @var \Drupal\locale\LocaleTranslation $translation */
$translation = $this->container->get('string_translator.locale.lookup');
$this->assertInstanceOf(LocaleTranslation::class, $translation);
+ // Ensure that the \Drupal\locale\LocaleTranslation::$translations property
+ // has some cached translations in it. Without this, serialization will not
+ // actually be tested fully.
+ $translation->getStringTranslation('es', 'test', '');
// Prove that serialization and deserialization works without errors.
$this->assertNotNull($translation);
diff --git a/core/modules/system/tests/src/Functional/FileTransfer/FileTransferTest.php b/core/modules/system/tests/src/Functional/FileTransfer/FileTransferTest.php
index ae157ab56624..fa6bda652deb 100644
--- a/core/modules/system/tests/src/Functional/FileTransfer/FileTransferTest.php
+++ b/core/modules/system/tests/src/Functional/FileTransfer/FileTransferTest.php
@@ -88,26 +88,10 @@ class FileTransferTest extends BrowserTestBase {
*/
public function testJail(): void {
$source = $this->_buildFakeModule();
-
- // This convoluted piece of code is here because our testing framework does
- // not support expecting exceptions.
- $got_it = FALSE;
- try {
- $this->testConnection->copyDirectory($source, sys_get_temp_dir());
- }
- catch (FileTransferException) {
- $got_it = TRUE;
- }
- $this->assertTrue($got_it, 'Was not able to copy a directory outside of the jailed area.');
-
- $got_it = TRUE;
- try {
- $this->testConnection->copyDirectory($source, $this->root . '/' . PublicStream::basePath());
- }
- catch (FileTransferException) {
- $got_it = FALSE;
- }
- $this->assertTrue($got_it, 'Was able to copy a directory inside of the jailed area');
+ $this->testConnection->copyDirectory($source, $this->root . '/' . PublicStream::basePath());
+ $this->expectException(FileTransferException::class);
+ $this->expectExceptionMessage('@directory is outside of the @jail');
+ $this->testConnection->copyDirectory($source, sys_get_temp_dir());
}
}