Problem/Motivation

If you call Editor::getFilterFormat() to see if it's set, it doesn't work, and the error message isn't very helpful:

  $format = $editor->getFilterFormat();
  if (empty($format)) {
    return;
  }

If you do this before an editor object is saved, you get a frustrating fatal error about trying to load an entity with a NULL id.

This usually happens calling code in a subroutine at '/admin/config/content/formats/add'.

The error message should be more helpful. The correct way to use this code is to check first with ::hasAssociatedFilterFormat().

  if (!$editor->hasAssociatedFilterFormat()) {
    return;
  }

  $format = $editor->getFilterFormat();
  if (empty($format)) {
    return;
  }

Proposed resolution

Throw a \DomainException with a helpful message if $editor->getFilterFormat() called without a text format assigned to the Editor.

Remaining tasks

Fix the tests as described in #46.

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3083746

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

oknate created an issue. See original summary.

oknate’s picture

Issue summary: View changes
oknate’s picture

Issue summary: View changes
oknate’s picture

Issue summary: View changes
oknate’s picture

Status: Active » Needs review
Issue tags: +Needs tests
StatusFileSize
new800 bytes

cancelled the test, because I posted a new patch soon after. See #6.

oknate’s picture

StatusFileSize
new734 bytes
new1.5 KB

The last submitted patch, 6: 3083746-6--FAIL.patch, failed testing. View results

wim leers’s picture

Component: media system » editor.module
Category: Bug report » Task
Issue tags: -Needs tests +DX (Developer Experience), +Needs title update

I think it'd be better to throw a \DomainException instead.

The test coverage doesn't actually match the issue title. Either the test or the issue title is inaccurate.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

wim leers’s picture

Status: Needs review » Needs work
oknate’s picture

Title: Editor::getFilterFormat() shouldn't cause fatal error before Editor saved » Editor::getFilterFormat() should throw domain error if Editor::format not set
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs title update
StatusFileSize
new1.92 KB
new2.18 KB

Updated the title, IS and patch

oknate’s picture

Issue summary: View changes
wim leers’s picture

Status: Needs review » Reviewed & tested by the community

