The \Drupal\serialization\Normalizer\NormalizerBase has the checkFormat() method which allows you to check whether data format is supported by this normalizer.

Proposed resolution

  1. Rename property $formats of \Drupal\hal\Normalizer\NormalizerBase to $format.
  2. Remove supportsNormalization() and supportsDenormalization() methods of the same class.
  3. Explicitly define the $format property in \Drupal\serialization\Normalizer\NormalizerBase class to allow inheritance.

Comments

BR0kEN created an issue. See original summary.

br0ken’s picture

Also, some part of hal module is already uses this behavior. See \Drupal\hal\Normalizer\FieldNormalizer.

br0ken’s picture

Status: Active » Needs review
StatusFileSize
new2.77 KB
br0ken’s picture

Issue summary: View changes
l0ke’s picture

StatusFileSize
new6.04 KB
new3.27 KB

Added test to demonstrate that supportsDenormalization() method override was redundant and it's removal will not break anything.

Also noticed that $supportedInterfaceOrClass property can be an array for example:
Drupal\serialization\NormalizerContentEntityNormalizer

protected $supportedInterfaceOrClass = ['Drupal\Core\Entity\ContentEntityInterface'];

In this case implementation of \Drupal\hal\Normalizer\NormalizerBase::supportsDenormalization() will throw \RuntimeException Array to string conversion on this line

$supported = new \ReflectionClass($this->supportedInterfaceOrClass);

Uploading a patch and let's wait until tests will pass.

br0ken’s picture

The patch above is just demonstrating that removed logic has not worked in a different way. Great work, @l0ke! Thanks. If tests becomes passed then it looks like changes are safe to be committed.

wim leers’s picture

Status: Needs review » Needs work

This has been bothering me for a long time too, but it was never a big enough deal to create this issue. Thanks!

SupportDenormalizationUnitTest is kind of a strange test. Possibly we already have enough functional test coverage that we don't need this unit test that is comparing "old code" with "new code" and asserting the results are the same. This test makes sense right now, but it won't anymore after this is committed.
I'll let a core committer decide.


Just two nits:

