Skip to content
Snippets Groups Projects
Verified Commit 3b29a90b authored by Théodore Biadala's avatar Théodore Biadala
Browse files

Issue #3436526 by skaught, plopesc, kostyashupenko, m4olivei, quietone,...

Issue #3436526 by skaught, plopesc, kostyashupenko, m4olivei, quietone, godotislate, catch, ckrina, KeyboardCowboy, nod_, longwave: Adjust custom navigation logo dimensions on upload
parent 4f46b8b9
No related branches found
No related tags found
20 merge requests!11131[10.4.x-only-DO-NOT-MERGE]: Issue ##2842525 Ajax attached to Views exposed filter form does not trigger callbacks,!9470[10.3.x-only-DO-NOT-MERGE]: #3331771 Fix file_get_contents(): Passing null to parameter,!8736Update the Documention As per the Function uses.,!8513Issue #3453786: DefaultSelection should document why values for target_bundles NULL and [] behave as they do,!3878Removed unused condition head title for views,!3818Issue #2140179: $entity->original gets stale between updates,!3742Issue #3328429: Create item list field formatter for displaying ordered and unordered lists,!3731Claro: role=button on status report items,!3154Fixes #2987987 - CSRF token validation broken on routes with optional parameters.,!3133core/modules/system/css/components/hidden.module.css,!2964Issue #2865710 : Dependencies from only one instance of a widget are used in display modes,!2812Issue #3312049: [Followup] Fix Drupal.Commenting.FunctionComment.MissingReturnType returns for NULL,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2062Issue #3246454: Add weekly granularity to views date sort,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!877Issue #2708101: Default value for link text is not saved,!617Issue #3043725: Provide a Entity Handler for user cancelation,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493
Pipeline #275771 passed with warnings
Pipeline: drupal

