Returned ExternalEntityTypeInterface interface does not include all public methods of ExternalEntityType

Created on 31 March 2025, 3 months ago

Problem/Motivation

1. I get the following PHPStan issue:

Call to an undefined method Drupal\external_entities\Entity\ExternalEntityTypeInterface::getDataAggregator().

When the following code is used:

$storage = $this->entityTypeManager->getStorage('custom_external_entity');
$query = $storage->getQuery();
$storage_client = $query->getExternalEntityType()->getDataAggregator()->getStorageClient(0);

Because $query->getExternalEntityType() returns \Drupal\external_entities\Entity\ExternalEntityTypeInterface rather than \Drupal\external_entities\Entity\ConfigurableExternalEntityTypeInterface

Proposed resolution

Either updating the return type for getExternalEntityType to be \Drupal\external_entities\Entity\ConfigurableExternalEntityTypeInterface or adding \Drupal\external_entities\Entity\ConfigurableExternalEntityTypeInterface as a return type from this method.

🐛 Bug report
Status

Active

Version

3.0

Component

Code

Created by

🇦🇺Australia RichardGaunt Melbourne

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @RichardGaunt
  • 🇦🇺Australia RichardGaunt Melbourne

    Created a MR that fixes this issue:
    https://git.drupalcode.org/project/external_entities/-/merge_requests/81

    Not sure whether inheritance should be this way as ConfigurableExternalEntityTypeInterface feels like an extension on ExternalEntityTypeInterface but its a starting point.

  • Pipeline finished with Failed
    3 months ago
    Total: 244s
    #462045
  • 🇦🇺Australia RichardGaunt Melbourne

    https://git.drupalcode.org/issue/external_entities-3516546/-/jobs/4830977

    Tests are failing with this change but won't fix until I know the direction to take.

  • 🇫🇷France guignonv Montpellier

    OK. I think I understand the problem but I need to think if your approach is the best. There might be a deeper design issue (-probably my bad-). I'm working other projects in parallel so I'll do my best to think about it as soon as I can and come back to you here. No hurry?

  • 🇦🇺Australia RichardGaunt Melbourne

    I am all good I made a local patch to fix for my purposes.

  • Status changed to Postponed: needs info 27 days ago
  • 🇫🇷France guignonv Montpellier

    I had a deeper look into the code and (re)thought about the logic.

    First, your example works for me with no error (PHP 8.3.21) for a regular external entity type created through the UI.

    $storage = \Drupal::entityTypeManager()->getStorage('some_regular_xntt');
    $query = $storage->getQuery();
    $storage_client = $query->getExternalEntityType()->getDataAggregator()->getStorageClient(0);
    // It works, I got a storage client instance.
    // Note: $query->getExternalEntityType() returns a \Drupal\external_entities\Entity\ExternalEntityType instance, as expected.
    

    So, I believe you are using a custom external entity type created programmatically to get such an error?

    Anyway, in terms of logic, I see no issue in current code.
    Your line:

    $storage_client = $query->getExternalEntityType()->getDataAggregator()->getStorageClient(0);
    

    assumes $query->getExternalEntityType() returns a ConfigurableExternalEntityTypeInterface object while it might not be the case. In fact, before calling ->getDataAggregator()->getStorageClient(0), you should check that the returned object is actually an instance of ConfigurableExternalEntityTypeInterface.
    I think there is either a problem of logic in your code (like the missing test above) or I am missing something. I did not find any inconsistency in current sources (...which does not mean there are none but so far, so good...).

    Maybe I should explain here the reason of the existence of ConfigurableExternalEntityTypeInterface:
    if you look in v2, there were only ExternalEntityTypeInterface. The idea of adding a layer is not just to add complexity and problems, it is because developers may want to create their own external entity type without having to use the same current logic that works with data aggregator + storage clients + field mappers + property mappers + data processors. The ExternalEntityInterface just defines what makes an entity "external" (methods to manage raw data or annotations) while the ConfigurableExternalEntityTypeInterface adds what is necessary to manage Drupal fields, meaning that fields are configurable by external entity types. When you have Drupal "fields", you need to map them to external data fields: get external data (data aggregator + storage clients) and map (field mapper + property mapper + data processor).

    With current design, I believe one can define and implement a external entity type that may not use Drupal fields at all and use its own logic (its own ExternalEntityStorageInterface implementation, etc.).

    To conclude, for me, it works as designed. Please provide me a test class that demonstrates the problem otherwise. ...or provide more of your code that raise a problem, with the context.

    No news on this issue in a month and I'll set to to "Closed (works as designed)".

Production build 0.71.5 2024