Hello,

I am testing Drupal 8.8.0-alpha1 and get the following error:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function Drupal\jsonapi\ResourceType\ResourceTypeRepository::__construct(), 4 passed in /project/www/modules/contrib/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php on line 92 and exactly 5 expected in /project/www/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php:107
Stack trace:
#0 /project/www/modules/contrib/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php(92): Drupal\jsonapi\ResourceType\ResourceTypeRepository->__construct(Object(Drupal\Core\Entity\EntityTypeManager), Object(Drupal\Core\Entity\EntityTypeBundleInfo), Object(Drupal\Core\Entity\EntityFieldManager), Object(Drupal\Core\Cache\BackendChain))
#1 /project/www/core/lib/Drupal/Component/DependencyInjection/Container.php(285): Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository->__construct(Object(Drupal\Core\Entity\EntityTypeManager), Object(Drupal\Core\Entity\EntityTypeBundleInfo), Object(Drupal\Core\Entity\EntityFieldMan in /project/www/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php on line 107

Patch incoming.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Grimreaper created an issue. See original summary.

Grimreaper’s picture

Here is the patch, thanks for the review.

damontgomery’s picture

I was just looking at this. The patch in #2 works for me.

I'm not sure if this is the right place for this, but I found another bug / incompatibility with 8.8.0-alpha1.

- Overwrite a node resource
- Change the Resource Type, example: `node--article` to `article`
- Save
- Clear the cache, `drush cr`

```
PHP Fatal error: Uncaught TypeError: Argument 2 passed to Drupal\jsonapi\Routing\Routes::Drupal\jsonapi\Routing\{closure}() must be an instance of Drupal\jsonapi\ResourceType\ResourceType, null given in /var/www/my_site/docroot/core/modules/jsonapi/src/Routing/Routes.php:434
Stack trace:
#0 [internal function]: Drupal\jsonapi\Routing\Routes::Drupal\jsonapi\Routing\{closure}(false, NULL)
#1 /var/www/my_site/docroot/core/modules/jsonapi/src/Routing/Routes.php(436): array_reduce(Array, Object(Closure), false)
#2 /var/www/my_site/docroot/core/modules/jsonapi/src/Routing/Routes.php(339): Drupal\jsonapi\Routing\Routes::hasNonInternalTargetResourceTypes(Array)
#3 /var/www/my_site/docroot/core/modules/jsonapi/src/Routing/Routes.php(183): Drupal\jsonapi\Routing\Routes::getIndividualRoutesForResourceType(Object(Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType))
#4 /var/www/my_site/docroot/core/modules/jsonapi/src/Routing/Routes.php(116): Drupal\jsonapi\Routing\Routes::getRout in /var/www/my_site/docroot/core/modules/jsonapi/src/Routing/Routes.php on line 434
```

I'm not sure what was causing that issue but it might be related to https://www.drupal.org/project/drupal/issues/2996114.

Grimreaper’s picture

Status: Needs review » Needs work

Thanks @damontgomery for the feedback.

I am also writing automated tests on #3064320: Pathauto support, And I got problems with jsonapi_extras on Core 8.8.0-alpha1.

So I guess there are other places to fix.

dorficus’s picture

The problem @danmontgomery mentioned is a core issue here: https://www.drupal.org/project/drupal/issues/2996114 that is causing this error.

damontgomery’s picture

Thanks @dorficus and @Grimreaper.

Is it worth updating this issue to limit the scope to the issue you fixed and then having new issues for the other problems?

I've been using your patch for a few days and it seems to be working on our work-in-progress site.

Thanks.

dorficus’s picture

I just started using the patch and it's doing what it should be. We're also developing a WIP site that is right on that cusp of 8.7.x and 8.8.x and I want to get some of the functions from 8.8.x. This is the only blocker, but the patch works for me.

@Grimreaper, what errors are you getting when testing pathauto?

Grimreaper’s picture

@dorficus.

I was trying to reproduce my bugs with #3089850: Tests: Pathauto support. But I can't sorry.

So yes, the scope of the issue can be limited on my first patch.

shalikas’s picture

Any news Regarding this problem ?

when i'm doing get request to jsonapi endpoint, after upgrade to 8.8 alpha1 i got

Fatal error: Trait 'Shaper\DataAdaptor\DataAdaptorValidatorTrait' not found in
/public_html/modules/jsonapi_extras/src/Plugin/ResourceFieldEnhancerBase.php on line
25

Rajab Natshah’s picture

#2 works well with Drupal 8.8.0-beta1 only

Not sure if this should be in a new branch or should be handled by code

But it's not working with Drupal 8.7.x it will have the issue of

