Follow-up to #2302235: Set default property values in EntityType

Problem/Motivation

Currently \Drupal\Core\Entity\EntityType::getBundleEntityType() simply returns a value of bundle_entity_type protected property that initialized with "bundle" string.

The provided default "bundle" is wrong because hides absence of actual value parsed from entity annotation by returning "bundle" string that used only by internals of field ui module. That was done in #2302235: Set default property values in EntityType

This causes a field ui module route generation tricky because you need to check:
1) entity has bundle support EntityTypeInterface::hasKey('bundle')
2) entity bundles are managed by other entity EntityTypeInterface::getBundleEntityType() should return entity machine name or NULL, currently returns "bundle" string.

Entity can have "bundle_entity_type" and no bundle key definition, so no documentation about using this properties right. Also there's "bundle_of" property that describes reverse relation from config entity to content entity.

This default value also introduces a limitation to use "bundle" as entity name because entity param converter will try to load an entity when field ui module forms and controllers need raw value of the bundle.

Proposed resolution

Change default value to NULL
Clean-up all checks in code for "bundle" by introducing a static helper FieldUI::getRouteBundleParameterName() method
In changed places rename:
- $bundle_entity_type to $bundle_entity_type_id - sometimes called a "$field_entity_type"
- use $entity_type variable name for entity type definition for consistency.

Remaining tasks

Review patch approach
Fix, commit

User interface changes

no

API changes

Default value for \Drupal\Core\Entity\EntityType::$bundle_entity_type changes from 'bundle' to NULL.
A new method is added to \Drupal\Core\Entity\EntityTypeInterface: getBundleConfigDependency()

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because every caller of \Drupal\Core\Entity\EntityType::getBundleEntityType() needs to take into account a possible return value of 'bundle' which doesn't mean anything for them. Examples of this wrong behavior can be seen in (and are fixed by) the patch.
Issue priority Normal because there's a known workaround (i.e. take the special 'bundle' return value into account).
Prioritized changes The main goal of this issue is to improve the developer experience for this method. It also improves maintainability because it removes special-casing code.
Disruption Little disruptive for contributed and custom modules because it will require a small code updates if they use the current workaround of checking the "bundle" return value as absence of bundle entity type.
CommentFileSizeAuthor
#99 set_default_property-2346857-99.patch21.37 KBclaudiu.cristea
#99 interdiff.txt923 bytesclaudiu.cristea
#96 interdiff.txt5.07 KBclaudiu.cristea
#96 set_default_property-2346857-96.patch21.37 KBclaudiu.cristea
#87 2346857-87.patch21.34 KBclaudiu.cristea
#87 interdiff.txt1.13 KBclaudiu.cristea
#85 interdiff.txt904 bytesclaudiu.cristea
#85 2346857-85.patch21.59 KBclaudiu.cristea
#82 2346857-82.patch21.64 KBclaudiu.cristea
#82 interdiff.txt483 bytesclaudiu.cristea
#80 2346857-80.patch21.39 KBclaudiu.cristea
#71 2346857_70.patch17.59 KBMile23
#67 2346857_67.patch21.58 KBMile23
#64 set_default_property-2346857-64.patch21.66 KBsiva_epari
#59 interdiff.txt950 bytesamateescu
#59 2346857-59.patch22.34 KBamateescu
#57 2346857-57.patch22.34 KBamateescu
#53 2346857-53.patch22.33 KBamateescu
#49 interdiff.txt9.23 KBamateescu
#49 2346857-49.patch22.3 KBamateescu
#46 2346857-46.patch17.71 KBamateescu
#42 2346857-bundle_entity_type-42.patch21.54 KBandypost
#42 interdiff.txt1.7 KBandypost
#41 2346857-bundle_entity_type-41.patch19.84 KBandypost
#41 interdiff.txt2.78 KBandypost
#35 2346857-bundle_entity_type-35.patch19.66 KBandypost
#35 interdiff.txt6.25 KBandypost
#34 2346857-bundle_entity_type-34.patch19.3 KBandypost
#34 interdiff.txt2.99 KBandypost
#32 2346857-bundle_entity_type-32.patch17.13 KBandypost
#28 2346857-bundle_entity_type-28.patch17.13 KBandypost
#28 interdiff.txt6.71 KBandypost
#26 2346857-bundle_entity_type-26.patch13.72 KBandypost
#26 interdiff.txt11.06 KBandypost
#20 2346857-bundle_entity_type-20.patch16.39 KBandypost
#20 interdiff.txt2.52 KBandypost
#19 2346857-bundle_entity_type-18.patch16.75 KBandypost
#19 interdiff.txt1.54 KBandypost
#18 2346857-bundle_entity_type-17.patch15.67 KBandypost
#18 interdiff.txt9.28 KBandypost
#13 2346857-interdiff-11.txt701 bytesrpayanm
#13 2346857-13.patch12.09 KBrpayanm
#9 2346857-set-null-to-bundle_entity_type-9.patch12.08 KBm1r1k
#9 interdiff.txt9.88 KBm1r1k
#6 interdiff.txt799 bytesm1r1k
#6 2346857-set-null-to-bundle_entity_type-2.patch10.79 KBm1r1k
#3 2346857-set-null-to-bundle_entity_type-1.patch10.01 KBm1r1k
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