#275792

    Pipeline: drupal

    #275786

      Pipeline: drupal

      #275775

        logo_provider: default
        logo_managed: {}
        logo_managed: null
        logo_max_filesize: 1048576
        logo_height: 40
        logo_width: 40
        ......@@ -3,20 +3,45 @@
        navigation.settings:
        type: config_object
        label: 'Navigation settings'
        constraints:
        FullyValidatable: ~
        mapping:
        logo_provider:
        type: string
        label: 'Select Navigation logo handling'
        constraints:
        NotNull: []
        Choice:
        - default
        - hide
        - custom
        logo_managed:
        type: sequence
        type: integer
        label: 'Custom logo'
        sequence:
        type: integer
        nullable: true
        constraints:
        Range:
        min: 0
        logo_max_filesize:
        type: integer
        label: 'Maximum file sizes (bytes)'
        constraints:
        NotNull: [ ]
        Range:
        min: 0
        logo_height:
        type: integer
        label: 'Logo expected height'
        constraints:
        NotNull: [ ]
        Range:
        min: 0
        logo_width:
        type: integer
        label: 'Logo expected width'
        constraints:
        NotNull: [ ]
        Range:
        min: 0
        navigation.block_layout:
        type: config_object
        ......
        ......@@ -26,3 +26,16 @@ function navigation_post_update_update_permissions(array &$sandbox) {
        return $needs_save;
        });
        }
        /**
        * Defines the values for the default logo dimensions.
        */
        function navigation_post_update_set_logo_dimensions_default(array &$sandbox) {
        $settings = \Drupal::configFactory()->getEditable('navigation.settings');
        $settings->set('logo_height', 40)
        ->set('logo_width', 40);
        if (is_array($settings->get('logo_managed'))) {
        $settings->set('logo_managed', current($settings->get('logo_managed')));
        }
        $settings->save();
        }
        ......@@ -7,10 +7,12 @@
        use Drupal\Component\Utility\Environment;
        use Drupal\Core\Config\ConfigFactoryInterface;
        use Drupal\Core\Config\TypedConfigManagerInterface;
        use Drupal\Core\Entity\EntityTypeManagerInterface;
        use Drupal\Core\File\FileSystemInterface;
        use Drupal\Core\File\FileUrlGeneratorInterface;
        use Drupal\Core\Form\ConfigFormBase;
        use Drupal\Core\Form\FormStateInterface;
        use Drupal\Core\Image\ImageFactory;
        use Drupal\Core\Render\RendererInterface;
        use Drupal\file\Entity\File;
        use Drupal\file\FileUsage\FileUsageInterface;
        ......@@ -24,34 +26,6 @@
        */
        final class SettingsForm extends ConfigFormBase {
        /**
        * The file system service.
        *
        * @var \Drupal\Core\File\FileSystemInterface
        */
        protected $fileSystem;
        /**
        * The file usage service.
        *
        * @var \Drupal\file\FileUsage\FileUsageInterface
        */
        protected $fileUsage;
        /**
        * The file URL generator.
        *
        * @var \Drupal\Core\File\FileUrlGeneratorInterface
        */
        protected $fileUrlGenerator;
        /**
        * Renderer service.
        *
        * @var \Drupal\Core\Render\RendererInterface
        */
        protected RendererInterface $renderer;
        /**
        * Constructs a Navigation SettingsForm object.
        *
        ......@@ -59,28 +33,30 @@ final class SettingsForm extends ConfigFormBase {
        * The factory for configuration objects.
        * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
        * The typed config manager.
        * @param \Drupal\Core\File\FileSystemInterface $file_system
        * File system service.
        * @param \Drupal\Core\File\FileSystemInterface $fileSystem
        * The file system.
        * @param \Drupal\Core\File\FileUrlGeneratorInterface $fileUrlGenerator
        * The file URL generator.
        * @param \Drupal\file\FileUsage\FileUsageInterface $fileUsage
        * The File Usage service.
        * @param \Drupal\Core\Render\RendererInterface $renderer
        * Renderer service.
        * The renderer service.
        * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
        * The entity type manager.
        * @param \Drupal\Core\Image\ImageFactory $imageFactory
        * The image factory.
        */
        public function __construct(
        ConfigFactoryInterface $config_factory,
        TypedConfigManagerInterface $typed_config_manager,
        FileSystemInterface $file_system,
        FileUrlGeneratorInterface $fileUrlGenerator,
        FileUsageInterface $fileUsage,
        RendererInterface $renderer,
        protected FileSystemInterface $fileSystem,
        protected FileUrlGeneratorInterface $fileUrlGenerator,
        protected FileUsageInterface $fileUsage,
        protected RendererInterface $renderer,
        protected EntityTypeManagerInterface $entityTypeManager,
        protected ImageFactory $imageFactory,
        ) {
        parent::__construct($config_factory, $typed_config_manager);
        $this->fileSystem = $file_system;
        $this->fileUrlGenerator = $fileUrlGenerator;
        $this->fileUsage = $fileUsage;
        $this->renderer = $renderer;
        }
        /**
        ......@@ -93,7 +69,9 @@ public static function create(ContainerInterface $container) {
        $container->get('file_system'),
        $container->get('file_url_generator'),
        $container->get('file.usage'),
        $container->get('renderer')
        $container->get('renderer'),
        $container->get('entity_type.manager'),
        $container->get('image.factory')
        );
        }
        ......@@ -130,7 +108,7 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
        NavigationRenderer::LOGO_PROVIDER_HIDE => $this->t('Hide logo'),
        NavigationRenderer::LOGO_PROVIDER_CUSTOM => $this->t('Custom logo'),
        ],
        '#default_value' => $config->get('logo_provider'),
        '#config_target' => 'navigation.settings:logo_provider',
        ];
        $form['logo']['image'] = [
        '#type' => 'container',
        ......@@ -141,7 +119,7 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
        ],
        ];
        $allowed = 'png jpg jpeg';
        $current_logo_managed_fid = $config->get('logo_managed');
        $current_logo_managed_fid = $config->get('logo_managed') ? [$config->get('logo_managed')] : NULL;
        $max_navigation_allowed = $config->get('logo_max_filesize');
        $max_system_allowed = Environment::getUploadMaxSize();
        $max_allowed = $max_navigation_allowed < $max_system_allowed ? $max_navigation_allowed : $max_system_allowed;
        ......@@ -172,9 +150,13 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
        */
        public function validateForm(array &$form, FormStateInterface $form_state): void {
        $logo_managed = $form_state->getValue('logo_managed');
        if ($form_state->getValue('logo_provider') === NavigationRenderer::LOGO_PROVIDER_CUSTOM && empty($logo_managed) === TRUE) {
        if ($form_state->getValue('logo_provider') === NavigationRenderer::LOGO_PROVIDER_CUSTOM && empty($logo_managed)) {
        $form_state->setErrorByName('logo_managed', 'An image file is required with the current logo handling option.');
        }
        // If the upload element is not empty and the image is new, try to adjust
        // the image dimensions.
        $this->validateLogoManaged($form, $form_state);
        }
        /**
        ......@@ -185,8 +167,7 @@ public function submitForm(array &$form, FormStateInterface $form_state): void {
        // Get the previous config settings.
        $previous_logo_provider = $config->get('logo_provider');
        $logo_managed = $config->get('logo_managed');
        $previous_logo_fid = $logo_managed ? reset($logo_managed) : NULL;
        $previous_logo_fid = $config->get('logo_managed');
        // Get new values from the form.
        $new_logo_provider = $form_state->getValue('logo_provider');
        ......@@ -214,10 +195,82 @@ public function submitForm(array &$form, FormStateInterface $form_state): void {
        }
        $config
        ->set('logo_provider', $form_state->getValue('logo_provider'))
        ->set('logo_managed', $form_state->getValue('logo_managed'))
        ->set('logo_managed', $new_logo_fid)
        ->save();
        parent::submitForm($form, $form_state);
        }
        /**
        * Validate the Logo Managed image element.
        *
        * @param array $form
        * An associative array containing the structure of the form.
        * @param \Drupal\Core\Form\FormStateInterface $form_state
        * The current state of the form.
        */
        protected function validateLogoManaged(array $form, FormStateInterface $form_state): void {
        $logo_managed = $form_state->getValue('logo_managed');
        $config = $this->config('navigation.settings');
        if (empty($logo_managed)) {
        return;
        }
        $width = $config->get('logo_width');
        $height = $config->get('logo_height');
        // Skip if the fid has not been modified.
        $fid = reset($logo_managed);
        if ($fid == $config->get('logo_managed')) {
        return;
        }
        $file = $this->entityTypeManager->getStorage('file')
        ->load($fid);
        if ($fid && !$this->adjustLogoDimensions($file)) {
        $form_state->setErrorByName('logo_managed', $this->t('Image dimensions are bigger than the expected %widthx%height pixels and cannot be used as the navigation logo.',
        [
        '%width' => $width,
        '%height' => $height,
        ]));
        }
        }
        /**
        * Adjusts the custom logo dimensions according to navigation settings.
        *
        * @param \Drupal\file\Entity\File $file
        * The file entity that contains the image.
        *
        * @return bool
        * TRUE if the logo image dimensions are properly adjusted. FALSE otherwise.
        */
        protected function adjustLogoDimensions(File $file): bool {
        $config = $this->config('navigation.settings');
        $image = $this->imageFactory->get($file->getFileUri());
        if (!$image->isValid()) {
        return FALSE;
        }
        $width = $config->get('logo_width');
        $height = $config->get('logo_height');
        if ($image->getWidth() <= $width && $image->getHeight() <= $height) {
        return TRUE;
        }
        if ($image->scale($width, $height) && $image->save()) {
        $this->messenger()->addStatus($this->t('The image was resized to fit within the navigation logo expected dimensions of %widthx%height pixels. The new dimensions of the resized image are %new_widthx%new_height pixels.',
        [
        '%width' => $width,
        '%height' => $height,
        '%new_width' => $image->getWidth(),
        '%new_height' => $image->getHeight(),
        ]));
        return TRUE;
        }
        return FALSE;
        }
        }
        ......@@ -19,6 +19,7 @@
        use Drupal\Core\Plugin\Context\ContextDefinition;
        use Drupal\Core\Routing\RouteMatchInterface;
        use Drupal\file\Entity\File;
        use Drupal\file\FileInterface;
        use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
        use Symfony\Component\HttpFoundation\RequestStack;
        ......@@ -143,18 +144,15 @@ public function buildNavigation(array &$page_top): void {
        $page_top['navigation'] = $build;
        if ($logo_provider === self::LOGO_PROVIDER_CUSTOM) {
        $logo_managed_fid = $logo_settings->get('logo_managed');
        if (isset($logo_managed_fid[0]) && $logo_managed_fid[0] > 0) {
        $logo_managed = File::load($logo_managed_fid[0]);
        if ($logo_managed instanceof File) {
        $logo_managed_uri = $logo_managed->getFileUri();
        $logo_managed_url = $this->fileUrlGenerator->generateAbsoluteString($logo_managed_uri);
        $page_top['navigation'][0]['settings']['logo_path'] = $logo_managed_url;
        $image = $this->imageFactory->get($logo_managed_uri);
        if ($image->isValid()) {
        $page_top['navigation'][0]['settings']['logo_width'] = $image->getWidth();
        $page_top['navigation'][0]['settings']['logo_height'] = $image->getHeight();
        }
        $logo_managed = File::load($logo_settings->get('logo_managed'));
        if ($logo_managed instanceof FileInterface) {
        $logo_managed_uri = $logo_managed->getFileUri();
        $logo_managed_url = $this->fileUrlGenerator->generateAbsoluteString($logo_managed_uri);
        $page_top['navigation'][0]['settings']['logo_path'] = $logo_managed_url;
        $image = $this->imageFactory->get($logo_managed_uri);
        if ($image->isValid()) {
        $page_top['navigation'][0]['settings']['logo_width'] = $image->getWidth();
        $page_top['navigation'][0]['settings']['logo_height'] = $image->getHeight();
        }
        }
        }
        ......
        ......@@ -93,7 +93,7 @@ public function testSettingsLogoOptionsForm(): void {
        // Preset the configuration to verify a custom image is being seen.
        $config = $this->configFactory->getEditable('navigation.settings');
        $config->set('logo_provider', 'custom');
        $config->set('logo_managed', [$logo_file->id()]);
        $config->set('logo_managed', $logo_file->id());
        $config->save();
        // Refresh the page to verify custom logo is placed.
        $this->drupalGet('/admin/config/user-interface/navigation/settings');
        ......
        <?php
        declare(strict_types=1);
        namespace Drupal\Tests\navigation\FunctionalJavascript;
        use Drupal\file\Entity\File;
        use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
        use Drupal\Tests\TestFileCreationTrait;
        /**
        * Tests that theme form settings works correctly.
        *
        * @group navigation
        */
        class NavigationSettingsFormTest extends WebDriverTestBase {
        use TestFileCreationTrait;
        /**
        * {@inheritdoc}
        */
        protected static $modules = ['navigation'];
        /**
        * {@inheritdoc}
        */
        protected $defaultTheme = 'stark';
        /**
        * {@inheritdoc}
        */
        protected function setUp(): void {
        parent::setUp();
        $admin = $this->drupalCreateUser(['administer site configuration']);
        $this->drupalLogin($admin);
        // Set expected logo dimensions smaller than core provided test images.
        \Drupal::configFactory()->getEditable('navigation.settings')
        ->set('logo_height', 10)
        ->set('logo_width', 10)
        ->save();
        }
        /**
        * Tests that submission handler works correctly.
        */
        public function testFormSettingsSubmissionHandler() {
        $page = $this->getSession()->getPage();
        $assert_session = $this->assertSession();
        $this->drupalGet("/admin/config/user-interface/navigation/settings");
        // Add a new managed file.
        $file = current($this->getTestFiles('image'));
        $image_file_path = \Drupal::service('file_system')->realpath($file->uri);
        $page->attachFileToField('files[logo_managed]', $image_file_path);
        $assert_session->waitForButton('logo_managed_remove_button');
        // Assert the new file is uploaded as temporary. This file should not be
        // saved as permanent if settings are not submitted.
        $image_field = $this->assertSession()->hiddenFieldExists('logo_managed[fids]');
        $file = File::load($image_field->getValue());
        $this->assertFalse($file->isPermanent());
        $page->pressButton('Save configuration');
        \Drupal::entityTypeManager()->getStorage('file')->resetCache();
        $this->drupalGet("/admin/config/user-interface/navigation/settings");
        // Assert the uploaded file is saved as permanent.
        $image_field = $this->assertSession()->hiddenFieldExists('logo_managed[fids]');
        $file = File::load($image_field->getValue());
        $this->assertTrue($file->isPermanent());
        // Ensure that the image has been resized to fit in the expected container.
        $image = \Drupal::service('image.factory')->get($file->getFileUri());
        $this->assertLessThanOrEqual(10, $image->getHeight());
        $this->assertLessThanOrEqual(10, $image->getWidth());
        }
        }
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Please register or to comment