The website encountered an unexpected error. Please try again later.
ArgumentCountError: Too few arguments to function Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository::__construct(), 4 passed in /core/lib/Drupal/Component/DependencyInjection/Container.php on line 281 and exactly 5 expected in Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository->__construct() (line 87 of modules/contrib/jsonapi_extras/src/ResourceType/ConfigurableResourceTypeRepository.php).
Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository->__construct(Object, Object, Object, Object) (Line: 281)
Drupal\Component\DependencyInjection\Container->createService(Array, 'jsonapi.resource_type.repository') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('jsonapi.resource_type.repository', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'private__Ge7rNV4093r8BU-kWDWBZlLspq4potsAwl4zVEFbGaE') (Line: 502)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 515)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'serializer') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('serializer', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'simple_oauth.repositories.access_token') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('simple_oauth.repositories.access_token', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'simple_oauth.server.resource_server') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('simple_oauth.server.resource_server', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'simple_oauth.authentication.simple_oauth') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('simple_oauth.authentication.simple_oauth', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 326)
Drupal\Component\DependencyInjection\Container->createService(Array, 'authentication_collector') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('authentication_collector', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'authentication') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('authentication', 1) (Line: 487)
Drupal\Component\DependencyInjection\Container->resolveServicesAndParameters(Array) (Line: 237)
Drupal\Component\DependencyInjection\Container->createService(Array, 'authentication_subscriber') (Line: 173)
Drupal\Component\DependencyInjection\Container->get('authentication_subscriber') (Line: 105)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.request', Object) (Line: 127)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 67)
Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->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: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->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: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
Rajab Natshah’s picture

The __construct for ResourceTypeRepository in Drupal core 8.7.x has 4 arguments
But in Drupal core 8.8.x it has 5 arguments.

dorficus’s picture

@RajabNatshah this patch is only for the 8.8.x version. There was an API change so previous versions of Drupal would require a different version of the module to function.

Rajab Natshah’s picture

Thank you J.

That is clear to me
I'm suggesting for a new branch

#10

Not sure if this should be in a new branch or should be handled by code

#3093428: Add the 3089444-21.patch for the [JSON:API Extras] module to fix Compatibility with Drupal 8.8.x and Drupal 8.7.x

Seems that we may need a new branch for
#3089444: Compatibility with Drupal 8.8.x

or a new branch for Varbase API too.

lawxen’s picture

#2 Works Make the site can be cache cleared, thanks @Grimreaper.
But the we should fix the test code.

lawxen’s picture

Title: Compatibility with Drupal 8.8.x » Compatibility with Drupal 8.8.x: Use ResourceTypeBuildEvent instead ConfigurableResourceTypeRepository
Category: Bug report » Task

After read above two issues, the whole ConfigurableResourceTypeRepository.php should be removed, and use ResourceTypeBuildEvent to handle the renaming of fields.

lawxen’s picture

Assigned: Unassigned » lawxen
lawxen’s picture

Assigned: lawxen » Unassigned

I try to add a ResourceTypeBuildEventSubscriber, but there's are so many other places needs be changed, But I don't have so much time these days.

+  jsonapi_extras.resource_type_building.build_subscriber:
+    class: Drupal\jsonapi_extras\EventSubscriber\ResourceTypeBuildEventSubscriber
+    arguments: ['@entity_type.manager', '@entity_type.bundle.info']
+    tags:
+      - { name: event_subscriber }
<?php

namespace Drupal\jsonapi_extras\EventSubscriber;

use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\jsonapi\ResourceType\ResourceTypeBuildEvents;
use Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent;
use Drupal\jsonapi_extras\Entity\JsonapiResourceConfig;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Event subscriber which tests disabling resource types.
 *
 * @internal
 */