andypost’s picture

m1r1k’s picture

Assigned: Unassigned » m1r1k
m1r1k’s picture

Assigned: m1r1k » Unassigned
Status: Active » Needs review
FileSize
10.01 KB
m1r1k’s picture

Issue tags: +Amsterdam2014
m1r1k’s picture

Status: Needs work » Needs review
FileSize
10.79 KB
799 bytes
yched’s picture

Not a blocker, but

  • +++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
    @@ -158,7 +158,7 @@ public function calculateDependencies() {
         $bundle_entity_type_id = $target_entity_type->getBundleEntityType();
    -    if ($bundle_entity_type_id != 'bundle') {
    +    if ($bundle_entity_type_id) {
    

    That could be shortened to "if ($bundle_entity_type_id = ...)"
    & same for most of the other hunks in the patch :-)

    Other than that, this looks good once it's green.

  • m1r1k’s picture

    Status: Needs work » Needs review
    FileSize
    9.88 KB
    12.08 KB

    Here are some improvements

    andypost’s picture

    +++ b/core/modules/field_ui/src/OverviewBase.php
    @@ -78,6 +78,11 @@ public static function create(ContainerInterface $container) {
         $this->bundleEntityType = $entity_type->getBundleEntityType();
    ...
    +    if (!($this->bundleEntityType = $entity_type->getBundleEntityType())) {
    

    repeated twice for no reason

    jsobiecki’s picture

    Issue tags: -Amsterdam2014 +dcwroc2014
    rpayanm’s picture

    Status: Needs work » Needs review
    FileSize
    12.09 KB
    701 bytes
    andypost’s picture

    @yched what is a recommended way to make sure that entity has bundles? there's 2 keys:

    1) $entity_type->getBundleEntityType() - simply means that there's no entity type that is a bundle for that entity.
    2) $entity_type->hasKey('bundle') - no bundle key so entity is not "bundlable", meaning that getBundleEntityType() should return NULL

    Berdir’s picture

    Depends on what you want to know. If you want to know if an entity has bundles, use hasKey(). If you want to know if it has bundles that are stored as entities, use getBundleEntityType().

    andypost’s picture

    Status: Needs work » Needs review
    Issue tags: -Novice, -Needs reroll
    FileSize
    9.28 KB
    15.67 KB

    "bundle" key is needed for entity_test that manages bundles by custom way, so here's workaround

    andypost’s picture

    FileSize
    1.54 KB
    16.75 KB

    Fix last test, suppose patch ready for review

    andypost’s picture

    A bit of clean-up

    andypost’s picture

    @Berdir maybe better to get rid of this "bundle" default in favour of route subscriber?

    Berdir’s picture

    Assigned: Unassigned » yched

    Yeah not sure about this, lets try to get some feedback from yched on this.

    To summarize the problem in one sentencene, the problem is that field_ui relies in a weird way on bundle_entity_type being "bundle" when it is actually no entity type, which makes checks for this more complicated in other parts of the code.

    I think that we should not make the API weird to make it easier for field_ui, but not sure what the best way to fix that is.

    Berdir’s picture

    Assigned: yched » Unassigned

    Uff.

    We discussed this a bit. We're not sure what to do, but here is an idea:

    Instead of supporting a dynamic parameter (which we do not understand works for FieldOverview), what if we always use {bundle} for our own routes:

    Meaning, do $path = str_replace('{' . $bundle_entity_type . '}', '{bundle}', $path) in case we have a $bundle_entity_type. Then all the route parameters generation code can hardcode 'bundle'.

    We don't know if anyything will break because of that, but it might be worth a try?

    If it s not already documented, we should also expand the documentation for field_ui_base_route that you either have to put in the bundle entity type if you have one or bundle in there for field_ui to work.

    yched’s picture

    Might be woth pinging @tim.plunkett about this ? IIRC he's the one who was kind enough to take care of moving field_ui's callbacks to routes :-)

    andypost’s picture

    Issue tags: +Needs architectural review, +Needs committer feedback
    FileSize
    11.06 KB
    13.72 KB

    This breaks a lot of places in core that supposed to typed bundle, for example

    So there's a lot of places needs to be cleaned-up to load bundle manually to get a label of bundle entity.
    Is this change could be approved?

    Status: Needs review » Needs work

    The last submitted patch, 26: 2346857-bundle_entity_type-26.patch, failed testing.

    andypost’s picture

    Status: Needs work » Needs review
    FileSize
    6.71 KB
    17.13 KB

    I found that base route for field UI is defined by entity so too much code needs change.
    So fallback to previous patch (interdiff against #20)

    Status: Needs review » Needs work

    The last submitted patch, 28: 2346857-bundle_entity_type-28.patch, failed testing.

    Berdir’s picture

    Status: Needs work » Needs review

    Yeah, what I meant is to replace {node_type} to {bundle} in field_ui routes, but that breaks on the link templates, local tasks and so on.

    Berdir’s picture

    Status: Needs review » Needs work
    andypost’s picture

    Status: Needs work » Needs review
    FileSize
    17.13 KB

    just a re-roll, looks configFieldMapper needs some clean-up

    Status: Needs review » Needs work

    The last submitted patch, 32: 2346857-bundle_entity_type-32.patch, failed testing.

    andypost’s picture

    Status: Needs work » Needs review
    FileSize
    2.99 KB
    19.3 KB

    Content translation now affected too

    andypost’s picture

    Issue summary: View changes
    FileSize
    6.25 KB
    19.66 KB

    Re-roll with some clean-up by using existing FieldUI::getRouteBundleEntityType() and introduction of FieldUI::getRouteBundleParameterName() to use for flip-flop entity types and "bundle"

    Suppose all fieldUI code should use the function to build a route names.

    Patch ready for review/suggestions.

    PS: updated issue summary a bit

    jibran’s picture

    Issue tags: +Need issue summary update

    We need beta evaluation in issue summary.

    Status: Needs review » Needs work

    The last submitted patch, 35: 2346857-bundle_entity_type-35.patch, failed testing.

    andypost’s picture

    Issue summary: View changes
    Issue tags: -Need issue summary update

    added beta and fixed IS

    jibran’s picture

    Changes look good to me. Let's see what @Berdir or @yched thinks about it.

    Berdir’s picture

    @amateescu wanted to work on field_ui to clean up how the bundle route parameter works, that would simplify this a lot I think.

    andypost’s picture

    Status: Needs work » Needs review
    FileSize
    2.78 KB
    19.84 KB

    Another clean-up, less noise

    andypost’s picture

    FileSize
    1.7 KB
    21.54 KB

    a bit more fixes

    The last submitted patch, 41: 2346857-bundle_entity_type-41.patch, failed testing.

    andypost’s picture

    Green again, waiting for reviews

    amateescu’s picture

    I remember someone (probably @Berdir) asked me to link here the issue for cleaning up Field UI routes, so here it is: #2428035: Bring some sanity into Field UI routes and forms

    amateescu’s picture

    Status: Needs review » Needs work
    Issue tags: -Needs architectural review
    FileSize
    17.71 KB

    Rewritten this patch on top of #2428035: Bring some sanity into Field UI routes and forms. We can switch back to NR when that issue gets in.

    andypost’s picture

    Status: Needs work » Needs review
    Issue tags: +Needs issue summary update

    Let's test a patch, overall looks great!

    Just few questions

    1. +++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
      @@ -674,4 +674,17 @@ public function getListCacheTags();
      +  public function getBundleConfigDependency($bundle);
      

      should be added to IS

    2. +++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php
      @@ -48,14 +48,13 @@ protected function alterRoutes(RouteCollection $collection) {
      +        if ($bundle_entity_type = $entity_type->getBundleEntityType()) {
                 $options['parameters'][$bundle_entity_type] = array(
                   'type' => 'entity:' . $bundle_entity_type,
                 );
      ...
               }
      +        // Special parameter used to easily recognize all Field UI routes.
      +        $options['_field_ui'] = TRUE;
      

      Suppose option should be applied only in case of bundle as entity

    Status: Needs review » Needs work

    The last submitted patch, 46: 2346857-46.patch, failed testing.

    amateescu’s picture

    Issue summary: View changes
    Status: Needs work » Needs review
    Issue tags: -Needs committer feedback, -Needs issue summary update
    FileSize
    22.3 KB
    9.23 KB

    #47.1 Done.
    #47.2 I think it should be there all the time so contrib can depend on it for all Field UI routes.

    amateescu’s picture

    @andypost, do you have any other remarks or can we get this to RTBC? :)

    andypost’s picture

    Status: Needs review » Reviewed & tested by the community
    alexpott’s picture

    Status: Reviewed & tested by the community » Needs work
    Issue tags: +Needs issue summary update

    I'm not sure that the beta evaluation is correct. Have we really justified the disruption here? Also some of the issue summary sounds like a bug.

    amateescu’s picture

    Category: Task » Bug report
    Issue summary: View changes
    Status: Needs work » Reviewed & tested by the community
    Issue tags: -Needs issue summary update
    FileSize
    22.33 KB

    Rerolled and updated the beta evaluation. I agree with #52 that the current behavior smells more like a bug.

    claudiu.cristea’s picture

    +++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
    @@ -693,4 +693,17 @@ public function getConfigDependencyKey();
    +   *   - 'type': The config dependency type (e.g. 'module', 'config').
    

    This is minor. While we are using 'key' and 'name' for dependencies (::getConfigDependencyKey() and ::getConfigDependencyName()) why not be consistent here? I would rename 'type' to 'key'.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 53: 2346857-53.patch, failed testing.

    amateescu’s picture

    Status: Needs work » Reviewed & tested by the community
    FileSize
    22.34 KB

    #55: Drupal\Core\Entity\DependencyTrait::addDependency() has $type and $name as arguments, and the return array of Drupal\Core\Entity\EntityTypeInterface::getBundleConfigDependency() is always used to pass the dependency type and name to the addDependency() method mentioned above, so changing type to key would actually be very confusing IMO.

    Rerolled the patch.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 57: 2346857-57.patch, failed testing.

    amateescu’s picture

    Status: Needs work » Reviewed & tested by the community
    FileSize
    22.34 KB
    950 bytes

    Missed a spot.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 59: 2346857-59.patch, failed testing.

    amateescu queued 59: 2346857-59.patch for re-testing.

    amateescu’s picture

    Status: Needs work » Reviewed & tested by the community

    Bot fluke.

    alexpott’s picture

    Status: Reviewed & tested by the community » Needs work
    Issue tags: +Needs reroll

    Needs a reroll.

    siva_epari’s picture

    Status: Needs work » Needs review
    Issue tags: -Needs reroll
    FileSize
    21.66 KB

    Patch rerolled.

    andypost’s picture

    Status: Needs review » Reviewed & tested by the community

    thanx

    alexpott’s picture

    Status: Reviewed & tested by the community » Needs work
    Issue tags: +Needs change record

    We need a change record to do this.

    Mile23’s picture

    Status: Needs work » Needs review
    FileSize
    21.58 KB

    Needed a reroll.

    Mile23’s picture

    Status: Needs review » Needs work

    The last submitted patch, 67: 2346857_67.patch, failed testing.

    Mile23’s picture

    Assigned: Unassigned » Mile23

    And needs *another* reroll, 5 minutes later. :-)

    Mile23’s picture

    Assigned: Mile23 » Unassigned
    FileSize
    17.59 KB

    More reroll.

    Mile23’s picture

    Status: Needs work » Needs review

    Status: Needs review » Needs work

    The last submitted patch, 71: 2346857_70.patch, failed testing.

    andypost’s picture

    Issue tags: +Needs reroll
    hitesh-jain’s picture

    Assigned: Unassigned » hitesh-jain
    hitesh-jain’s picture

    Issue tags: -Needs reroll

    I could apply the patch, so no reroll is needed it seems.

    hitesh-jain’s picture

    Assigned: hitesh-jain » Unassigned

    Status: Needs work » Needs review

    andypost queued 71: 2346857_70.patch for re-testing.

    Status: Needs review » Needs work

    The last submitted patch, 71: 2346857_70.patch, failed testing.

    claudiu.cristea’s picture

    Status: Needs work » Needs review
    Issue tags: -dcwroc2014
    FileSize
    21.39 KB

    Let's see.

    Status: Needs review » Needs work

    The last submitted patch, 80: 2346857-80.patch, failed testing.

    claudiu.cristea’s picture

    Status: Needs work » Needs review
    Issue tags: -consistency
    FileSize
    483 bytes
    21.64 KB

    use statement missed.

    claudiu.cristea’s picture

    Status: Needs review » Needs work

    The last submitted patch, 82: 2346857-82.patch, failed testing.

    claudiu.cristea’s picture

    Status: Needs work » Needs review
    FileSize
    21.59 KB
    904 bytes

    Status: Needs review » Needs work

    The last submitted patch, 85: 2346857-85.patch, failed testing.

    claudiu.cristea’s picture

    Status: Needs work » Needs review
    FileSize
    1.13 KB
    21.34 KB

    Better.

    andypost’s picture

    Status: Needs review » Reviewed & tested by the community

    CR is good

    alexpott’s picture

    Status: Reviewed & tested by the community » Needs review
    Issue tags: +Needs subsystem maintainer review

    It'd be nice to get a +1 on the final solution from @Berdir or @yched

    Berdir’s picture

    Assigned: Unassigned » yched
    Status: Needs review » Reviewed & tested by the community
    Issue tags: -Needs subsystem maintainer review

    +1 ;)

    This is a small API change that will affect some modules, a quick grep showed DS and field_group. But the current behavior is really weird and exposes field UI internals in the entity type API.

    Maybe give @yched some time to give his +1? He already confirmed almost a year ago that he is onboard with the general idea but the patch changed a lot since then.

    Status: Reviewed & tested by the community » Needs work

    The last submitted patch, 87: 2346857-87.patch, failed testing.

    Status: Needs work » Needs review

    alexpott queued 87: 2346857-87.patch for re-testing.

    amateescu’s picture

    Status: Needs review » Reviewed & tested by the community

    Back to rtbc.

    alexpott’s picture

    The fail in #91 was due to not be able to checkout code on testbot and nothing to do with the patch.

    yched’s picture

    +1 indeed, minor remarks below :

    1. +++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
      @@ -256,18 +256,9 @@ public function calculateDependencies() {
      +    if ($bundle_config_dependency = $target_entity_type->getBundleConfigDependency($this->bundle)) {
      

      Here and for other callers of the new getBundleConfigDependency() : the method either returns something or throws an exception, so not sure why we bother with the "if ($dep = getBundleConfigDependency())", it's always gonna be TRUE ?

    2. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
      @@ -764,4 +764,30 @@ public function addConstraint($constraint_name, $options = NULL) {
      +  public function getBundleConfigDependency($bundle) {
      +    // If the target entity type uses entities to manage its bundles then
      +    // depend on the bundle entity.
      

      Minor : the comment was copy/pasted along with the code from EntityDisplayBase to EntityType, but the notion of "target" entity type makes little sense in that new location (it's now about "this" EntityType)

    3. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
      @@ -764,4 +764,30 @@ public function addConstraint($constraint_name, $options = NULL) {
      +      if (!$bundle_entity = \Drupal::entityManager()->getStorage($bundle_entity_type_id)->load($bundle)) {
      +        throw new \LogicException(sprintf('Missing bundle entity, entity type %s, entity id %s.', $bundle_entity_type_id, $bundle));
      +      }
      

      Probably not for this issue to change since it is just being moved around, but isn't that the kind of stuff asserts are for now ?

    claudiu.cristea’s picture

    Status: Reviewed & tested by the community » Needs review
    FileSize
    21.37 KB
    5.07 KB
    claudiu.cristea’s picture

    @yched,

    1. #95.1: Good catch.
    2. #95.2: Fixed.
    3. #95.3: I don't understand. Asserts? Sorry, I'm missing something :)

    Please re-RTBC if looks OK for you

    yched’s picture

    Status: Needs review » Reviewed & tested by the community

    Thanks @claudiu.cristea. Looks good.

    Minor, can be fixed on commit :

    +++ b/core/lib/Drupal/Core/Entity/EntityType.php
    @@ -764,4 +764,30 @@ public function addConstraint($constraint_name, $options = NULL) {
    +    // If the this entity type uses entities to manage its bundles then depend
    +    // on the bundle entity.
    

    "The this" :-)

    claudiu.cristea’s picture

    Status: Reviewed & tested by the community » Needs review
    FileSize
    923 bytes
    21.37 KB

    Ouch! Sorry :)

    claudiu.cristea’s picture

    Status: Needs review » Reviewed & tested by the community

    Setting back to RTBC per #98.

    alexpott’s picture

    Status: Reviewed & tested by the community » Fixed

    I'm committing this under the maintainer discretion provision in the beta evaluation policy. This makes bundle behave like other entity values - when an entity does not have a bundle it is NULL. Committed 877fd18 and pushed to 8.0.x. Thanks!

    Thanks for adding the beta evaluation to the issue summary.

    • alexpott committed 877fd18 on 8.0.x
      Issue #2346857 by andypost, claudiu.cristea, amateescu, m1r1k, Mile23,...

    Status: Fixed » Closed (fixed)

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