Title says it all. There are increasingly many issues being reported against jsonapi_extras that are caused by this incompatibility: #3003023: TypeError: Argument 4 passed to Drupal\jsonapi_extras\... + #2994885: JSONAPI Version Requirements prevent installation via Composer + …

Let's get that fixed.

CommentFileSizeAuthor
#81 on-commit.txt2.84 KBe0ipso
#72 3004582-73.patch37.75 KBwim leers
#72 interdiff.txt1.62 KBwim leers
#70 3004582-70.patch37.63 KBwim leers
#70 interdiff.txt427 byteswim leers
#69 3004582-64-2x.patch38.03 KBwim leers
#64 3004582-64-2x.patch38.03 KBwim leers
#64 interdiff.txt973 byteswim leers
#63 3004582-63-2x.patch37.98 KBwim leers
#63 interdiff.txt7.16 KBwim leers
#61 3004582-61-2x.patch30.87 KBwim leers
#61 interdiff.txt2.59 KBwim leers
#59 3004582-59-2x.patch28.35 KBwim leers
#59 interdiff.txt1.01 KBwim leers
#57 3004582-57-2x.patch27.39 KBwim leers
#57 interdiff.txt421 byteswim leers
#55 3004582-55-2x.patch27.39 KBwim leers
#55 interdiff.txt423 byteswim leers
#53 3004582-53-2x.patch27.34 KBwim leers
#52 interdiff.txt1.72 KBwim leers
#51 3004582-51.patch26.99 KBwim leers
#48 3004582-48.patch27.85 KBwim leers
#48 interdiff.txt4.98 KBwim leers
#47 3004582-47.patch27.52 KBwim leers
#47 interdiff.txt2.64 KBwim leers
#45 3004582-45.patch25.38 KBwim leers
#45 interdiff.txt5.2 KBwim leers
#41 3004582-41.patch20.93 KBwim leers
#41 interdiff.txt2.06 KBwim leers
#37 3004582-36.patch20.88 KBwim leers
#37 interdiff.txt2.56 KBwim leers
#35 3004582-35.patch20.16 KBwim leers
#35 interdiff.txt5.63 KBwim leers
#32 3004582-32.patch15.86 KBwim leers
#32 interdiff.txt1.66 KBwim leers
#29 3004582-28.patch15.84 KBwim leers
#29 interdiff.txt1.07 KBwim leers
#27 3004582-26.patch15.25 KBwim leers
#27 interdiff.txt1.88 KBwim leers
#25 3004582-25.patch13.4 KBwim leers
#25 interdiff.txt3.29 KBwim leers
#24 3004582-24.patch10.69 KBwim leers
#24 interdiff.txt1.14 KBwim leers
#23 3004582-23.patch10.8 KBwim leers
#23 interdiff.txt2.58 KBwim leers
#22 3004582-22.patch8.89 KBwim leers
#22 interdiff.txt905 byteswim leers
#21 jsonapi_createresourcetype_1x-do-not-test.patch2.38 KBwim leers
#21 jsonapi_createresourcetype_2x-do-not-test.patch2.74 KBwim leers
#21 3004582-21.patch8.04 KBwim leers
#21 interdiff.txt4.45 KBwim leers
#3 3004582-3.patch4.36 KBwim leers
#3 interdiff.txt4.13 KBwim leers
#2 3004582-2.patch727 byteswim leers

Comments

Wim Leers created an issue. See original summary.

wim leers’s picture

If one installs jsonapi 1.23 and jsonapi_extras 2.9, then updates from 1.23 to 2.0-beta2 and runs core/rebuild.php, one sees:


Warning: Declaration of Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository::isMutableResourceType(Drupal\Core\Entity\EntityTypeInterface $entity_type) should be compatible with Drupal\jsonapi\ResourceType\ResourceTypeRepository::isMutableResourceType(Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php on line 17

Fatal error: Uncaught TypeError: Argument 4 passed to Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository::__construct() must implement interface Drupal\Core\Entity\EntityRepositoryInterface, instance of Drupal\Core\Cache\MemoryBackend given, called in /Users/wim.leers/Work/d8/core/lib/Drupal/Component/DependencyInjection/Container.php on line 286 and defined in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php:76 Stack trace: #0 /Users/wim.leers/Work/d8/core/lib/Drupal/Component/DependencyInjection/Container.php(286): Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository->__construct(Object(Drupal\Core\Entity\EntityTypeManager), Object(Drupal\Core\Entity\EntityTypeBundleInfo), Object(Drupal\Core\Entity\EntityFieldManager), Object(Drupal\Core\Cache\MemoryBackend), Object(Drupal\Core\Entity\EntityRepository), Object(Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager), Object(Drupal\Core\Config\ConfigFactory)) #1 /Users/wim.leers/ in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php on line 76

Let's look at that warning first. #2995111: shouldBeInternalResourceType et al. should receive the resource type, not the entity type added a new $bundle parameter to isMutableResourceType() (specifically for jsonapi_extras!), but jsonapi_extras was not updated accordingly in #2992557: Inject additional services manually to ConfigurableResourceType.

Easy fix. Compatible with both jsonapi 1.x & 2.x.

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new4.13 KB
new4.36 KB

Now we're down to

Fatal error: Uncaught TypeError: Argument 4 passed to Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository::__construct() must implement interface Drupal\Core\Entity\EntityRepositoryInterface, instance of Drupal\Core\Cache\MemoryBackend given, called in /Users/wim.leers/Work/d8/core/lib/Drupal/Component/DependencyInjection/Container.php on line 286 and defined in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php:76 Stack trace: #0 /Users/wim.leers/Work/d8/core/lib/Drupal/Component/DependencyInjection/Container.php(286): Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository->__construct(Object(Drupal\Core\Entity\EntityTypeManager), Object(Drupal\Core\Entity\EntityTypeBundleInfo), Object(Drupal\Core\Entity\EntityFieldManager), Object(Drupal\Core\Cache\MemoryBackend), Object(Drupal\Core\Entity\EntityRepository), Object(Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager), Object(Drupal\Core\Config\ConfigFactory)) #1 /Users/wim.leers/ in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php on line 76

When running /core/rebuild.php.

This one is a bit trickier. #2984886: Trigger route rebuild when new bundles/fields are added/removed added a new parameter to ResourceTypeRepository in jsonapi's 2.x branch.

jsonapi_extras' ConfigurableResourceTypeRepository, which decorates that same class, must therefore also pass this parameter.

Fortunately, jsonapi 1.x only expects 3 parameters, and will continue to do so. We have two possible solutions here:

  1. Avoid the need to keep the constructors in sync by having the additional services that jsonapi_extras' override ConfigurableResourceTypeRepository needs be injected via setters rather than via the constructor.
  2. Or use Symfony's service decorator feature. This does mean ConfigurableResourceTypeRepository will need to implement all methods required by the interface. It already implements one, but it would then have to start implementing the other two too. This would also require injecting all services that ConfigurableResourceTypeRepository uses, which includes many of those in ResourceTypeRepository. But worse, it'd require mapping every ResourceType object to a ConfigurableResourceType object.

The first option is vastly simpler, even though the second may arguably be better in the long term. I also tried the second approach, but it'd require massive code changes. Perhaps we want to do it in a follow-up issue. But I think we prefer the minimal set of changes to get to a cross-compatible jsonapi_extras module? :)

So, here's that first approach.

wim leers’s picture

Still passing on JSON API 1.x ✅

On 2.x, it's now failing with this output:


Notice: Undefined property: Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository::$all in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php on line 86

Fatal error: Uncaught Error: Call to a member function get() on null in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceType.php:121 Stack trace: #0 /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceType.php(216): Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType->getResourceFieldConfiguration('type', 'fieldName') #1 /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceType.php(41): Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType->translateFieldName('type', 'fieldName', 'publicName') #2 /Users/wim.leers/Work/d8/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php(316): Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType->getPublicName('type') #3 /Users/wim.leers/Work/d8/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php(117): Drupal\jsonapi\ResourceType\ResourceTypeRepository->calculateRelatableResourceTypes(Object(Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType) in /Users/wim.leers/Work/d8/modules/jsonapi_extras/src/ResourceType/ConfigurableResourceType.php on line 121

#2977669: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec causes this failure, because it made this change:

diff --git a/src/ResourceType/ResourceTypeRepository.php b/src/ResourceType/ResourceTypeRepository.php
index 7b3f3eb..9a17ddd 100644
--- a/src/ResourceType/ResourceTypeRepository.php
+++ b/src/ResourceType/ResourceTypeRepository.php
@@ -192,11 +294,17 @@ class ResourceTypeRepository implements ResourceTypeRepositoryInterface {
         $resource_type->getBundle()
       );
 
-      return array_map(function ($field_definition) {
+      $relatable_internal = array_map(function ($field_definition) {
         return $this->getRelatableResourceTypesFromFieldDefinition($field_definition);
       }, array_filter($field_definitions, function ($field_definition) {
         return $this->isReferenceFieldDefinition($field_definition);
       }));
+
+      $relatable_public = [];
+      foreach ($relatable_internal as $internal_field_name => $value) {
+        $relatable_public[$resource_type->getPublicName($internal_field_name)] = $value;
+      }
+      return $relatable_public;
     }
     return [];
   }

That was added in #2977669-69: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec. This was a bugfix to ensure that relatable resource types are discovered using their public name (the "alias") rather than the internal name. Without this, JSON API Extras also didn't work correctly!

This means that \Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType::getPublicName() gets called earlier than it did before. If we look at \Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository::all(), then:

  public function all() {
    if (!$this->all) {
      $all = parent::all(); <--- NOW IT IS CALLED HERE
      array_walk($all, [$this, 'injectAdditionalServicesToResourceType']); <--- PREVIOUSLY IT WAS CALLED HERE
      $this->all = $all;
    }
    return $this->all;
  }

Because of this, ConfigurableResourceType objects do not yet have the additional services injected and hence fail.

Of course, ideally jsonapi_extras would use the built-in aliasing capabilities provided by jsonapi since #2977669: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec rather than layering on its own, as proposed in #2986408: Use aliasing capabilities provided by JSON API 2.x, but doing that would not be compatible with JSON API 1.x.

Solution: still TBD.

wim leers’s picture

So, let's say we comment out that early invocation of ConfigurableResourceType::getPublicName:

diff --git a/src/ResourceType/ResourceTypeRepository.php b/src/ResourceType/ResourceTypeRepository.php
index 359523f..8ee7aa1 100644
--- a/src/ResourceType/ResourceTypeRepository.php
+++ b/src/ResourceType/ResourceTypeRepository.php
@@ -313,7 +313,7 @@ class ResourceTypeRepository implements ResourceTypeRepositoryInterface {
 
       $relatable_public = [];
       foreach ($relatable_internal as $internal_field_name => $value) {
-        $relatable_public[$resource_type->getPublicName($internal_field_name)] = $value;
+//        $relatable_public[$resource_type->getPublicName($internal_field_name)] = $value;
       }
       return $relatable_public;
     }

Where do we get then?

Well … something that is literally impossible to solve:

The website encountered an unexpected error. Please try again later.
LogicException: JSON API does not allow adding more normalizers! in Drupal\jsonapi\Serializer\Serializer->__construct() (line 34 of modules/jsonapi/src/Serializer/Serializer.php).
Drupal\jsonapi\Serializer\Serializer->__construct(Array, Array) (Line: 266)
Drupal\Component\DependencyInjection\Container->createService(Array, 'jsonapi.serializer_do_not_use_removal_imminent') (Line: 171)
Drupal\Component\DependencyInjection\Container->get('jsonapi.serializer_do_not_use_removal_imminent', 1) (Line: 480)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 230)
Drupal\Component\DependencyInjection\Container->createService(Array, 'jsonapi.exception_subscriber') (Line: 171)
Drupal\Component\DependencyInjection\Container->get('jsonapi.exception_subscriber') (Line: 105)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.exception', Object) (Line: 228)
Symfony\Component\HttpKernel\HttpKernel->handleException(Object, Object, 1) (Line: 79)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 129)
Drupal\cdn\StackMiddleware\DuplicateContentPreventionMiddleware->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 669)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