👍

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/editor/src/Entity/Editor.php
    @@ -126,10 +127,15 @@ public function hasAssociatedFilterFormat() {
    -    if (!$this->filterFormat) {
    -      $this->filterFormat = \Drupal::entityTypeManager()->getStorage('filter_format')->load($this->format);
    +    if ($this->filterFormat) {
    +      return $this->filterFormat;
         }
    -    return $this->filterFormat;
    +    elseif (empty($this->format)) {
    +      throw new \DomainException('Editor::getFilterFormat should not be called if Editor lacks an assigned text format.');
    +    }
    +    return \Drupal::entityTypeManager()
    +      ->getStorage('filter_format')
    +      ->load($this->format);
    

    This no longer sets $this->filterFormat... I think

        if (empty($this->format)) {
          throw new \DomainException('Editor::getFilterFormat should not be called if Editor lacks an assigned text format.');
        }
        if (!$this->filterFormat) {
          $this->filterFormat = \Drupal::entityTypeManager()
            ->getStorage('filter_format')
            ->load($this->format);
        }
        return $this->filterFormat;
    

    would work better.

  2. +++ b/core/modules/editor/tests/src/Kernel/EditorFilterIntegrationTest.php
    @@ -52,4 +52,23 @@ public function testTextFormatIntegration() {
    +  public function testEmptyFilterFormat() {
    +    $editor = Editor::create(['editor' => 'unicorn']);
    +    $this->expectException(\DomainException::class);
    +    $editor->getFilterFormat();
    +
    +    // Create an arbitrary text format.
    +    $format = FilterFormat::create([
    +      'format' => mb_strtolower($this->randomMachineName()),
    +      'name' => $this->randomString(),
    +    ]);
    +    $format->save();
    +    $editor->set('format', $format->id());
    +    $format = $editor->getFilterFormat();
    +    $this->assertInstanceOf(FilterFormat::class, $format);
    +  }
    

    This is not testing what you think it is. After the exception is thrown nothing else in the test is executed. So if you change assertInstanceOf to assertNotInstanceOf the test still passes.

  3. +++ b/core/modules/editor/tests/src/Kernel/EditorFilterIntegrationTest.php
    @@ -52,4 +52,23 @@ public function testTextFormatIntegration() {
    +    $this->expectException(\DomainException::class);
    +    $editor->getFilterFormat();
    +
    

    Should test the exception message too just in case there are multiple domain exceptions.

oknate’s picture

Status: Needs work » Needs review
StatusFileSize
new2.62 KB
new2.59 KB

Addressing #14
1) Nice catch, updated.
2) Reversed the order so the exception is tested last.
3) Added assertion for the exception message.

oknate’s picture

Adding credit for Alex Pott. Update: It didn't seem to take. So when this is committed, if not committed by Alex, he should get credit for his very good feedback.

alexpott’s picture

Status: Needs review » Needs work
+++ b/core/modules/editor/src/Entity/Editor.php
@@ -126,8 +127,13 @@ public function hasAssociatedFilterFormat() {
+      throw new \DomainException('Editor::getFilterFormat should not be called if Editor lacks an assigned text format.');

Thinking about this some more... I think including the ID of the editor entity would be helpful. Also can you use __METHOD__ instead of hardcoding the method name. It makes the code a bit more portable.

@oknate unfortunately the credit checkboxes only work for maintainers.

oknate’s picture

So what are you thinking for the message? How's this?

"You cannot call getFilterFormat() on the HelloWorld Editor since it does not have an assigned text format."

or

"You cannot call getFilterFormat() on the editor HelloWorld since it does not have an assigned text format."

alexpott’s picture

I think You cannot call getFilterFormat() on the editor HelloWorld since it does not have an assigned text format. works for me. Not sure - either version looks fine to be honest. In exception messages you can use sprintf() and not FormattableMarkup() because error mostly not going to HTML (think syslog). So variables are often put in quotes.

oknate’s picture

Status: Needs work » Needs review
StatusFileSize
new1.61 KB
new2.68 KB

Updated the output. I wasn't sure if I should put quotes around the editor ID or the method. Let me know if I should remove the quotes from either.

alexpott’s picture

@oknate sorry I should have been clearer. I think only the editor ID needs quotes. Other than that this looks great.

oknate’s picture

StatusFileSize
new2.68 KB

Updated to remove the first set of double quotes.

phenaproxima’s picture

  1. +++ b/core/modules/editor/src/Entity/Editor.php
    @@ -126,8 +127,13 @@ public function hasAssociatedFilterFormat() {
    +    if (empty($this->format)) {
    +      throw new \DomainException(sprintf('You cannot call %s on the editor "%s" since it does not have an assigned text format.', __METHOD__, $this->getEditor()));
    +    }
    

    I have a feeling that this is going to be contentious. The documentation for EditorInterface::getFilterFormat() explicitly says this:

    This could be NULL if the associated filter format is still being created.

    That makes me think that this behavior, unhelpful though it may be, was intentional and that adding this exception constitutes an API/behavior change. Therefore, I'm tagging this for framework manager review.

  2. +++ b/core/modules/editor/src/Entity/Editor.php
    @@ -126,8 +127,13 @@ public function hasAssociatedFilterFormat() {
    -      $this->filterFormat = \Drupal::entityTypeManager()->getStorage('filter_format')->load($this->format);
    +      $this->filterFormat = \Drupal::entityTypeManager()
    +        ->getStorage('filter_format')
    +        ->load($this->format);
    

    This change seems out of scope?

phenaproxima’s picture

Oh wait -- looking up in the issue, I see that @alexpott already reviewed this patch. If he thought this was okay, I guess this doesn't technically need framework manager review. Still...the interface documentation says something different, so I'm going to keep the tag.

oknate’s picture

Re:

This could be NULL if the associated filter format is still being created.

The problem is with this code. It doesn't verify that $this->format is !empty:

    if (!$this->filterFormat) {
      $this->filterFormat = \Drupal::entityTypeManager()->getStorage('filter_format')->load($this->format);
    }

So this part of the documentation was wrong:

   * This could be NULL if the associated filter format is still being created.
   * @see hasAssociatedFilterFormat()

It wouldn't return NULL. It would throw an error when trying to load the entity.

oknate’s picture

StatusFileSize
new1.49 KB
new3.25 KB

Addressing #23
1) Updating the interface documentation, to update the returns NULL, and adding the throws.
2) Removing the out of scope change (formatting).

alexpott’s picture

+1 on fixing the docs and throwing a proper exception.

jhedstrom’s picture

Explicit UI tests were added in #2207777: Can not configure editor whilst creating a new text format, so I think this change won't break/regress as those are still passing here with this change.

This looks good to me. +1 RTBC.

oknate’s picture

All three places touched in the patch in #28 use this pattern before calling getFilterFormat():

    if (!$editor->hasAssociatedFilterFormat()) {
      return [];
    }

That's the right way to do it, but the documentation, as @phenaproxima pointed out, said it could return NULL, which wouldn't happen, because if the filter format was missing, it would throw an error trying to load the filter format with a null value.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

wim leers’s picture

What remains to be done here? This seems very ready per #27, #28 and #29? 🤔

longwave’s picture

Status: Needs review » Reviewed & tested by the community

Agree with #33, there seems nothing left to do here, the patch is easy to follow and adds a test. The patch still applies cleanly to 9.3.x as well.

catch’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/core/modules/editor/src/EditorInterface.php
@@ -23,10 +23,10 @@ public function hasAssociatedFilterFormat();
    *
-   * @return \Drupal\filter\FilterFormatInterface|null
+   * @throws \DomainException
+   *   If called without an associated filter format.
    */

I think this could do with a bit more explanation why the editor wouldn't have an associate format (only when it's being created?) (which the original comment being removed has).

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs change record

This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

#35 still needs to be addressed
Tagging for change record so others are aware of the new change.

Rest looks good!

wim leers’s picture

Issue tags: +Novice

I think this would be a good novice issue 😊

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

wim leers’s picture

Any takers? I promise reviews :)

