Static analysis for EntityStorage

Created on 4 December 2024, 4 months ago

Problem/Motivation

Currently, when we call `$node = $entity_type_manager->getStorage('node')->load(123);`, static analysis has no straightforward way to know the type of `$node`. It only knows that it is an entity.

There are tools like https://mglaman.dev/blog/better-static-analysis-entity-type-storages-php..., but this is very specific to phpstan, not clear that it will be understood by IDEs etc.

Steps to reproduce

Proposed resolution

Put a `@template TEntity of EntityInterface` on `EntityStorageInterface`.
Document the return type of e.g. EntityStorageInterface::load() as `(TEntity&EntityInterface)|null`.

TBD:
Provide a method `EntityTypeManager->getStorageByClass(string $class)`, which is documented to return an instance of `EntityStorageInterface<$class>`.
The mapping logic here would be similar to EntityTypeRepository::getEntityTypeFromClass(), but it would also have to support interfaces. The mapping can be cached somewhere.
If an interface is used by more than one type, throw an exception.

Open questions

We could decide if this belongs into EntityTypeManager or some other place.

Difficulties

I can already see one flaw of this proposed system.
We can have code that calls $entity_type_manager->getStorageByClass(NodeInterface::class)` which works.
Then somebody introduces a new entity type with `MyEntityInterface extends NodeInterface` or just `MyEntity implements NodeInterface`, and all of that existing code will break, because now the interface is ambiguous.

We could use the actual entity class, but I don't like it.
Or we could a have a method that takes the entity type id _and_ the interface.
Or we could simply use `->getStorage($entity_type_id)`, but then calling code can put `@var EntityStorageInterface $storage` on the variable.

Optional changes

Optionally, also add `@template TEntityId of int|string` on EntityStorageInterface.
To properly support this we would need `getConfigStorageByClass($class)` and `getContentStorageByClass($class)` which would provide different key types. But I think it provides little benefit for the cost.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

🌱 Plan
Status

Active

Version

11.1 🔥

Component

entity system

Created by

🇩🇪Germany donquixote

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

Merge Requests

Comments & Activities

Production build 0.71.5 2024