You see, #2936754: Avoid using the Serialization component for JSON API specific tasks explicitly started disallowing custom normalizers:

  public function __construct(array $normalizers = [], array $encoders = []) {
    foreach ($normalizers as $normalizer) {
      if (strpos(get_class($normalizer), 'Drupal\jsonapi\Normalizer') !== 0) {
        throw new \LogicException('JSON API does not allow adding more normalizers!');
      }
    }
    parent::__construct($normalizers, $encoders);
  }

I don't see any way we can fix that. @e0ipso +1'd this at #2936754-26: Avoid using the Serialization component for JSON API specific tasks, but in #32 of that issue, he writes:

This issue purposely breaks JSON API Extras for now. However, we will need to fix this once we come up with the best pattern.

I … am not sure what this means. @e0ipso, can you explain what you meant?

gabesullice’s picture

@Wim Leers, re: #5, I just found a way to do something similar here: https://cgit.drupalcode.org/jsonapi_hypermedia/commit/?id=a4477cf5af177c...

Since the JSON API serializer "falls back" to the regular serialization system, I think we can play a little trick. If we use a CompilerPass, we can remove the JSON API normalizers that we want to override, then, we'll set a very high priority on the Extras normalizer and register them into the default serializer using the tag normalizer instead of jsonapi_normalizer_do_not_use_removal_imminent.

Then when normalization happens, the JSON API serializer will find no applicable normalizer and "fall back" to the Extras normalizers.

Now, here's the tricky bit... once we "fall back", the serializer that is set inside the Extras normalizers will no longer the JSON API one, it'll be the JSON API one. Meaning that we've completely exited the world of JSON API normalization. That happens because the normalizers all have SerializerAwareTrait on them. When those normalizers are added to a serializer, the serializer calls $normalizer->setSerializer($this); on each one of them.

Why is that a problem? Because JSON API Extras overrides JSON API's EntityNormalizer, which calls $this->serializer->normalizer($field). If $this->serializer isn't the JSON API serializer, we'll have a broken system.

What we need to do, somehow, is make sure that instead of the standard serializer being set on the Extras normalizers, the JSON API serializer is set. I think we can do this by overriding the setSerializer() method. Hopefully, we can just turn it into a no-op method and set $this->serializer in the constructor. That might cause a loop in the DI container though, in which case we'll need to probably do something even uglier.

wim leers’s picture

This … doesn't sound very reliable and definitely not easy to understand/maintain. I do very much appreciate that you're trying to help to move this along though :)

e0ipso’s picture

However, we will need to fix this once we come up with the best pattern.

What I meant is that we may need to allow some extensibility from within JSON API… or we can come up with a creative/clever solution.

@gabesullice shows a possible path in #6. Another idea is to provide a class map in composer.json that will allow us to have classes namespaced by \Drupal\jsonapi\Normalizers inside the JSON API Extras module. That'd be a succinct solution, although like #6 it violates the principle of least astonishment. I'm not sure we can have a creative/clever solution without being astonishing.

The other possible path is to find a different solution to #2936754: Avoid using the Serialization component for JSON API specific tasks that allows us to add these normalizers.

gabesullice’s picture

This … doesn't sound very reliable and definitely not easy to understand/maintain.

I completely agree. But it is a solution and a step forward from being something that "is literally impossible to solve."

Unfortunately, I think that is a right solution here. Not as long as the existing JSON API serialization system is as complex as it is and as long as we feel unsafe opening up for extension.

I think my proposal is a stop-gap and we can solve this in the right way when we refactor or replace the JSON API serialization system.

wim leers’s picture

Another idea is to provide a class map in composer.json that will allow us to have classes namespaced by \Drupal\jsonapi\Normalizers inside the JSON API Extras module.

WOAH

I'm not sure we can have a creative/clever solution without being astonishing.

😂

I was personally looking into how we could do the work we want to do in a different phase. I was looking at \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::renderResponseBody(), whrere we're dealing with a JsonApiDocumentTopLevelNormalizerValue instance. That feels like it could be the place where we can reliably do this. I don't know how yet exactly though.

gabesullice’s picture

a class map in composer.json that will allow us to have classes namespaced by \Drupal\jsonapi\Normalizers inside the JSON API Extras module.

I went pretty far down this path in my first attempt within jsonapi_hypermedia. I can't say it's impossible, but I can say that I was not able to make it work in a few hours of tinkering.

wim leers’s picture

I think my proposal is a stop-gap and we can solve this in the right way when we refactor or replace the JSON API serialization system.

It is!

But before embarking on that path I'd just want all three of us to have spent a day or two pondering the problem. See my suggestion in #10 for a different direction (although unlike your direction, it doesn't have a concrete working proposal yet).

e0ipso’s picture

Also worth noting, that if normalizers were tracking schema, then I'd feel much better on allowing others to add normalizers for JSON API.

I've been wanting to take a bite to that issue for a long time.

gabesullice’s picture

\Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::renderResponseBody(), whrere we're dealing with a JsonApiDocumentTopLevelNormalizerValue instance. That feels like it could be the place where we can reliably do this.

I think this will lead to a lot of new code that we'll need to write for JSON API Extras. That seems out of the scope here, which is just getting Extras to be compatible so we can release an JSON API 2.x RC.

I'll say this: I do agree that that would be a very clean place to inject something. I might even go a step further and say that Extras could simply have its own KernelEvents::RESPONSE subscriber to be completely separated from JSON API.

