Updated: Comment #N

Problem/Motivation

The EntityType class that was committed in [#] provides a nice API for dealing with entity info, such as methods to get the bundle, label etc... However, The constructor just adds all first level items as a property on the EntityType class. This is fine for all the keys that have been declared in the class, but anything else will just be a public property. Ideally we don't want to be mixing protected and public properties like. Well, in general we don't really want public properties.

Proposed resolution

For any unknown properties, store them in an array called $additional.

Remaining tasks

N/A

User interface changes

N/A

API changes

N/A

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because breaking property optimization is bad
Issue priority Normal because it's not *THAT* bad
Disruption Not disruptive at all

Comments

damiankloip’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new15.38 KB
tim.plunkett’s picture

I'm not too concerned about the public properties, but this does solve that.
I wonder if this will really be better in the end though.

  1. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
    @@ -15,188 +15,57 @@
    +   *   - 'static_cache': (bool) Indicates whether entities should be statically
    

    These shouldn't have quotes around them.

  2. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
    @@ -15,188 +15,57 @@
    -   * Indicates whether entities should be statically cached.
    -   *
    -   * @var bool
    -   */
    -  protected $static_cache;
    

    I mainly worry about entity type authors, as this makes the annotation keys even harder to find.

  3. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
    @@ -326,7 +193,9 @@ public function getController($controller_type) {
    -    $this->controllers[$controller_type] = $value;
    +    $controllers = $this->getControllers();
    +    $controllers[$controller_type] = $value;
    +    $this->set('controllers', $controllers);
    

    This kinda sucks.

  4. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
    @@ -358,42 +229,43 @@ public function setList($class) {
    -    return $this->admin_permission ?: FALSE;
    +    return $this->get('admin_permission', FALSE);
    

    This is a wash, either way.

  5. +++ b/core/lib/Drupal/Core/Entity/EntityType.php
    @@ -439,77 +313,77 @@ public function setLabelCallback($callback) {
    -    return !empty($this->translatable);
    

    I wonder if this will present a problem (isset vs empty)? Hopefully not.

damiankloip’s picture

StatusFileSize
new15.33 KB
new4.75 KB

I mainly worry about entity type authors, as this makes the annotation keys even harder to find.

I'm not sure how this makes them harder to find? Having a documented array structure like this is more akin to the annotation. Do you not think the mapping (in people's minds) from annotation keys to class properties is slightly more tedious? It is definitely not obviously that these properties map to that, unless you understand what's going on internally.

This kinda sucks.

Yeah, that does suck a bit. This was a pretty quick implementation but I am ok with doing something like that. It's an internal implementation after all. Any ideas on how to make that better? I could look at doing something using NestedArray? If not, I can certainly live with that. I've seen worse things...

I wonder if this will present a problem (isset vs empty)? Hopefully not.

I think not, everything seems ok at the moment. Well, let's hope that's the case anyway :)

eclipsegc’s picture

So, this issue and #2169853: EntityType Annotation does not extend AnnotationBase are sort of similar and also sort of opposed.

One of the observations I've made here is that if the EntityType annotation moves to AnnotationBase, we should probably enumerate the properties common to all Entity Types on it. I'm doing some very simple filtering of the values passed to the annotation and putting any that are not also properties into an array together. With regard to how this actually affects the Annotation, I fell it's the best of all worlds since we can continue to add non-property elements to the annotation to extend the API in contrib, but we also set a standard for every required property.

The flip side to all of this is 2 fold:

  1. With regard to the values that are passed into the EntityTypeInterface class upon instantiation (during AnnotationInterface::get()) I'm a little irritated that I have to refactor the Annotation into an array again. It feels like 1 step forward, 2 steps back.
  2. I'm not sure I see the purpose of the EntityType annotation class AND the EntityType (interface) class that we use as a default for all entities. We can still override what is returned with an entity_type_class property, and if that's set instantiate and return it, but it seems to me the Annotation and Interface class could be one in the same.

This being the first discovery methodology to leverage class instances as definitions puts us in unexplored territory (at least within Drupal 8) and I want to keep an open mind about what the implementation could/should do. Still that being said, moving to a pure array definition of the "properties" feels like a drastic step backwards imo, and I'd prefer we not do that. I'm not really making an argument with regard to the specifics of the "entity system" itself, I'm speaking more in terms of just plugins in general.

Eclipse

filijonka’s picture

First of all I'm a lil bit concerned that we OOP speaking think that it's ok to add properties that are not defined by the class, if you as user wanna add properties to a class that isn't defined, extend it and add your own properties and functions for it if needed. Otherwise it's will be hard to say what kind of object is this.

So in my opionon the current solution is not done correctly by letting any properties be added.

IF this is still something that is wanted it's clearly not good as it is since the properties not defined by class will be public but the solution to add a property that will hold any user added property in a associativ array.

dawehner’s picture

IMHO not storing public stuff is still the right thing to do.

dawehner’s picture

Especially because it also breaks some of the internal PHP optimizations: #2531564: Fix leaky and brittle container serialization solution

tim.plunkett’s picture

What public stuff? It's all protected. What is broken here?

damiankloip’s picture

What about when contrib gets involved, any key that is not defined will just be public properties on the entity type. E.g. I am looking at a contrib module D8 port of OG, they have not touched it for a while, and still have a 'module' key in the annotation. So that's now a public property on the entity types.

It's just not broken in core because core is careful about what is implemented in the annotation.

damiankloip’s picture

Specifically this in the constructor:

foreach ($definition as $property => $value) {
  $this->{$property} = $value;
}
damiankloip’s picture

StatusFileSize
new658 bytes

Spoke to Tim, we could just have something like this. Might want a new Exception or something, and maybe a better message!

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new1.2 KB
new567 bytes

Hope we didn't care about BaseFieldOverrideStorage too much...

tim.plunkett’s picture

StatusFileSize
new590 bytes
new1.77 KB

I love checking DrupalCI for live results.
Fixing EntityTestUpdate for #2100343: Remove 'fieldable' key in entity definitions in favour of 'field_ui_base_route'.

tim.plunkett’s picture

StatusFileSize
new2.84 KB
new1.06 KB

<3

I guess I'll open a test-only issue to finish this... Next patch

tim.plunkett’s picture

The docs on content_translation_entity_type_alter() *tell* you to break this by adding arbitrary keys. :(

tim.plunkett’s picture

Status: Needs work » Needs review
StatusFileSize
new9.03 KB
new6.19 KB

Here is an example of a fix for that (and an example for contrib). The obvious problem here is that only one module can set entity_type_class...

tim.plunkett’s picture

berdir’s picture

+++ b/core/modules/migrate/src/Entity/Migration.php
@@ -24,7 +24,7 @@
  *   label = @Translation("Migration"),
- *   module = "migrate",
+ *   provider = "migrate",
  *   handlers = {

Can be removed, set automatically?

Other than that, this approach doesn't make sense to me. The class approach doesn't work IMHO, that allows to set exactly one additional property. It's quite common for modules to extend this, we just have the luxury in core to actually be able to define those on the annotation class. Contrib doesn't. common_reference_target is entity_reference specific and I know that entity_reference_revisions adds a parallel property for that, field_ui_base_route is obviously field_ui specific, permission_granularity is also a (currently at least) a content translation specific thing,

It's also an API change.

Two alternatives:

* Transparently store everything that is not a defined property in $this->additional or some other property. No API change.
* Offer separate methods to set arbitrary flags. If combined with enforcing it like here, it would be an API change too.

tim.plunkett’s picture

Transparently store everything that is not a defined property in $this->additional or some other property. No API change.

That was my first suggestion to @damiankloip on IRC, I think that is the way forward.

damiankloip’s picture

I am good with storing additional data in additional. Anything that is not just adding public properties willy nilly :)

tim.plunkett’s picture

StatusFileSize
new3.64 KB
new2.18 KB
damiankloip’s picture

StatusFileSize
new5.59 KB
new1.95 KB

Nice, I like that. And some tests.

tim.plunkett’s picture

So the only problem with those tests.... They pass with or without the test.
Is there any way to assert the PHP 5.4 property optimization thing?

damiankloip’s picture

StatusFileSize
new2.68 KB
new6.32 KB
new1.28 KB

Well, we could just use ReflectionObject and test for any public properties. That should work fine, like this. Thoughts?

tim.plunkett’s picture

Title: Refactor EntityType internal implementation to use an array » EntityType should put unknown properties into an array
Category: Task » Bug report
Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs issue summary update, -Needs beta evaluation

Thanks!

alexpott’s picture

+++ b/core/lib/Drupal/Core/Entity/EntityType.php
@@ -233,6 +233,13 @@ class EntityType implements EntityTypeInterface {
+  protected $additional = [];

So this could potentially break any entity which defines additional already right? So there is some potential disruption.

berdir’s picture

@alexpott: No, not an entity. It would need to be a custom entity type annotation class, I'm not even sure that is supported with the simple annotation parser that we use now.

alexpott’s picture

@catch asked in IRC

I don't think there are upgrade path implications, but do we actually rely on additional in core?
i.e. what breaks if we just don't add extra crap?

Can we just remove support for setting undeclared properties?

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

For #31

alexpott’s picture

Status: Needs review » Reviewed & tested by the community

Ah of course ... hook_entity_type_alter() for example content_translation_entity_type_alter().

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

This issue is a normal bug fix, and doesn't include any disruptive changes, so it is allowed per https://www.drupal.org/core/beta-changes. Committed 16f0ab8 and pushed to 8.0.x. Thanks!

I ponder upgrade path and other considerations I think this is safe to do.

  • alexpott committed 16f0ab8 on 8.0.x
    Issue #2167603 by damiankloip, tim.plunkett: EntityType should put...

Status: Fixed » Closed (fixed)

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