class ResourceTypeBuildEventSubscriber implements EventSubscriberInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The bundle manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityTypeBundleInfo;

  /**
   * A resource configuration entity.
   *
   * @var \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig
   */
  protected $resourceConfig;

  /**
   * Constructs a ContentTranslationOverviewAccess object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
   *   The entity type bundle info service.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_bundle_info) {
    $this->entityTypeManager = $entity_type_manager;
    $this->entityTypeBundleInfo = $entity_bundle_info;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      ResourceTypeBuildEvents::BUILD => [
        ['disableResourceType'],
        ['aliasResourceTypeFields'],
      ],
    ];
  }

  /**
   * Disables any resource types that have been disabled by a test.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent $event
   *   The build event.
   */
  public function disableResourceType(ResourceTypeBuildEvent $event) {
    $resource_type_name = $event->getResourceTypeName();
    $resource_config = $this->getResourceConfig($resource_type_name);

    if (!empty($resource_config) && $resource_config->get('disabled')) {
      $event->disableResourceType();
    }
  }

  /**
   * Aliases any resource type fields that have been aliased by a test.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent $event
   *   The build event.
   */
  public function aliasResourceTypeFields(ResourceTypeBuildEvent $event) {
    $aliases = [];

    $resource_type_name = $event->getResourceTypeName();
    $resource_config = $this->getResourceConfig($resource_type_name);
    if (!empty($resource_config)) {
      $mappings = $this->overrideFieldMapping($resource_config);
      if (!empty($mappings)) {
        $aliases[] = $mappings;
        foreach ($event->getFields() as $field) {
          if (isset($aliases[$field->getInternalName()])) {
            $event->setPublicFieldName($field, $aliases[$field->getInternalName()]);
            $event->getResourceTypeName();
          }
        }
      }
    }
  }

  /**
   * Get a single resource configuration entity by its ID.
   *
   * @param string $resource_config_id
   *   The configuration entity ID.
   *
   * @return \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig
   *   The configuration entity for the resource type.
   */
  protected function getResourceConfig($resource_config_id) {
    if (!$this->resourceConfig) {
      $resource_configs = $this->getResourceConfigs();
      $this->resourceConfig = isset($resource_configs[$resource_config_id]) ?
        $resource_configs[$resource_config_id] : '';
    }
    return $this->resourceConfig;
  }

  /**
   * Load all resource configuration entities.
   *
   * @return \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig[]
   *   The resource config entities.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   */
  public function getResourceConfigs() {
    $resource_config_ids = [];
    foreach ($this->getEntityTypeBundleTuples() as $tuple) {
      list($entity_type_id, $bundle) = $tuple;
      $resource_config_ids[] = static::buildResourceConfigId(
        $entity_type_id,
        $bundle
      );
    }
    $resource_configs = $this->entityTypeManager
      ->getStorage('jsonapi_resource_config')
      ->loadMultiple($resource_config_ids);
    return $resource_configs;
  }

  /**
   * Entity type ID and bundle iterator.
   *
   * @return array
   *   A list of entity type ID and bundle tuples.
   */
  protected function getEntityTypeBundleTuples() {
    $entity_type_ids = array_keys($this->entityTypeManager->getDefinitions());
    // For each entity type return as many tuples as bundles.
    return array_reduce($entity_type_ids, function ($carry, $entity_type_id) {
      $bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($entity_type_id));
      // Get all the tuples for the current entity type.
      $tuples = array_map(function ($bundle) use ($entity_type_id) {
        return [$entity_type_id, $bundle];
      }, $bundles);
      // Append the tuples to the aggregated list.
      return array_merge($carry, $tuples);
    }, []);
  }

  /**
   * Gets the field mapping for the given field names and entity type + bundle.
   *
   * @param \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig $resource_config
   *   The associated resource config.
   *
   * @return array
   *   An array with:
   *   - keys are (real/internal) field names
   *   - values are either FALSE (indicating the field is not exposed despite
   *     not being internal), TRUE (indicating the field should be exposed under
   *     its internal name) or a string (indicating the field should not be
   *     exposed using its internal name, but the name specified in the string)
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function overrideFieldMapping(JsonapiResourceConfig $resource_config) {
    // Use the base class to fetch the non-configurable field mappings.
    $mappings = $resource_config->getFieldMapping();
    // Ignore all the fields that don't have aliases.
    $mappings = array_filter($mappings, function ($field_info) {
      return $field_info !== TRUE;
    });
    return $mappings;
  }

  /**
   * Builds the resource config ID from the entity type ID and bundle.
   *
   * @param string $entity_type_id
   *   The entity type ID.
   * @param string $bundle
   *   The entity bundle.
   *
   * @return string
   *   The ID of the associated ResourceConfig entity.
   */
  protected static function buildResourceConfigId($entity_type_id, $bundle) {
    return sprintf(
      '%s--%s',
      $entity_type_id,
      $bundle
    );
  }

}

Rajab Natshah’s picture

Hi Liu :)
Nice following and debugging on this issue

I think we should change the patch to work as what Jacob did for webform
#3091715: Too few arguments to function Drupal\webform\WebformThemeManager::__construct()

like the null argument !! maybe
I have noticed number argument number issues when we start to use Drupal 8.8.x and Drupal 8.7.x at the same time.

Rajab Natshah’s picture

Rajab Natshah’s picture

Status: Needs work » Needs review
Rajab Natshah’s picture

Title: Compatibility with Drupal 8.8.x: Use ResourceTypeBuildEvent instead ConfigurableResourceTypeRepository » Compatibility with Drupal 8.8.x and Drupal 8.7.x

Still I think a new branch could result on a faster performance by removing all conditions in the module.
any condition which related D8.8.x or D8.7.x

BR0kEN’s picture