In essence, your suggestion will force JSON API Extras to work only on the "rasterized" array representing the entire JSON API document. IOW, Extras will need to operate on big, multi-dimensional arrays rather than just the typed objects where it has overridden things in a targeted way (i.e. the EntityNormalizer is called once for every entity). OTOH, working with "reshaping" arrays is exactly how @e0ipso's shaper library works, so maybe that'd be okay... It seems like a lot to tackle though.

I don't believe this issue is the place to start down the road of such a large re-architecture.

But before embarking on that path I'd just want all three of us to have spent a day or two pondering the problem.

I will definitely keep pondering :P

gabesullice’s picture

FWIW, \Drupal\jsonapi_extras\Normalizer\FieldItemNormalizer already overrides setSerializer, which was the hairiest part of my #6 proposal.

e0ipso’s picture

Thanks for the awesome job you are doing here!

Of course, ideally jsonapi_extras would use the built-in aliasing capabilities provided by jsonapi since #2977669: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec rather than layering on its own, as proposed in #2986408: Use aliasing capabilities provided by JSON API 2.x, but doing that would not be compatible with JSON API 1.x.

I think this makes it clear that we want to have a dedicated branch jsonapi_extras-3.x for compatibility with jsonapi-2.x. Unless anyone disagrees we can move forward with that assumption. @Wim Leers thanks for finding the exact thing that makes us do the thing we suspected we'd have to do.

wim leers’s picture

#14:

In essence, your suggestion will force JSON API Extras to work only on the "rasterized" array representing the entire JSON API document.

That is one possibility. The other possibility is that jsonapi_extras runs its own response subscriber before jsonapi's, so it can modify the JsonApiDocumentTopLevel object before it gets normalized into a JsonApiDocumentTopLevelNormalizerValue object by \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::renderResponseBody(). That seems simpler/more reliable for jsonapi_extras.

#16:

I think this makes it clear that we want to have a dedicated branch jsonapi_extras-3.x for compatibility with jsonapi-2.x. Unless anyone disagrees we can move forward with that assumption. @Wim Leers thanks for finding the exact thing that makes us do the thing we suspected we'd have to do.

I don't think it's a hard requirement, but I do think it'll make jsonapi_extras a lot easier to maintain. Because #2977669: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec effectively moved a significant portion of the infrastructure that jsonapi_extras needs into jsonapi itself, which means it has to do far less work!

So yes, I personally do think it's worth creating a new branch of jsonapi_extras, because it will make it a lot easier to maintain.

wim leers’s picture

Been working on this all day. Update later tonight, and if not tonight, then tomorrow.

e0ipso’s picture

Exciting!

wim leers’s picture

I had something workable for solving #5's first problem earlier today, but it was 2.x-only. I could make it work with 1.x too, but then we'd need 1.x to change, which then still means you need to update more things, which still means no nice smooth update path.

I now managed to get something to work that allows jsonapi_extras 2.x to continue to work with any existing 1.x site, and start working with 2.x. It will require a small change in JSON API 2.x. Super small. Super trivial. And it'll allow JSON API Extras to become simpler in the future, when it drops 1.x support.

I did not yet solve the normalizer problem though. Still, exciting to see that I might be able to not require a new branch!

Need to call it a day now though. More tomorrow!

wim leers’s picture

We can solve the first problem described in #5 by making it possible for ConfigurableResourceTypeRepository (JSON API Extras' override) to create the "correct" ResourceType value objects the first time, rather than relying on decoration first.
To do that, we also need to provide a $field_mapping parameter, which the big hunk in #2986408-2: Use aliasing capabilities provided by JSON API 2.x gets us.

Now, the early call to $resource_type->getPublicName() no longer causes a problem :)

Best of all: I can make this work on both 1.x and 2.x if we either apply the attached jsonapi_* patches to the respective branches, or if we keep the 2.x detection logic in this interdiff. Keeping the 2.x detection logic is preferable because it significantly simplifies the update path for sites on JSON API 1.x today: they can first update JSON API Extras and then update JSON API from 1.x to 2.x at any time of their choosing.

Compatible with 1.x and 2.x.

wim leers’s picture

Related issues:
StatusFileSize
new905 bytes
new8.89 KB

New problem (on 2.x):

