Proposal: New ConfigEntity extension strategy

Created on 9 April 2025, 15 days ago

Problem/Motivation

Over the last year, I've been thinking (and on Slack talking) about a new way to implement this module.

Today, we:

* Gather up all the config entities
* Walk through the anatomy of each one, finding all the properties, references, etc.
* Use all the data to build out what the views_data for the config entity should be.

Pros:
* We figured it out, and it does it's job decently well, despite the additional work we need to do.

Cons:
* Very memory and process intensive
* Provides a solution that is in addition to what seems to be the systems preferred approach

Let me explain...

Say we wanted to create a new configuration entity and we wanted to build in views support for it from the beginning. It would look something like this

/**
 * Defines a configuration-based entity type used for testing Views data.
 *
 * @ConfigEntityType(
 *   id = "views_config_entity_test",
 *   label = @Translation("Test config entity type with Views data"),
 *   handlers = {
 *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
 *     "views_data" = "Drupal\views_config_entity_test\ViewsConfigEntityTestViewsData"
 *   },
 *   admin_permission = "administer modules",
 *   config_prefix = "type",
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "name"
 *   },
 *   config_export = {
 *     "id",
 *     "label",
 *   }
 * )
 */
class ViewsConfigEntityTest extends ConfigEntityBase {

Hilariously, this is the ONLY config entity in core (that I've been able to find) that defines it's own views support. Why?

Well here's the ViewsConfigEntityTestViewsData:

class ViewsConfigEntityTestViewsData implements EntityViewsDataInterface {

  /**
   * {@inheritdoc}
   */
  public function getViewsData() {
    return [];
  }

  /**
   * {@inheritdoc}
   */
  public function getViewsTableForEntityType(EntityTypeInterface $entity_type) {
    return 'views_config_entity_test';
  }

}

So there isn't a lot of guidance on this but if I still think that if we wanted to inform the system that a configuration entity has views support, we would do that with the config entity's views_data handler. Now content entities have tables that views can use to create queries. Config entities have files / the data stored in the active store. And that's the inherit problem we've been solving here.

I just think that we could try do to an approach similar to Workspaces module. Which would consist of:

1. Gather up all the config entities.
2. Filter out any that already have a views_handler defined.
3. For all the config entities that don't have the views handler defined extend the entity to use a DefaultConfigEntityViewsDataHandler. Or if for whatever reason a config entity wants to completely opt out of views support, provide a IgnoredViewsDataHandler.

The DefaultConfigEntityViewsDataHandler is where we can provide our generic approach of building up the data that views needs.

In my view this new approach have some big advantages but also some disadvantages we should talk about:

Pros
* Config entities behave more like content entities. Content entities use these handlers, but config entities can too.
* Reorganizing the code out of the .inc file would allow us break up the code a bit more and make things more testable.
* If a config entity wants to handle this complexity on their own we won't fight them for control.

Cons:
* A bunch of new work.
* We strike at the heart of what makes this module hard.

It's hard because content entities have tables and maps pretty well with the original purposes of the "Materialized Views" of Views module. We're kind of building up a fake table structure for Views to use. We haven't spent a lot of time on dealing with the long term realities of that because we spend so much of our time getting this to actually work.

Future thoughts:
I think this a lot more room for improvement in the future. One thing I've learned in my short time helping out the ECA / modeler_api module is that there may be a lot of value in using this module to build out some kind of intermediate data format. Something that can be referred to later that ISN'T in cache but an actual file that supplies ViewsData what it needs.

I don't exactly know what format this would be output as, but I suppose a config entity would do.

That's all of my thoughts so far. Let's discuss

🌱 Plan
Status

Active

Version

2.1

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States cosmicdreams Minneapolis/St. Paul

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

Comments & Activities

  • Issue created by @cosmicdreams
  • πŸ‡ΊπŸ‡ΈUnited States swirt Florida

    @cosmicdreams I like this refined approach (disclaimer: I only understood maybe 80% ;) ) . If config entities have the ability to provide Views data it makes sense to leverage that as much as possible.

    One challenge I see is doing it in a way that would not break any existing Config Views. Hopefully the underlying architecture change would be un-noticeable to the casual user.

  • πŸ‡ΊπŸ‡ΈUnited States swirt Florida

    Another consideration after someone figures out how to implement Views data for a config entity is to provide better documentation so that module developers creating config entities can do a better job of including it themselves.

Production build 0.71.5 2024