mglaman’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/src/ResourceType/ConfigurableResourceTypeRepository.php
@@ -83,13 +79,8 @@ class ConfigurableResourceTypeRepository extends ResourceTypeRepository {
+  public function __construct(...$arguments) {
+    parent::__construct(...$arguments);

👍 this is much simpler. The only reason the constructor is overridden is to add additional cache tags, nothing else is injected.

---

Edit: 8.8 failed, but that looks like unrelated errors.

sokru’s picture

Run into this problem when tried to update Drupal core to 8.8.0. Somehow the update managed to finish system_update_8803 but so stuck on system_update_8804 with error [error] SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db.path_alias' doesn't exist: INSERT INTO {path_alias} ....

I was able to reproduce this all time with restored database, then applied patch from #24 and all update hooks finished correctly.

axle_foley00’s picture

The patch in #24 did fixed the issue for me when upgrading from 8.7.8 to 8.8.0.

brockfanning’s picture

I don't understand the details, but also need to resolve this for a site. I tried re-testing the patch in #24 and it appears to have passed this time, FWIW.
Edit - Whoops, I think I was reading the test results wrong. My re-test didn't change the results, it seems.

drupalninja99’s picture

Patch #24 worked for me

BR0kEN’s picture

#24 reveals another issues with Drupal 8.8.x however it's still needed in order to move forward.

Right now 8.x-3.x tests fail early (https://www.drupal.org/pift-ci-job/1497535) and #24 helps to overcome this but also leads to the following errors - https://www.drupal.org/pift-ci-job/1495249. The #99 of #2996114: Argument 2 passed to Drupal\jsonapi\Routing\Routes::Drupal\jsonapi\Routing\{closure}() must be an instance of Drupal\jsonapi\ResourceType\ResourceType, NULL given allows to resolve many of those errors.

  • e0ipso committed 9d38b7e on 8.x-3.x authored by RajabNatshah
    Issue #3089444 by RajabNatshah, Grimreaper, BR0kEN: Compatibility with...
  • e0ipso committed ae5d8c1 on 8.x-3.x authored by BR0kEN
    Issue #3089444 by RajabNatshah, Grimreaper, BR0kEN, lawxen, dorficus,...
e0ipso’s picture

Thanks to everyone that contributed to this issue!

e0ipso’s picture

Status: Reviewed & tested by the community » Fixed
siva01’s picture

As wrote lawxen, there is still problem with renamed fields.

Error: Call to undefined method Drupal\jsonapi\ResourceType\ResourceTypeAttribute::withRelatableResourceTypes() in Drupal\jsonapi\ResourceType\ResourceType-&amp;gt;Drupal\jsonapi\ResourceType\{closure}() (Zeile 385 in /var/www/html/docroot/core/modules/jsonapi/src/ResourceType/ResourceType.php) #0 [internal function]: Drupal\jsonapi\ResourceType\ResourceType-&amp;gt;Drupal\jsonapi\ResourceType\{closure}(Array, &amp;#039;type&amp;#039;)

How reproduce it: try rewrite some field and use custom field name. Run drush cim, or drush updb. And you will get error. So this module still isn't compatible with Drupal 8.8

BR0kEN’s picture

Status: Fixed » Closed (fixed)

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

siva01’s picture

@BR0kEN I already did it. Problem is in "type". We used alias "type" for one another field, than it is paragraph "type" (bundle) field, which is disabled, but still it make some conflict. Result is "Fatal error: Uncaught Error: Call to undefined method Drupal\jsonapi\ResourceType\ResourceTypeAttribute::withRelatableResourceTypes()". Fast solution is use different alias.

BR0kEN’s picture

@siva01, I cannot reproduce this either using UI nor by the unit test. Can you help writing a test?

Also, feel free to open a new ticket and link it to this one.

My test that passes (Drupal\Tests\jsonapi\Functional\JsonApiFunctionalTest):

  public function testDisableBundleFieldAndReuseItsName() {
    $this->createDefaultContent(10, 5, FALSE, FALSE, static::IS_NOT_MULTILINGUAL, FALSE);

    $this->assertTrue($this->container->get('module_installer')->install([
      'jsonapi_test_resource_type_building',
    ], TRUE));
    \Drupal::state()->set('jsonapi_test_resource_type_builder.disabled_resource_type_fields', [
      'node--article' => [
        'type' => TRUE,
      ],
    ]);
    \Drupal::state()->set('jsonapi_test_resource_type_builder.resource_type_field_aliases', [
      'node--article' => [
        'body' => 'type',
      ],
    ]);
    $this->rebuildAll();

    $data = Json::decode($this->drupalGet('/jsonapi/node/article'));
    $this->assertSession()->statusCodeEquals(200);
    $this->assertCount(10, $data['data']);
    // The "body" was renamed to "type".
    $this->assertNotEmpty($data['data'][0]['attributes']['type']['processed']);
  }