The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">LogicException</em>: The database connection is not serializable. This probably means you are serializing an object that has an indirect reference to the database connection. Adjust your code so that is not necessary. Alternatively, look at DependencySerializationTrait as a temporary solution. in <em class="placeholder">Drupal\Core\Database\Connection-&gt;__sleep()</em> (line <em class="placeholder">1481</em> of <em class="placeholder">core/lib/Drupal/Core/Database/Connection.php</em>). <pre class="backtrace">serialize(Array) (Line: 109)
Drupal\Core\Cache\MemoryBackend-&gt;set(&#039;jsonapi.resource_types&#039;, Array, -1, Array) (Line: 110)
Drupal\jsonapi\ResourceType\ResourceTypeRepository-&gt;all() (Line: 112)
Drupal\jsonapi\Routing\Routes-&gt;routes()
call_user_func(Array) (Line: 146)
Drupal\Core\Routing\RouteBuilder-&gt;rebuild() (Line: 83)
Drupal\Core\ProxyClass\Routing\RouteBuilder-&gt;rebuild() (Line: 1158)
drupal_flush_all_caches() (Line: 192)
Drupal\system\Form\PerformanceForm-&gt;submitCacheClear(Array, Object)
call_user_func_array(Array, Array) (Line: 111)
Drupal\Core\Form\FormSubmitter-&gt;executeSubmitHandlers(Array, Object) (Line: 51)
Drupal\Core\Form\FormSubmitter-&gt;doSubmitForm(Array, Object) (Line: 589)
Drupal\Core\Form\FormBuilder-&gt;processForm(&#039;system_performance_settings&#039;, Array, Object) (Line: 318)
Drupal\Core\Form\FormBuilder-&gt;buildForm(&#039;system_performance_settings&#039;, Object) (Line: 93)
Drupal\Core\Controller\FormController-&gt;getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-&gt;Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer-&gt;executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-&gt;wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-&gt;Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel-&gt;handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel-&gt;handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session-&gt;handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle-&gt;handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware-&gt;handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware-&gt;handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel-&gt;handle(Object, 1, 1) (Line: 669)
Drupal\Core\DrupalKernel-&gt;handle(Object) (Line: 19)
</pre>

Because as of #2995111: shouldBeInternalResourceType et al. should receive the resource type, not the entity type, the (Configurable)ResourceType objects are being stored in a static cache. Doing this results in the services injected into ConfigurableResourceType to be serialized as well. (Because it's not a true value object anymore due to those services.) use DependencySerializationTrait; to the rescue!

wim leers’s picture

StatusFileSize
new2.58 KB
new10.8 KB

Several methods can be removed when only 2.x is supported by jsonapi_extras. But that's explicitly not the goal of this issue!

Still, while we're working on this, we should add @todos to mark those things for removal to make things simpler in the future. It also gives us a sense of how much simpler things become once jsonapi_extras only supports jsonapi 2.x.

wim leers’s picture

StatusFileSize
new1.14 KB
new10.69 KB

One method already was 2.x-only, and is no longer necessary in a world where there is a ::createResourcetype(). :) Slight simplification, yay!

wim leers’s picture

StatusFileSize
new3.29 KB
new13.4 KB

My \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::renderResponseBody()-based proposal for solving the remaining problem (normalizers) actually only solves half the problem: it only works for normalization, not denormalization.

So, I started to implement the work-around @gabesullice proposed in #6. One thing he didn't foresee is that it's actually not possible to remove the serializer.normalizer.field_item.jsonapi serializer, because serializer.normalizer.field_item.jsonapi_extras decorates it! And similarly, we need JSON API Extras' subclasses to pass all necessary parameters to the other two overridden normalizers, which means they need to be inherited to be able to work on both 1.x and 2.x. That means that rather than removing, we can make them private untagged services.

His other key prediction, about us somehow needing to make sure JSON API Extras' EntityNormalizer uses JSON API's serializer did come true though. I solved that by inheriting jsonapi's FieldItemList normalizer into the core's serializer, with a similarly high priority. This means it gets selected in lieu of core's ListNormalizer, and hence keeps things working fine.

Best of all: while this approach is necessary for jsonapi 2.x, it also works fine for 1.x. So we don't need conditional logic between 1.x and 2.x here!

Status: Needs review » Needs work

The last submitted patch, 25: 3004582-25.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new1.88 KB
new15.25 KB

Finally: since #2955615: Field properties are not being denormalized, the signature of the protected ::prepareInput() changed. It makes sense to not have warnings on 2.x, especially because it actually uses that additional data. There can be warnings on JSON API 1.x, but they're harmless.

Status: Needs review » Needs work

The last submitted patch, 27: 3004582-26.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

StatusFileSize
new1.07 KB
new15.84 KB

Fix CS violations.

wim leers’s picture

Assigned: wim leers » Unassigned

I need to run now. Sadly, with this patch still red.

I never ran these tests locally, I instead actually used JSON API, both 1.x and 2.x, with the following JSON API Extras customizations turned on:

  • custom base path
  • collection count enabled
  • a field aliased

And it works!

It'd be great if somebody else could fix those last few failures. I'd LOVE to see this committed in the next few days and hopefully even today!

wim leers’s picture

Assigned: Unassigned » wim leers
Status: Needs work » Needs review
StatusFileSize
new1.66 KB
new15.86 KB

Could it be this simple? This appears to satisfy PHP on both JSON API 1.x and 2.x.

Status: Needs review » Needs work

The last submitted patch, 32: 3004582-32.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new5.63 KB
new20.16 KB

The remaining failures in EntityToJsonApiTest are legitimate. That test was introduced in [#29842455].

Ever since #2971040: PHP 7.1 Compatibility Warning, in the JSON API 2.x branch, the JsonApiDocumentTopLevel class was moved to be compatible with PHP 7.2. So we need to conditionally use the correct class. That's easy enough.

But on top of that, the constructor of the JsonApiDocumentTopLevel class evolved in the 2.x branch: it now requires more parameters.

Status: Needs review » Needs work

The last submitted patch, 35: 3004582-35.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new2.56 KB
new20.88 KB

After fixing that, turns out that the changes so far are somehow causing relationships to be normalized differently (incorrectly). It took some debugging, but then in hindsight it was obvious: increasing the service priorities in #25 cause \Drupal\jsonapi\Normalizer\FieldNormalizer to be picked instead of \Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer for entity reference fields. I was able to fix that by also decorating serializer.normalizer.entity_reference_field.jsonapi. But then I had to also decorate serializer.normalizer.entity_reference_item.jsonapi. And more and more …

So, time to go back to @gabesullice's original proposal:

What we need to do, somehow, is make sure that instead of the standard serializer being set on the Extras normalizers, the JSON API serializer is set. I think we can do this by overriding the setSerializer() method. Hopefully, we can just turn it into a no-op method and set $this->serializer in the constructor. That might cause a loop in the DI container though, in which case we'll need to probably do something even uglier.

Now at least EntityToJsonApiTest is passing!

Status: Needs review » Needs work

The last submitted patch, 37: 3004582-36.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Assigned: wim leers » Unassigned

Now at least EntityToJsonApiTest is passing!

The test run confirms this.

Next up: a circular reference to be solved. Symfony's error message is (as usual) utterly useless: it says

Circular reference detected for service "serializer", path: "jsonapi.request_handler -> serializer".

But the circle is triggered like so: jsonapi.request_handler -> serializer -> serializer.normalizer.entity.jsonapi_extras -> jsonapi.serializer_do_not_use_removal_imminent -> serializer i.e. the serializer.normalizer.entity.jsonapi_extras is created by serializer but also has that as one of its dependencies.

So: time for something even uglier! Hopefully @gabesullice can do that while I sleep, otherwise I'll do it tomorrow.

wim leers’s picture

Assigned: Unassigned » wim leers

On this again.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new2.06 KB
new20.93 KB

Fixing the CS violations is easy of course, but the circular dependency will require some more thought, tinkering and cursing.

Status: Needs review » Needs work

The last submitted patch, 41: 3004582-41.patch, failed testing. View results

e0ipso’s picture

Thanks for the hard battle you're fighting on this @Wim Leers!

wim leers’s picture

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new5.2 KB
new25.38 KB

I managed to find a work-around :)

Now all tests should pass on jsonapi 1.x.

Status: Needs review » Needs work

The last submitted patch, 45: 3004582-45.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new2.64 KB
new27.52 KB

Fixed the failure in EntityToJsonApiTest.

And gahhhhhhhh 😭 JsonExtrasApiFunctionalTest::testWrite() is passing fine locally! Added debug output.

wim leers’s picture

StatusFileSize
new4.98 KB
new27.85 KB

Fixed CS violations and refactored the decorator to be less sensitive to typos.

The last submitted patch, 47: 3004582-47.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 48: 3004582-48.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new26.99 KB

Looks like the refactoring of the decorator in #48 actually fixed it. That also explains why I couldn't reproduce it locally!

Removing debug output and fixing newly introduced CS violations.

🤞

wim leers’s picture

StatusFileSize
new1.72 KB

D'oh.

wim leers’s picture

StatusFileSize
new27.34 KB

FINALLY!

Now, let's see what happens when running this against JSON API 2.x. I think this is how I can get it to run against 2.x, let's see …

Status: Needs review » Needs work

The last submitted patch, 53: 3004582-53-2x.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new423 bytes
new27.39 KB

It's using 2.0-beta2, but we need it to install 54f560dea96c1cdd32165e23639cb19bc588134f, which includes #3006270: Add ResourceTypeRepository::createResourceType() for easier JSON API Extras support and simpler code.

Status: Needs review » Needs work

The last submitted patch, 55: 3004582-55-2x.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new421 bytes
new27.39 KB

AARGH JSON …

Rather than me being able to come back after lunch to a useful test run, now I need to wait again. 😡

Status: Needs review » Needs work

The last submitted patch, 57: 3004582-57-2x.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new1.01 KB
new28.35 KB

Finally, a test run of JSON API Extras against JSON API 2.x!

1) Drupal\Tests\jsonapi_extras\Functional\JsonExtrasApiFunctionalTest::testRead
Exception: Notice: A non well formed numeric value encountered
Drupal\jsonapi_extras\Plugin\jsonapi\FieldEnhancer\DateTimeEnhancer->doUndoTransform()() (Line: 24)

Per https://www.drupal.org/node/2982678, we need to make the datetime enhancer a bit smarter.

Status: Needs review » Needs work

The last submitted patch, 59: 3004582-59-2x.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new2.59 KB
new30.87 KB

Still same failure count, but failing later:

There was 1 error:

1) Drupal\Tests\jsonapi_extras\Functional\JsonExtrasApiFunctionalTest::testRead
Behat\Mink\Exception\ExpectationException: Current response status code is 200, but 404 expected.