+++ b/core/modules/hal/tests/src/Unit/SupportDenormalizationUnitTest.php
@@ -0,0 +1,104 @@
+class SupportDenormalizationUnitTest extends UnitTestCase {
+  /**

+++ b/core/modules/serialization/src/Normalizer/NormalizerBase.php
@@ -16,6 +16,12 @@
   protected $supportedInterfaceOrClass;
+  /**

Needs \n in between. After that's fixed, this is RTBC.

br0ken’s picture

Assigned: br0ken » Unassigned
Status: Needs work » Reviewed & tested by the community

@Wim Leers, patch in #5 named as 2863778-5-do-not-commit.patch and created only for demonstration purposes (what you've mentioned in your comment). We discussed this with @l0ke and he has created the patch only to show to the committers/reviewers that removed logic was doing completely the same. (that's simplifies the review and testing).

According to above, coding standards problems should be ignored for patch #5 since it's have only demonstration character.

wim leers’s picture

Ahhhh, right! Great :)

Can you then please repulsed #2? Core committers expect the last patch to be the patch to commit.

br0ken’s picture

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. @BR0kEN - it's community convention that you don't rtbc your own patches. Also it's great when the RTBC patch is the most recent patch on the issue so that it is the one being re-tested when the issue is at rtbc.
  2. +++ b/core/modules/serialization/src/Normalizer/NormalizerBase.php
    @@ -16,6 +16,12 @@
       protected $supportedInterfaceOrClass;
    +  /**
    

    Need a new line here.

  3. +++ b/core/modules/serialization/src/Normalizer/NormalizerBase.php
    @@ -67,7 +73,7 @@ public function supportsDenormalization($data, $type, $format = NULL) {
    -    if (!isset($format) || !isset($this->format)) {
    +    if (!isset($format) || empty($this->format)) {
           return TRUE;
         }
    

    Is this change covered by a test anywhere?

  4. Also looking at \Drupal\serialization\Normalizer\NormalizerBase the use of in_array with specifying the 3rd parameter as TRUE makes me afraid of really odd bugs.
alexpott’s picture

@BR0kEN also - just so you know - hiding the files doesn't affect the RTBC retest.

br0ken’s picture

@alexpott, I hiding the files because they are auxiliary.

br0ken’s picture

+++ b/core/modules/serialization/src/Normalizer/NormalizerBase.php
@@ -67,7 +73,7 @@ public function supportsDenormalization($data, $type, $format = NULL) {
-    if (!isset($format) || !isset($this->format)) {
+    if (!isset($format) || empty($this->format)) {
       return TRUE;
     }

The format property is used only by two normalizers in core: \Drupal\hal\Normalizer\FieldNormalizer and \Drupal\hal\Normalizer\NormalizerBase. I'm proposing to change for empty() because there's no sense to convert "empty" data to an array.

br0ken’s picture

Status: Needs work » Needs review
StatusFileSize
new2.82 KB
new430 bytes
br0ken’s picture

StatusFileSize
new2.5 KB
new682 bytes

But let's allow the next: in_array('', ['']).

br0ken’s picture

@alexpott, regarding your 4 point. I can't realize where you found in_array() with three arguments called.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community
alexpott’s picture

@BR0kEN - it's the lack of the third argument and it not being TRUE that scares me. Pretty much people always want in_array($needle, $haystack, TRUE) and not in_array($needle, $haystack) - see https://3v4l.org/sr29Y

br0ken’s picture

@alexpott, ah, that's what you meant - got it now. Are you proposing to change this here, in scope of this issue, or leave as is?

alexpott’s picture

@BR0kEN not in scope because as far as we know it is not causing issues but it'd be great if someone could open an issue about it.

br0ken’s picture

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/hal/src/Normalizer/NormalizerBase.php
@@ -11,35 +11,8 @@
   /**
-   * The formats that the Normalizer can handle.
-   *
-   * @var array
-   */
-  protected $formats = ['hal_json'];
...
+  protected $format = ['hal_json'];

Sorry I just noticed this rename. We shouldn't rename a property on a base class. This is API. Things are meant to inherit from this class - it's abstract! Or at least it we do this we need to implement a magic __get and __set for the property "formats" - which gets complex because the original scope of the property is protected.

Maybe the thing to do is make the base class use either $format or $formats? And deprecate $formats. Tricky. BC is hard.

catch’s picture

Maybe the thing to do is make the base class use either $format or $formats? And deprecate $formats.

That seems right here. Use $formats if it's set, but trigger_error() with a deprecation notice, use $format otherwise with no deprecation notice. Then a subclass with no changes continues to work the same way but gets the notice.

I thought about doing it the other way, but since the property is already set there doesn't seem a way around that.

br0ken’s picture

@alexpott, are you worrying about custom implementations? If yes, then makes sense.

xjm’s picture

For reference, here is the handbook page on how to add the deprecation: https://www.drupal.org/core/deprecation

And in general, yes, we do have to at least consider the impact on custom implementations.

br0ken’s picture

@xjm I haven't found anything regarding class properties. What is the correct approach is this case?

wim leers’s picture

Title: Use opportunities of "\Drupal\serialization\Normalizer\NormalizerBase" instead of redeveloping them by HAL "NormalizerBase" » Clean up \Drupal\hal\Normalizer\NormalizerBase: duplicate less from the parent class \Drupal\serialization\Normalizer\NormalizerBase
Category: Feature request » Task
Priority: Normal » Minor
Issue tags: +clean-up

Note that the next steps are clearly described in #24.

wim leers’s picture

wim leers’s picture

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new2.93 KB
new822 bytes

There we go.

wim leers’s picture

Status: Needs review » Needs work

Thanks!

  1. +++ b/core/modules/hal/src/Normalizer/NormalizerBase.php
    @@ -15,4 +15,19 @@
    +    if (!isset($format) || !isset($this->format) || !isset($this->formats)) {
    

    Using either $this->format or $this->formats is allowed.

    Therefore this should be

    if (!isset($format)
     || (!isset($this->format) && !isset($This->formats))) {
  2. +++ b/core/modules/hal/src/Normalizer/NormalizerBase.php
    @@ -15,4 +15,19 @@
    +    return in_array($format, (array) $this->format);
    

    And the $this->format here should be either $this->format or $this->formats, right now this is still breaking BC.

    P.S.: also should use strict comparison.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new3.15 KB
new1.43 KB

P.S.: also should use strict comparison.

Well, the parent is using the non strict comparison already, but yeah meh.

Using either $this->format or $this->formats is allowed.

Therefore this should be

Oh njce point! I improved the readability of the logic a bit.

The last submitted patch, 31: 2863778-29.patch, failed testing.

wim leers’s picture

I don't understand any of the changes in #33.

Also, yay, #31 failed! Seems like we have some test coverage for this that is now failing due to the bug I pointed out in #32.

dawehner’s picture

I don't understand any of the changes in #33.

Can you clarify what you don't understand? The only logic I applied on top of your comment is: (!$ && !b) == !($a || b)

wim leers’s picture

Status: Needs review » Needs work

Oh, hah, I misread! That part now makes sense. But this part still does not:

  1. +++ b/core/modules/hal/src/Normalizer/NormalizerBase.php
    @@ -11,35 +11,23 @@
    +    return in_array($format, (array) $this->format, TRUE);
    

    How is this supposed to work, if you used class::$format?

  2. +++ b/core/modules/hal/src/Normalizer/NormalizerBase.php
    @@ -11,35 +11,23 @@
    -  protected $formats = ['hal_json'];
    ...
    +  protected $format = ['hal_json'];
    

    Oh… you kept the rename. We shouldn't do that, see #23. That's what I was getting at in #32.2.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new3.21 KB
new691 bytes

I'm not sure why we have to take back the rename ... in case we use something like this ... which I actually wanted to include :)

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Now that makes sense :)

dawehner’s picture

Cool :)

br0ken’s picture

+++ b/core/modules/hal/src/Normalizer/NormalizerBase.php
@@ -11,35 +11,24 @@
+    if (isset($this->formats)) {
+      @trigger_error('::formats is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use ::$format instead. See https://www.drupal.org/node/2868275', E_USER_DEPRECATED);
+      return in_array($format, (array) $this->formats, TRUE);

What do you think about replacing return statement here by $this->format = $this->formats to avoid code duplication?

br0ken’s picture

StatusFileSize
new3.06 KB
new884 bytes

Just as an another opinion. In this case user definitely will get triggered an error about deprecation, even if method called with NULL as an argument.

dawehner’s picture

Sure why not.

wim leers’s picture

I like this even better. Even clearer that this method is decorating the parent method, but only for BC, and it'll be removed in 9.0.0.

Thanks, BR0kEN!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 42: 2863778-42.patch, failed testing.

br0ken’s picture

Status: Needs work » Reviewed & tested by the community

Just bringing back RTBC.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.4.x, thanks!

  • catch committed d66888c on 8.4.x
    Issue #2863778 by BR0kEN, dawehner, l0ke, Wim Leers, alexpott, catch:...
wim leers’s picture

Issue tags: +maintainability

Yay, improved maintainability!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

quietone’s picture

publish the change record