Keshav Patel made their first commit to this issue’s fork.

keshav patel’s picture

Created the MR using the #26 patch and addressed comment #35 as well, but the pipeline failed. keeping it on "Needs work".., please review the changes.

Change as per #35:

   /**
    * Returns the filter format this text editor is associated with.
    *
    * @return \Drupal\filter\FilterFormatInterface
    *
    * @throws \DomainException
 -  *   If called without an associated filter format.
 +  *   Thrown if the text editor is called without an associated filter format.
    */
  public function getFilterFormat();
wim leers’s picture

Those are all broken tests. Each of them is creating an Editor config entity without a corresponding FilterFormat already existing. We should fix those tests.

anicoto’s picture

Issue summary: View changes
Issue tags: +Portland2024, +backend
Novice issue reserved for the Mentored Contribution during the Contribution Day at DrupalCon Portland 2024. After the 8th of May 2024, this issue returns to being open to all. Thanks
xjm’s picture

Issue summary: View changes

Updating the remaining tasks to point to @Wim Leers' feedback. Thanks!

bibliophileaxe’s picture

Issue tags: +Barcelona2024
bibliophileaxe’s picture

The Drupal Contribution Mentoring team is triaging issues for DrupalCon Barcelona 2024, and we are reserving this issue for Mentored Contribution during the event.

After September 27, 2024, this issue returns to being open to all. Thanks!

stefdewa’s picture

I looked into updating the tests, specifically the failing tests from
core/modules/ckeditor5/tests/src/Kernel/CKEditor5PluginManagerTest::testInvalidPluginDefinitions
which calls
core/modules/ckeditor5/tests/src/Kernel/CKEditor5PluginManagerTest::providerTestInvalidPluginDefinitions.

The provider returns YAML with invalid ckeditor5 plugin definitions. The way I understand it, this YAML should define a FilterFormat that the ckeditor5 Editor uses. But how... that is not clear to me. Anyone have an idea on how this is done?

brandonlira made their first commit to this issue’s fork.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.