/var/www/html/vendor/behat/mink/src/WebAssert.php:770
/var/www/html/vendor/behat/mink/src/WebAssert.php:130
/var/www/html/modules/contrib/jsonapi_extras/tests/src/Functional/JsonExtrasApiFunctionalTest.php:182

--

There was 1 failure:

1) Drupal\Tests\jsonapi_extras\Functional\JsonExtrasApiFunctionalTest::testWrite
Failed asserting that 'http://php-apache-jenkins-drupal8-contrib-patches-39924/subdirectory/api/articles/e54aeede-efee-49ca-aeb9-da8c7a6ade48' is identical to Array &0 (
    'href' => 'http://php-apache-jenkins-drupal8-contrib-patches-39924/subdirectory/api/articles/e54aeede-efee-49ca-aeb9-da8c7a6ade48'
).

That's happening here:

    // 13. Test a disabled related resource of single cardinality.
    $this->drupalGet('/api/taxonomy_term/tags/' . $this->tags[0]->uuid() . '/vid');
    $this->assertSession()->statusCodeEquals(404);
    $this->drupalGet('/api/taxonomy_term/tags/' . $this->tags[0]->uuid() . '/relationships/vid');
    $this->assertSession()->statusCodeEquals(404);

Which passes on 1.x but not on 2.x. Because #2953346: Define related/relationship routes per field, not dynamically (with route parameters that need validating) changed how this is handled: the related route is still not created in case all target resource types are internal, but the relationship route is created, meaning this now results in a 200 response with 'data' : null in the response document. The 2.x branch does this differently since #2953346, specifically since #2953346-26: Define related/relationship routes per field, not dynamically (with route parameters that need validating). This change was not explicitly discussed. If we want to reconsider this, we can open a jsonapi issue. For now, I'm just adding a 2.x-specific test expectation.

Status: Needs review » Needs work

The last submitted patch, 61: 3004582-61-2x.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new7.16 KB
new37.98 KB

Let's look at the other failures, those in Drupal\Tests\jsonapi_extras\Kernel\Controller\EntityResourceTest.

They're easy to fix by adding 2.x and 1.x logic.

wim leers’s picture

StatusFileSize
new973 bytes
new38.03 KB

Looks like I made a c/p error in #61.

The last submitted patch, 63: 3004582-63-2x.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 64: 3004582-64-2x.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review

Last failure!

There was 1 error:

1) Drupal\Tests\jsonapi_extras\Functional\JsonExtrasApiFunctionalTest::testWrite
Undefined index: data

/var/www/html/modules/contrib/jsonapi_extras/tests/src/Functional/JsonExtrasApiFunctionalTest.php:299

ERRORS!
Tests: 2, Assertions: 55, Errors: 1.

If we look at the actual response, we get:

array(2) {
  ["errors"]=>
  array(1) {
    [0]=>
    array(4) {
      ["title"]=>
      string(11) "Bad Request"
      ["status"]=>
      int(400)
      ["detail"]=>
      string(88) "The provided type (taxonomy_term--tags) does not mach the destination resource types ()."
      ["links"]=>
      array(2) {
        ["via"]=>
        array(1) {
          ["href"]=>
          string(78) "http://d8/api/articles/071913b6-6d90-42be-845e-90d337bedc28/relationships/tags"
        }
        ["info"]=>
        array(1) {
          ["href"]=>
          string(64) "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1"
        }
      }
    }
  }
  ["jsonapi"]=>
  array(2) {
    ["version"]=>
    string(3) "1.0"
    ["meta"]=>
    array(1) {
      ["links"]=>
      array(1) {
        ["self"]=>
        array(1) {
          ["href"]=>
          string(30) "http://jsonapi.org/format/1.0/"
        }
      }
    }
  }
}

Note how there are zero destination resource types: ()!

Turns out this is because ever since JSON API 2.x gained a "field mapping" (for aliasing and disabling fields), we did not correctly update the relationship normalizer accordingly. AFAICT I introduced this in #2977669: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec. That issue resulted in far less probability of JSON API Extras breaking wrt disabling/aliasing of fields, because JSON API itself now does this. But in the case of JSON API, the fields we happen to alias automatically are all relationships to the corresponding bundle. And that just happens to be the one field that is in fact optional in a POST request. In other words: we only gained normalization test coverage in JSON API, not denormalization. The one case where it is now failing is in denormalization of relationships! i.e. when you POST or PATCH a RESOURCETYPE/relationships/RELATIONSHIPNAME route.
Since you cannot change a resource's bundle, and the bundle field is the only relationship that is automatically aliased by jsonapi, we'll need jsonapi to create a regression test for this.

wim leers’s picture

Title: Make JSON API Extras 2.x (next release: 2.10) compatible with JSON API 2.0-beta2 » [PP-1] Make JSON API Extras 2.x (next release: 2.10) compatible with JSON API 2.0-beta2
Status: Needs review » Postponed
Related issues: +#3007113: Follow-up for #2977669: denormalizing aliased relationships fails
wim leers’s picture

Title: [PP-1] Make JSON API Extras 2.x (next release: 2.10) compatible with JSON API 2.0-beta2 » Make JSON API Extras 2.x (next release: 2.10) compatible with JSON API 2.0-beta2
Status: Postponed » Needs review
StatusFileSize
new38.03 KB
wim leers’s picture

Assigned: wim leers » Unassigned
StatusFileSize
new427 bytes
new37.63 KB

#69 is green against jsonapi 2.x.
#51 was green against jsonapi 1.x, and so will this patch.

This is now in @gabesullice's hands for review, and especially in @e0ipso's!

e0ipso’s picture

Very close already!


  1. +++ b/src/EntityToJsonApi.php
    @@ -77,6 +81,9 @@ class EntityToJsonApi {
    +    $this->classToUse = ConfigurableResourceTypeRepository::isJsonApi2x()
    +      ? '\Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel'
    +      : '\Drupal\jsonapi\Resource\JsonApiDocumentTopLevel';
    

    This is brittle, but I suspect we'll have to live with it.

  2. +++ b/src/EntityToJsonApi.php
    @@ -91,7 +98,14 @@ class EntityToJsonApi {
    +    $referenced_entities = [];
    +    foreach ($includes as $field_name) {
    +      $referenced_entities = array_merge($referenced_entities, $entity->get($field_name)->referencedEntities());
    +    }
    

    Maybe a copy & paste leftover from normalize()? I don't see $referenced_entities being used in the method in this diff.

  3. +++ b/src/EntityToJsonApi.php
    --- a/src/JsonapiExtrasServiceProvider.php
    +++ b/src/JsonapiExtrasServiceProvider.php
    
    +++ b/src/JsonapiExtrasServiceProvider.php
    +++ b/src/JsonapiExtrasServiceProvider.php
    @@ -23,11 +23,29 @@ class JsonapiExtrasServiceProvider extends ServiceProviderBase {
    

    Everything in here is very clever. I can see that this took a long time to brew.

    Great work!

  4. +++ b/src/ResourceType/ConfigurableResourceType.php
    @@ -36,6 +39,8 @@ class ConfigurableResourceType extends ResourceType {
    +   * @todo Remove this when JSON API Extras drops support for JSON API 1.x.
    

    Thanks for this. It will be incredibly useful some day in the future.

  5. +++ b/src/ResourceType/ConfigurableResourceTypeRepository.php
    @@ -102,12 +126,50 @@ class ConfigurableResourceTypeRepository extends ResourceTypeRepository {
    +   * Mostly the same, with two key differences:
    

    Please elaborate on the comment. I wondered Mostly the same as what?

  6. +++ b/src/SerializerDecorator.php
    @@ -0,0 +1,140 @@
    +  protected function relay($method_name, array $args) {
    +    $this->lazilyInitialize();
    ...
    +  }
    ...
    +  }
    

    I don't feel great about this pattern. I think it adds some unnecessary magic. However I'm ready to buy it if you tell me how is this better over:

    /**
     * {@inheritdoc}
     */
      public function decode($data, $format, array $context = []) {
        return $this->decoratedSerializer->decode($data, $format, $context);
      }
    
wim leers’s picture

StatusFileSize
new1.62 KB
new37.75 KB
  1. ✔️ I agree with you in principle. But considering that that class was moved to a new namespace to be compatible with PHP 7.2, JSON API 2.x had no choice, and hence we don't have any choice here to support both. Once JSON API Extras stops supporting JSON API 2.x, all of this goes away :)
  2. 👍 Good catch, fixed!
  3. ❤️
  4. ❤️
  5. 👍 Good catch, fixed!
  6. 🤔 You say "unnecessary", but I say "it PREVENTS silly typos and oversights". I introduced this in #48, and it immediately fixed failures in #47 that were the consequence of getting some details wrong. (The failure count reported here for those patches is inaccurate, look at the actual test output: #47 had one actual failure, #48 had zero actual failures but just printed debug output which somehow gets counted as 2 failures…)

    I don't feel strongly about this though — I'm happy to do what you describe. That's what I was originally doing in #47 too.

e0ipso’s picture

I don't feel strongly about this

.

This resembles a lot to __call, but we cannot use __call because then we don't comply with the interfaces without Reflection conjurations. I have a preference for explicitness, but I see your point about typos.

I'm OK with leaving it as is.

wim leers’s picture

because then we don't comply with the interfaces without Reflection conjurations

Indeed.

have a preference for explicitness, but I see your point about typos.

I share that preference. But above anything else, I care about correctness and reliability. This is explicitly (without crazy hacks) relaying a call to another object. I think this is still equally explicit, at the cost of requiring to understand two relatively advanced PHP features: call_user_func_array() and func_get_args().

I'm OK with leaving it as is.

So then … what remains to be done for this to land? :)

I'm perfectly fine with you still preferring not using call_user_func_array() and func_get_args(). Your decision.

e0ipso’s picture

I'm ready to merge this. I'm just giving it time for @gabesullice to wake up and give it a quick look before merging.

wim leers’s picture

👍

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community
  1. +++ b/jsonapi_extras.services.yml
    @@ -6,18 +6,20 @@ services:
    +    calls:
    +      - [setSerializer, ['@jsonapi.serializer_do_not_use_removal_imminent']]
    
    +++ b/src/Normalizer/ContentEntityNormalizer.php
    @@ -11,4 +12,17 @@ class ContentEntityNormalizer extends JsonapiContentEntityNormalizer {
    +    // The second invocation is made by the Serializer service constructor, it
    +    // does not respect the service definition. We ignore this call.
    

    Ah, I was wondering how you would handle that. Looks good.

  2. +++ b/src/Normalizer/EntityNormalizerTrait.php
    @@ -16,11 +16,19 @@ trait EntityNormalizerTrait {
    +   *   (optional) Format the given data was extracted from. Only required for
    

    "Format from which the given data was extracted."

    Can be fixed on commit.

  3. +++ b/src/Plugin/jsonapi/FieldEnhancer/DateTimeEnhancer.php
    @@ -21,7 +22,10 @@ class DateTimeEnhancer extends DateTimeEnhancerBase {
    +    $date->setTimestamp(is_int($data)
    +      ? $data
    +      : (new DrupalDateTime($data))->getTimestamp()
    +    );
    

    Nit: I think 1 line would be more readable.

  4. +++ b/src/ResourceType/ConfigurableResourceTypeRepository.php
    @@ -71,28 +63,60 @@ class ConfigurableResourceTypeRepository extends ResourceTypeRepository {
    +   * One of the BC breaks in 2.x is the removal of JSON API 1.x's custom
    +   * computed "url" field to File entities. Hence its presence or absence is
    +   * also a very reliable detection mechanism.
    ...
    +  public static function isJsonApi2x() {
    +    return !class_exists('\Drupal\jsonapi\Field\FileDownloadUrl');
    +  }
    

    Let's make a followup to ensure that this will be true even after JSON API is in core but 1.x is installed in contrib.


LGTM. I don't think anything above should block a merge, the things I've mentioned can be fixed on commit or done in a followup.

wim leers’s picture

🎉

  • e0ipso committed 058197b on 8.x-2.x authored by Wim Leers
    Issue #3004582 by Wim Leers: Make JSON API Extras 2.x (next release: 2....
  • e0ipso committed 101c55b on 8.x-2.x authored by Wim Leers
    Issue #3004582 by Wim Leers: Make JSON API Extras 2.x (next release: 2....
  • e0ipso committed 213f91f on 8.x-2.x authored by Wim Leers
    Issue #3004582 by Wim Leers: Make JSON API Extras 2.x (next release: 2....
  • e0ipso committed 3434a88 on 8.x-2.x authored by Wim Leers
    Issue #3004582 by Wim Leers, e0ipso, gabesullice: Make JSON API Extras 2...
  • e0ipso committed c19b7f9 on 8.x-2.x authored by Wim Leers
    Issue #3004582 by Wim Leers: Make JSON API Extras 2.x (next release: 2....
  • e0ipso committed f1be472 on 8.x-2.x authored by Wim Leers
    Issue #3004582 by Wim Leers: Make JSON API Extras 2.x (next release: 2....
e0ipso’s picture

Status: Reviewed & tested by the community » Fixed
StatusFileSize
new2.84 KB

Fixed.

Multiple commit credits for @Wim Leers. You rock.

I made some changes on commit.

wim leers’s picture

Woot! Also great to see https://www.drupal.org/project/jsonapi_extras/releases/8.x-2.10 already released. Thank you, @e0ipso! :)

ndobromirov’s picture

Super!

Will be testing this one soon along with jsonapi 2.x :).
We are struggling with single node views with many relationships and includes.
This issue was a blocker for the migration to the new version.

wim leers’s picture

This issue was a blocker for the migration to the new version.

Exciting! :D

Note that you cannot use 2.0-beta2, you need the version after that (not yet released), or the latest dev snapshot. Because #3006270: Add ResourceTypeRepository::createResourceType() for easier JSON API Extras support and simpler code is needed.

stevieb’s picture

I tried installing JSON API Extras 8.x-2.10 & 8.x-2.x-dev using composer both failed
with the following releases JSON API 8.x-2.0-rc1 & 8.x-2.x-dev

the composer output says only JSON API 8.x-1/dev are compattable

wim leers’s picture

the composer output says only JSON API 8.x-1/dev are compattable

Probably due to to "drupal/jsonapi": "^1.22", then.

@stevieb, could you open a new issue for this? Thanks!

wim leers’s picture

Status: Fixed » Closed (fixed)

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