Problem/Motivation

Public properties on our entities allow APIs to be circumvented, and increases the likelihood of introducing bugs because an entity object may not be in a reliable or accurate state. (Additionally, ->something->value is cumbersome DX.)

We need an issue for every entity type. The content entities (user comment taxonomy_term) are the most important.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because properties should not be public, API methods should not be allowed to be sidestepped.
Issue priority Major because this meta goes across the entire system. But each child will be a normal bug.
Prioritized changes Prioritized since it is a bug and it reduces fragility.
Disruption Somewhat disruptive for core as well as contributed and custom modules:
  • BC break for anything using the public properties: code will need to convert to the methods
  • BC break for anything (mis)using properties that should not really be public: will require minor refactoring
  • BC break for alternate implementations of a given entity interface (rare/probably nonexistent): they will need to implement the new methods

But impact will be greater than the disruption, so it is allowed in the beta.

Proposed resolution

->getSomething() will provide a proper, reliable API for each entity type.

We did this by, for each entity, opening a new issue (coping one of the ones already existing. dreditor clone patch was helpful #1803622: Add a create follow-up issue link which fills in values (clone an issue)).
http://screencast.com/t/4qPjNP8fEHVw shows one way of creating a sub issue.

Remaining tasks

  • (done) Figure out how to list all Entities. See #5.
  • (done) Open all issues.
  • (done) Write some hints that patch producers will find helpful for creating patches for each issue.
  • (still needs more helpful hints) Write review instructions with hints of what reviewers will find useful when reviewing sub issues.

User interface changes

Sub issues have no UI changes.

API changes

Sub issues have API additions, actual getter methods.

TBD.

Testing

Added #2527114: Create PHPUnit test that Entity class variables are protected or are allowed public to make sure that there will be no new public class variables added as a accident.

Sub-Issues

Make class variables protected Issue
FieldConfigBase #2529034: Replace direct access to FieldConfigBase::default_value with methods
Migrate #2525002: Make the class variables protected for Migration
Node #2525068: Document the class variable Node::in_preview as will stay public
DateFormat #2527076: Make the class variables protected for Drupal\Core\Datetime\Entity\DateFormat

Completed tasks

Entity (link to api.d.o) Issue
Content entities
Comment #2028025: Expand CommentInterface to provide methods
Feed #2028037: Expand FeedInterface with methods
Term #2016701: Expand TermInterface to provide methods
BlockContent #2028035: Expand CustomBlockInterface with methods
Node #2015123: Expand NodeInterface to provide getters and setters
File #1818568: Convert files to the new Entity Field API
Item #2028039: Expand ItemInterface (aggregator.module) with methods
Message #1983548: Convert contact message entities to the new Entity Field API
User #2026347: Adding methods to UserInterface/AccountInterface
Config entities
Action #2384539: Make the class variables protected for Action
ConfigurableLanguage #2384541: Make the class variables protected for ConfigurableLanguage
Filterformat #2384487: Make the class variables protected for FilterFormat
ImageStyle #2384535: Make the class variables protected for ImageStyle
Migration #2384529: Make the class variables protected for Migration
Nodetype #2384481: Make the class variables protected for NodeType
RDFMapping #2384531: Make the class variables protected for RdfMapping
Searchpage #2384537: Make the class variables protected for SearchPage entity
ShortcutSet #2384527: Make the class variables protected for ShortcutSet
Block #2030571: Expand Block with methods
ConfigTest #2030595: Expand ConfigTest with methods
BlockContentType #2030597: Expand BlockContent and BlockContentType with methods
EntityDisplay #2030607: Expand EntityDisplayBase with methods
FieldStorageConfig #2030633: Expand FieldStorageConfig with methods
FilterFormat #2030641: Expand FilterFormat with methods
Vocabulary #2030669: Expand Vocabulary with methods
Action #2030513: Expand Action with methods
Breakpoint #2030585: Expand Breakpoint with methods
BreakpointGroup #2030587: Expand BreakpointGroup with methods
Category #2030591: Expand ContactForm with methods
Editor #2030605: Expand Editor with methods
EntityFormDisplay #2030629: Expand EntityFormDisplay with methods
EntityViewMode #2030613: Expand EntityViewMode (really EntityDisplayModeBase) with methods
ImageStyle #2030643: Expand ImageStyle with methods
Menu #2030645: Expand Menu with methods
MenuLink #2030649: Expand MenuLink with methods
PictureMapping #2030653: Expand ResponsiveImageMapping with methods
Role #2030655: Expand Role with methods
Shortcut #2030657: Expand Shortcut with methods
Tour #2030661: Expand Tour with methods
UnboundDisplay #2030663: Expand UnboundDisplay with methods

Hints to patch producers (based off of #12)

Ideally the visibility of the properties which are getters and setters in this case can force people to use the property directly and instead of using it directly, use it as a method so while working on the patch you can make the visibility as protected and change them back to public before RTBC - as stated in this comment leave it protected.

Find each property in the entity and make a getter.
See #2015123: Expand NodeInterface to provide getters and setters for an example.

Please read a couple examples

the discussions in
#2016701: Expand TermInterface to provide methods
and
#2028025: Expand CommentInterface to provide methods
to see some of the common complications so you can avoid them in your issue.

do not duplicate already implemented functionality

Also (see #12),
do not add getter methods for things that already exist on EntityInterface, do not duplicate:

  • id() for the primary id of the entity. id() is already doing the same thing, so do not make getId().
  • getRevisionId() for the revision id (only relevant for entities that have revisions: node/custom block)
  • bundle() for the bundle (e.g. the type for nodes, vocabulary for terms, ...)
  • uuid()
  • language()

Check if it makes sense

Only add setters if it makes sense conceptually: setId() is not necessary for database/content entities, as the ID is automatically generated for them when they are saved. Another example: setUUID(), this is set automatically initially and must not be changed afterwards.

Sometimes setters might seem to be needed, mostly in tests. Usually tests are setting something they should not. Try opening related issues (to the child) that refactor the test to not need to set something. Usually this can be done by creating a new whatever and passing in the values it needs to have at the time of creation.

Avoid conflicts

Look out for conflicts: EntityInterface for example already has isNew(). but it does something different. If making a new method, with a different purpose, pink a unique name for it.

In general

Links in the tables go to api.d.o
For example, the first config entity: Action
https://api.drupal.org/api/drupal/core%21modules%21system%21lib%21Drupal...
can see it's a class (not an interface).
It's not content entity (compare to Node)
And there is a table which shows the properties. Filter to just show properties, click on the heading Modifiers (twice) to sort and put public properties in a group at the top of that table.

For content entities, for example Node,
all of the public properties are deleted, and the init() method is deleted.

For config entities, for example Action,
the public properties should become protected.

Protected properties can be listed in the sub-issues, and considered case by case if a getter makes sense.

Initial patches in the sub-issues should not rename properties, just do a straight conversion to a getter.

Hints to patch reviewers

For each method added, check the class being extended or implemented. If a new method name is already in that class, watch out, it will be a conflict.

Please read a couple examples

the discussions in
#2016701: Expand TermInterface to provide methods
and
#2028025: Expand CommentInterface to provide methods
to see some of the common points other reviews have made and see if the issue you are reviewing can use similar feedback.

check for duplicated functionality

getter methods should not have been added for things that already exist on EntityInterface. For example, these should not have been implemented

  • getId() should not have been added, since primary id of the entity can be gotten with the already existing id()
  • read the classes that are being extended or implemented to see if there might have been methods to use that serve the same purpose (even if the name might be a little different).

Check if it makes sense

Setters should only have been added if it makes sense conceptually: setId() is not necessary for database/content entities, as the ID is automatically generated for them when they are saved. Another example: setUUID() is not needed, this is set automatically initially and must not be changed afterwards.

Check for conflicts

Look out for conflicts: EntityInterface for example already has isNew(). but it does something different. If making a new method, with a different purpose, the two will need unique names. It might take some thought to name things by their purpose.

CommentFileSizeAuthor
#5 class-list.png226.84 KBYesCT
#5 class-ng-properties.png289.77 KBYesCT
#5 ng.png110.79 KBYesCT
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

YesCT’s picture

I'm not sure about the tags for this and the sub issues.

Will the getters we want just be for properties or other things too?

I'm going to create a few issues.

I'll try and figure out which ones are NG.
grep -R "extends EntityNG" *
gives

core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php:class Feed extends EntityNG implements FeedInterface {
core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Item.php:class Item extends EntityNG implements ItemInterface {
core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php:class CustomBlock extends EntityNG implements CustomBlockInterface {
core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php:class Comment extends EntityNG implements CommentInterface {
core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php:class Node extends EntityNG implements NodeInterface {
core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php:class EntityTest extends EntityNG {
core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php:class Term extends EntityNG implements TermInterface {
core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php:class User extends EntityNG implements UserInterface {

grep -R "extends Entity " *

core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php:abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface {
core/lib/Drupal/Core/Entity/EntityNG.php:class EntityNG extends Entity {
core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php:class Message extends Entity implements MessageInterface {
core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php:class TestEntity extends Entity {
core/modules/field_ui/tests/modules/field_ui_test/lib/Drupal/field_ui_test/Plugin/Core/Entity/FieldUITestNoBundle.php:class FieldUITestNoBundle extends Entity {
core/modules/file/lib/Drupal/file/Plugin/Core/Entity/File.php:class File extends Entity implements FileInterface {
core/modules/menu_link/lib/Drupal/menu_link/Plugin/Core/Entity/MenuLink.php:class MenuLink extends Entity implements \ArrayAccess, MenuLinkInterface {
core/modules/system/tests/modules/entity_cache_test_dependency/lib/Drupal/entity_cache_test_dependency/Plugin/Core/Entity/EntityCacheTest.php:class EntityCacheTest extends Entity {

Is that an ok way to find all Entities?

YesCT’s picture

Issue summary: View changes

dont list each property in the summary of sub-issues.. just the patch for that. :) -c

YesCT’s picture

alternative to get a list (hint from dawehner): phpstorm, command-o entityinterface, control-h to show hierarchy
http://screencast.com/t/bsHHvjGpw

EntityInterface (core/lib/Drupal/Core/Entity/EntityInterface.php)
ConfigEntityInterface (core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php)
ActionConfigEntityInterface (core/modules/system/lib/Drupal/system/ActionConfigEntityInterface.php)
Action (core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php)
BlockInterface (core/modules/block/lib/Drupal/block/BlockInterface.php)
Block (core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php)
BreakpointGroupInterface (core/modules/breakpoint/lib/Drupal/breakpoint/BreakpointGroupInterface.php)
BreakpointGroup (core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/BreakpointGroup.php)
BreakpointInterface (core/modules/breakpoint/lib/Drupal/breakpoint/BreakpointInterface.php)
Breakpoint (core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/Breakpoint.php)
CategoryInterface (core/modules/contact/lib/Drupal/contact/CategoryInterface.php)
Category (core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php)
ConfigEntityBase (core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php)
Action (core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php)
Block (core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php)
Breakpoint (core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/Breakpoint.php)
BreakpointGroup (core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/BreakpointGroup.php)
Category (core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php)
ConfigTest (core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php)
ConfigQueryTest (core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigQueryTest.php)
CustomBlockType (core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php)
DisplayBase (core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php)
Display (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php)
UnboundDisplay (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php)
Editor (core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php)
EntityDisplayBase (core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php)
EntityDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php)
EntityFormDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityFormDisplay.php)
EntityViewMode (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityViewMode.php)
Field (core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php)
FieldInstance (core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php)
FilterFormat (core/modules/filter/lib/Drupal/filter/Plugin/Core/Entity/FilterFormat.php)
ImageStyle (core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php)
Menu (core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Menu.php)
PictureMapping (core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php)
Role (core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php)
Shortcut (core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php)
Tour (core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php)
View (core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php)
Vocabulary (core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php)
ConfigTestInterface (core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestInterface.php)
ConfigTest (core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php)
ConfigQueryTest (core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigQueryTest.php)
CustomBlockTypeInterface (core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeInterface.php)
CustomBlockType (core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php)
DisplayInterface (core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php)
BoundDisplayInterface (core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php)
Display (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php)
DisplayBase (core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php)
Display (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php)
UnboundDisplay (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php)
UnboundDisplayInterface (core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayInterface.php)
UnboundDisplay (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php)
EditorInterface (core/modules/editor/lib/Drupal/editor/EditorInterface.php)
Editor (core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php)
EntityDisplayBaseInterface (core/modules/entity/lib/Drupal/entity/EntityDisplayBaseInterface.php)
EntityDisplayBase (core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php)
EntityDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php)
EntityFormDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityFormDisplay.php)
EntityDisplayInterface (core/modules/entity/lib/Drupal/entity/EntityDisplayInterface.php)
EntityDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php)
EntityFormDisplayInterface (core/modules/entity/lib/Drupal/entity/EntityFormDisplayInterface.php)
EntityFormDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityFormDisplay.php)
EntityViewModeInterface (core/modules/entity/lib/Drupal/entity/EntityViewModeInterface.php)
EntityViewMode (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityViewMode.php)
FieldInstanceInterface (core/modules/field/lib/Drupal/field/FieldInstanceInterface.php)
FieldInstance (core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php)
FieldInterface (core/modules/field/lib/Drupal/field/FieldInterface.php)
Field (core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php)
FilterFormatInterface (core/modules/filter/lib/Drupal/filter/FilterFormatInterface.php)
FilterFormat (core/modules/filter/lib/Drupal/filter/Plugin/Core/Entity/FilterFormat.php)
ImageStyleInterface (core/modules/image/lib/Drupal/image/ImageStyleInterface.php)
ImageStyle (core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php)
MenuInterface (core/modules/system/lib/Drupal/system/MenuInterface.php)
Menu (core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Menu.php)
PictureMappingInterface (core/modules/picture/lib/Drupal/picture/PictureMappingInterface.php)
PictureMapping (core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php)
RoleInterface (core/modules/user/lib/Drupal/user/RoleInterface.php)
Role (core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php)
ShortcutInterface (core/modules/shortcut/lib/Drupal/shortcut/ShortcutInterface.php)
Shortcut (core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php)
TourInterface (core/modules/tour/lib/Drupal/tour/TourInterface.php)
Tour (core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php)
ViewStorageInterface (core/modules/views/lib/Drupal/views/ViewStorageInterface.php)
View (core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php)
ViewUI (core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php)
VocabularyInterface (core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyInterface.php)
Vocabulary (core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php)
ContentEntityInterface (core/lib/Drupal/Core/Entity/ContentEntityInterface.php)
CommentInterface (core/modules/comment/lib/Drupal/comment/CommentInterface.php)
Comment (core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php)
CustomBlockInterface (core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockInterface.php)
CustomBlock (core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php)
FeedInterface (core/modules/aggregator/lib/Drupal/aggregator/FeedInterface.php)
Feed (core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php)
FileInterface (core/modules/file/lib/Drupal/file/FileInterface.php)
File (core/modules/file/lib/Drupal/file/Plugin/Core/Entity/File.php)
ItemInterface (core/modules/aggregator/lib/Drupal/aggregator/ItemInterface.php)
Item (core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Item.php)
MenuLinkInterface (core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php)
MenuLink (core/modules/menu_link/lib/Drupal/menu_link/Plugin/Core/Entity/MenuLink.php)
NodeInterface (core/modules/node/lib/Drupal/node/NodeInterface.php)
Node (core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php)
TermInterface (core/modules/taxonomy/lib/Drupal/taxonomy/TermInterface.php)
Term (core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php)
Entity (core/lib/Drupal/Core/Entity/Entity.php)
ConfigEntityBase (core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php)
Action (core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php)
Block (core/modules/block/lib/Drupal/block/Plugin/Core/Entity/Block.php)
Breakpoint (core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/Breakpoint.php)
BreakpointGroup (core/modules/breakpoint/lib/Drupal/breakpoint/Plugin/Core/Entity/BreakpointGroup.php)
Category (core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Category.php)
ConfigTest (core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php)
ConfigQueryTest (core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigQueryTest.php)
CustomBlockType (core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php)
DisplayBase (core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php)
Display (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php)
UnboundDisplay (core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php)
Editor (core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php)
EntityDisplayBase (core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php)
EntityDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityDisplay.php)
EntityFormDisplay (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityFormDisplay.php)
EntityViewMode (core/modules/entity/lib/Drupal/entity/Plugin/Core/Entity/EntityViewMode.php)
Field (core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php)
FieldInstance (core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php)
FilterFormat (core/modules/filter/lib/Drupal/filter/Plugin/Core/Entity/FilterFormat.php)
ImageStyle (core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php)
Menu (core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Menu.php)
PictureMapping (core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php)
Role (core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php)
Shortcut (core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php)
Tour (core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php)
View (core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php)
Vocabulary (core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Vocabulary.php)
EntityCacheTest (core/modules/system/tests/modules/entity_cache_test_dependency/lib/Drupal/entity_cache_test_dependency/Plugin/Core/Entity/EntityCacheTest.php)
EntityNG (core/lib/Drupal/Core/Entity/EntityNG.php)
Comment (core/modules/comment/lib/Drupal/comment/Plugin/Core/Entity/Comment.php)
CustomBlock (core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php)
EntityTest (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php)
EntityTestDefaultAccess (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestDefaultAccess.php)
EntityTestLabel (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestLabel.php)
EntityTestLabelCallback (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestLabelCallback.php)
EntityTestMul (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php)
EntityTestNoLabel (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestNoLabel.php)
EntityTestRender (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRender.php)
EntityTestRev (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php)
EntityTestMulRev (core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php)
Feed (core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php)
Item (core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Item.php)
Node (core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php)
Term (core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Core/Entity/Term.php)
User (core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php)
FieldUITestNoBundle (core/modules/field_ui/tests/modules/field_ui_test/lib/Drupal/field_ui_test/Plugin/Core/Entity/FieldUITestNoBundle.php)
File (core/modules/file/lib/Drupal/file/Plugin/Core/Entity/File.php)
MenuLink (core/modules/menu_link/lib/Drupal/menu_link/Plugin/Core/Entity/MenuLink.php)
Message (core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php)
TestEntity (core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php)
BundleKeyTestEntity (core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleKeyTestEntity.php)
BundleTestEntity (core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleTestEntity.php)
CacheableTestEntity (core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/CacheableTestEntity.php)
EntityBCDecorator (core/lib/Drupal/Core/Entity/EntityBCDecorator.php)
UserBCDecorator (core/modules/user/lib/Drupal/user/UserBCDecorator.php)
MessageInterface (core/modules/contact/lib/Drupal/contact/MessageInterface.php)
Message (core/modules/contact/lib/Drupal/contact/Plugin/Core/Entity/Message.php)
UserInterface (core/modules/user/lib/Drupal/user/UserInterface.php)
User (core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php)
UserBCDecorator (core/modules/user/lib/Drupal/user/UserBCDecorator.php)

YesCT’s picture

Issue summary: View changes

list the entities from the grep

YesCT’s picture

Issue summary: View changes

added term issue

YesCT’s picture

Issue summary: View changes

added link to video of creating sub issue

YesCT’s picture

Trying to write some hints to patch producers...
Looking at the Node issue, patch from #7 in there #2015123-7: Expand NodeInterface to provide getters and setters
has a section that begins like:

+++ b/core/modules/node/lib/Drupal/node/NodeInterface.phpundefined
@@ -14,4 +14,66 @@
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index 5503100..65cda81 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.phpundefined
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\node\NodeInterface;
+use Drupal\node\NodeBCDecorator;
 
 /**
  * Defines the node entity class.
@@ -53,186 +54,84 @@
 class Node extends EntityNG implements NodeInterface {
 
   /**
-   * The node ID.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $nid;

So, I'm thinking of looking at similar files and using the @var list to suggest what getters we should make.

YesCT’s picture

Issue summary: View changes

updated remaining tasks.

YesCT’s picture

No @var's in Term, so maybe didn't need that issue.
I'll take a break from this and come back to make some sub issues tomorrow.

YesCT’s picture

FileSize
110.79 KB
289.77 KB
226.84 KB

Interfaces wont have properties. Look at *classes*.

From https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...

The list of classes is under "Implemented by"
class-list.png

Looking at the first one, action
https://api.drupal.org/api/drupal/core%21modules%21system%21lib%21Drupal...
can see it's a class (not an interface).
It's not NG (compare to Node)
And there is a table which shows the properties. Filter to just show properties, click on the heading Modifiers (twice) to sort and put public properties in a group at the top of that table.
class-ng-properties.png

Node https://api.drupal.org/api/drupal/core%21modules%21node%21lib%21Drupal%2...
shows it's NG.

ng.png

For NG entities, for example Node,
all of the public properties are deleted, and the init() method is deleted.

For non-NG entities, for example Action,
the public properties should become protected.

Protected properties can be listed in the sub-issues, and considered case by case if a getter makes sense.

Initial patches in the sub-issues should not rename properties, just do a straight conversion to a getter.

----

Taking out Base and BC from the list yeilds:
Action
Block
Breakpoint
BreakpointGroup
Category
Comment
ConfigTest
CustomBlock
CustomBlockType
Display
Editor
Entity
EntityDisplay
EntityFormDisplay
EntityViewMode
Feed
Field
FieldInstance
File
FilterFormat
ImageStyle
Item
Menu
MenuLink
Message
Node
PictureMapping
Role
Shortcut
Term
Tour
UnboundDisplay
User
View
ViewUI
Vocabulary

tim.plunkett’s picture

Title: [Meta] Expand Entity Interfaces to provide getters » [Meta] Expand Entity Type interfaces to provide getters
tim.plunkett’s picture

Issue summary: View changes

Updated issue summary.

YesCT’s picture

Issue summary: View changes

better list of entity types

Xano’s picture

Are we replacing public property access by getters and setters because it's cumbersome, or because property access is tight coupling and we don't want that? In case of the latter, we will also need to convert entity_create() calls to no longer provide a second argument, and we can only allow ourselves to access properties from within the entity class itself.

Berdir’s picture

Title: [Meta] Expand Entity Type interfaces to provide getters » [Meta] Expand Entity Type interfaces to provide methods

Woah, I didn't know this issue :) Changing title to *methods*, it's not just getters.

Contact Message and File are NG and are done, the NG conversion patch already added an interface.

User is in #2026347: Adding methods to UserInterface/AccountInterface. Will update the summary asap.

@Xano: The reason we remove the public properties for NG entities is that they're not actually public, they're just a hack to get autocomplete when we type hint on the class. There's the crazy init() method that then unset()'s them, so that __get() is invoked. Which we stop doing (type hint on classes), so that hack is useless.

That said, the methods are for convenience. It's still valid to pass values to entity_create() and access them directly. NG exposes it's fields dynamically and you can generically access them, if you want to work with entities in a generic way. That's the whole point of it's existence. Rest, Rules, edit.module, translation management, ... If you specifically access nodes and type hint on NodeInterface, it's recommended to use the methods.

Berdir’s picture

Issue summary: View changes

updated hints to patch producers encorporating info from #5

Berdir’s picture

Issue summary: View changes

Updated issue summary.

Berdir’s picture

Updated change notice a bit.

I think the separation should be database vs config entities, not NG vs. not NG.

Also note that

For NG entities, for example Node,
all of the public properties are deleted, and the init() method is deleted.

The second line is not an API *change*, as accessing it will still work, the public properties are just a hack for autocomplete, as described above. Access already goes through __get().

While..

For non-NG entities, for example Action,
the public properties should become protected.

the second line here is an API *change*, $action->something will no longer work. So we can still add the interface methods any time we want, but changing the properties to protected is a different thing.

Berdir’s picture

Berdir’s picture

Issue summary: View changes

Fix markup for File

Berdir’s picture

Issue summary: View changes

Updated issue summary.

Berdir’s picture

Issue summary: View changes

Updated issue summary.

Berdir’s picture

Issue tags: +Novice

Ah, instead of creating the issues myself, I'm just going to tag this as Novice directly :)

So if all issues for the NG entities already have issues, feel free to create additional ones for the second group of entities.

Berdir’s picture

Issue summary: View changes

Updated issue summary.

alarcombe’s picture

Issue summary: View changes

Added correct link to Expand ItemInterface (aggregator.module) with methods

YesCT’s picture

Issue summary: View changes

added action issue

plopesc’s picture

Issue summary: View changes

Creating new class follow-up issues

Berdir’s picture

Note:

* Do not add getter methods for things that already exist on EntityInterface, do not duplicate:
** id() for the primary id of the entity (no getId())
** getRevisionId() for the revision id (only relevant for entities that have revisions: node/custom block)
** bundle() for the bundle (e.g. the type for nodes, vocabulary for terms, ...)
** uuid()
** language()
* Only add setters if it makes sense conceptually: setId() is not necessary for database/content entities, as the ID is automatically generated for them when they are saved. Another example: setUUID(), this is set automatically initially and must not be changed afterwards.
* Look out for conflicts: EntityInterface for example already has isNew().

When in doubt, look at some other issues of similar entity types and discuss with a person nearby :)

Berdir’s picture

Issue summary: View changes

Adding new follow-up issues

YesCT’s picture

Issue summary: View changes

updated with hints.

YesCT’s picture

Issue summary: View changes

oops wrong comment number.

Wim Leers’s picture

So… #9 suggests that this should not happen to config entities. Yet #2030605: Expand Editor with methods exists, while Editor is a config entity. Can somebody please clarify what is going on here?

I agree that

->something->value

is cumbersome, but that's not actually what happens for config entities (or at least not for Editor).

tim.plunkett’s picture

#9 is just saying lets not make them protected.
We should still add methods and never use the properties directly.

For purposes of the patch it would be helpful to make them all protected to make sure the patch works, then switch them back to public before RTBC.

Berdir’s picture

Yes, what @tim.plunkett said, we type hint on interfaces, that means you don't see the public properties of the class and we need methods :)

Berdir’s picture

Issue summary: View changes

organizing

Wim Leers’s picture

#14 & #15: okay. I've done this at #2030605-2: Expand Editor with methods now. But… I still fail to see *why* we need to do this in the first place for config entities. The config system requires that all properties are public, so nothing prevents developers from using the public properties rather than the accessor methods. So now you have two ways to do the exact same thing. Which is inferior to what we have now.

So: why?

Xano’s picture

The config system requires that all properties are public

What about \Drupal\Core\Entity\EntityInterface::getExportProperties()? That, in combination with entity type-specific protected properties, works fine.

tim.plunkett’s picture

The config system requires that all properties are public

Yeah that's 100% wrong. The only properties required to be public are $id and $uuid, and that's for stupid reasons anyway.
See all of the properties on \Drupal\views\Plugin\Core\Entity\View, and the getExportProperties() at the bottom.

tim.plunkett’s picture

Ivan Zugec’s picture

Quick question, should patches for this meta issue have tests? (I asked the same question in #2030641: Expand FilterFormat with methods)

It looks like some do and some don't.

For example, the following patches do not have tests:

- #2015123: Expand NodeInterface to provide getters and setters
- #2026347: Adding methods to UserInterface/AccountInterface

And the following do have patches:

- #1983548: Convert contact message entities to the new Entity Field API
- #1818568: Convert files to the new Entity Field API

Xano’s picture

Yes, we should have full code coverage.

Xano’s picture

Issue summary: View changes

added @ to some issues

kgoel’s picture

Can someone please confirm if getters and setters need to be protected and change visibility into public before RTBC as stated here - https://drupal.org/node/2016679#comment-7616179

johnennew’s picture

I'm going to go for setting the parameters as protected for ConfigEntityBase Entities as @tim.plunkett suggests in #18. This requires an overridden version of \Drupal\Core\Config\Entity\ConfigEntityBase::getExportProperties() function on the Entity copying the pattern in the view Entity.

Note the issue description describes this.

kristofferwiklund’s picture

I did some work with Breakpoint #2030585: Expand Breakpoint with methods and wrote some tests. And I was thinking should we have some common test file to making sure that the different entity classes does not define methods mention in #12. So a simple "if function exist" test for every entity? This should be possible to write in PHPUnit and should go fast.

kristofferwiklund’s picture

Issue summary: View changes

Updated issue summary.

sun’s picture

Why didn't we make all of the new setter methods chainable?

$entity = entity_create('foo')
  ->setLabel('Bar')
  ->setBody('Beer')
  ->save();
sun’s picture

Further diving into the example snippet of #25:

->setLabel('Bar')

#2015123: Expand NodeInterface to provide getters and setters added:

interface NodeInterface extends ContentEntityInterface, EntityChangedInterface {
...
  public function getTitle();
  public function setTitle($title);

However, getTitle() duplicates EntityInterface::label().

In turn, there are three Node entity methods now:

$label = $node->label();
$title = $node->getTitle();
var_dump($label == $title);
// TRUE

$node->setTitle('foo');
// Does not exist, even though "label" is the standard terminology for all entities.
//$node->setLabel('foo');

Since the whole point of this effort is DX, it would be good for DX to ensure consistency and sanity.

vijaycs85’s picture

Issue summary: View changes

Cleaning up sub-tasks...

webchick’s picture

Priority: Normal » Major
Issue tags: +beta blocker, +Needs issue summary update

I suppose this needs to be a beta blocker (either to finish the open patches, or to roll back the ones committed so far). It makes no sense to ship Drupal 8 with half the entities having raw properties and the other half having accessor methods; that's a recipe for total confusion.

The issue summary could do with a much better description of why we would spear-head such a massive API change post-API freeze ("->getSomething() would be nicer." doesn't quite cut it. ;)). We're 7 months into it and not half done yet. Not looking good.

Berdir’s picture

I don't have time right now to update the issue summary in detail, but if someone wants to work on it, here are some reasons and explanations.

We decided to use interfaces for entity objects whenever possible and type hint against those. Interfaces can not define class properties (public or not), only methods.

Assuming you're using an IDE with method autocomplete (PhpStorm, Netbeans, .. and if you're not, you should), go to a method that has a "NodeInterface $node" argument, write $node-> and you will see suggestions like getTitle(), isPublished() and so on.

Now do the same for TermInterface $term, and all you get is the generic methods from ContentEntityInterface and upwards. You don't see $term->name for example, because that's defined on Term, not TermInterface.

So, without specific methods, those interfaces are not half as useful as they could be.

Now, for content entities, everything is a field. You would have to write $node->title->value, not $node->title to access the title. And not doing so can result in pretty weird errors if you pass that to a function that expects a string or so.

Additionally, content entities do not actually work with public properties anymore, @fago came up with this crazy trick to define them and then in __construct() and __wakeup(), call $this->init(), which does an unset($this->name) and so on. The only reason to do that was to be able to get autocomplete for $term->name, which no longer works, as demonstrated above. That's why we want to remove it in #2095919: Kill ContentEntityBase::init() . And the idea was to wait on the remaining content issues (feed, comment, term) which replace those public properties with methods. We could alternatively just drop the remaining properties there, being able to remove that trick/method is my main motivation for doing this at the moment.

That said, at least for content entities, this is not an API change. $node->title->value still works. And there are no methods for configurable fields, there is no $node->getBody(), only $node->body->value. So there will always be a certain amount of inconsistencies, but that's IMHO not a reason to not do this at all.

For config entities, it's not an API change as long as we leave the public properties and don't change them to protected. Which I think we shouldn't do at this point. They don't have the additional problems that content entities have, so are IMHO not as important.

I also don't see why the inconsistency between different entity objects is such a problem. All those config entities are already way more unified than they were in 7.x, with a common API to load and save them. Moving from accessing properties to methods defined on interfaces and from functions to classes is an ongoing effort everywhere in 8.x, we're just trying to catch up with everyone else here.

So in my opinion, this is not a beta blocker. The only thing that I could possibly see as a beta blocker is the mentioned kill init() issue, because it's going to be very confusing if people pick the wrong entity type as an example, one that still relies on it. And we can do that without the three remaining content entity issues, if we have to, as described.

xjm’s picture

Priority: Major » Critical

Aha, this is one of the "missing Entity DX beta blockers" that I keep talking about. It's at least a beta target; it has significant enough impact on DX that we should try to finish beforehand.

Edit: I'm open to discuss it being a major beta target instead, but I'd really like to see the "expected" Entity API that will be used all over modules everywhere available by beta.

xjm’s picture

Priority: Critical » Major
Issue tags: -beta blocker +beta target

Discussed with @catch. Let's do this.

These are API additions for the most part, not BC breaks unless you are subclassing Node creating your own special flower MyNode implements NodeInterface or something, I think. Let's tag the child issues "API addition", "DX", and "beta target" accordingly.

xjm’s picture

Also, catch pointed out that we should stop doing these if they are not done by RC (maybe we could add them in 8.1.0 but not 8.0.1) but that they can probably keep happening after beta. Just it would be ideal if we got as much possible in before then for contrib DX.

xjm’s picture

Issue tags: +rc deadline
YesCT’s picture

not adding all the sub issues. just some related ones.

catch’s picture

So the only way this would be a BC break is the following (unless I missed something):

1. You are completely implementing a replacement Node class from scratch, implementing NodeInterface.

2. You are subclassing Node, and the implementations on the Node class aren't compatible with your implementation (because if they were compatible, then even this is not an API change).

Both #1 and #2 have minimal effect, and if a contrib module was affected, it's a very simple change to make.

For code interacting with the interface, rather than implementing it, it's only an API addition.

webchick’s picture

Right, it's technically only an API addition from a procedural point of view. But from a DX point of view, if half of the entities have accessor methods and the other half don't, it's going to create a very confusing situation, which is not what we want when we're trying to "complete" APIs.

I'm comfortable with major + beta target. Thanks to Berdir for the expanded reasoning in #29.

Berdir’s picture

In case of content entities and in combination with #2095919: Kill ContentEntityBase::init() , what could happen is that you take Term (Node is already changed), as an example, copy it for your own new entity type, adjust the public properties and change your init() implementation and then we remove the call to that method and very interesting things (tm) will happen. But that is also easy to fix by removing the properties and the method (there is no requirement to provide methods).

fago’s picture

Yeah, #2095919: Kill ContentEntityBase::init() makes sense even as beta blocker to me as it might confuse people.

But from a DX point of view, if half of the entities have accessor methods and the other half don't, it's going to create a very confusing situation, which is not what we want when we're trying to "complete" APIs.

True, but we won't have all of core following best practices by beta. So if some entities use less methods than others, that's not ideal but not a big deal imho - as long as there is consistent usage of patterns for content & config entities.

daffie’s picture

Issue summary: View changes
daffie’s picture

Removed #2030599: Expand Display with methods from the list, because it has been removed from core to its own module.

daffie’s picture

Issue summary: View changes
daffie’s picture

benjy’s picture

This makes perfect sense to me, it's basic encapsulation which, is good here because it hides the detail from the user that you actually have to access the "value" property to get the "value".

I was trying to think about it from a new comers point of view and how I would go about it presuming i'd come straight from D7. I think some code might illustrate it better, (Note, I used node because it was simple even though it has getters now).

<?php
$node = node_load(1);
dpm($node); // Drupal\node\Entity\Node

echo $node->title; // empty, no longer works but doesn't error either.

dpm(get_class_methods($node)); // Did they add a getter?

// Nope, let's look at that property again
dpm($node->title); // Drupal\node\NodeTitleItemList

// Ok let's see what methods its got.
dpm(get_class_methods($node->title));

// The only method that looks like what we wanted is getValue().
dpm( $node->title->getValue()); // This gives us an array... hmm

// Maybe it's properties will help.
dpm(get_object_vars($node->title)); // Nope, that's empty.
?>

I'm not entirely sure how you'd figure out that you had to do $node->title->value.

EDIT: I can't seem to get any white space into my code sample...

sun’s picture

Just to re-complete the previously raised considerations:

#26 still applies today and presents a major inconsistency both in terms of API and DX:

  1. $node->title->value == $node->getTitle() != $entity->label()
  2. $node->setTitle() == ?

(1) is not even fully true anymore today, in case you consider the use-case of rendering a node's title (label) for theming purposes, because title is a field now.

Next to completing the big picture of entity type specific interface methods (good idea), we should also ensure consistency between content and config entities.

Ideally, getLabel() and setLabel(). Let's make at least the shared base entity properties consistent for all entities?

Speaking of getLabel(), let's bear in mind that our current id(), uuid(), label(), etc methods are lacking a "get" prefix, which brutally stems from D7/PHP4-era thinking. In OO, all methods without a "get", "set", "has", or "is" prefix are supposed to do something beyond a trivial operation.

Despite following common OO practices, D8 requires you to learn that a seemingly arbitrary method foo() actually just returns something crucial.

In terms of consistency, industry standards, and learnability, I could not agree more; all of these (API) changes should be performed prior to releasing Drupal 8.0.

Wim Leers’s picture

Thanks so much for the clarifications. I'll ensure #2030605: Expand Editor with methods happens.

daffie’s picture

In the issue summery is a difference between NG and non-NG entities.
- Can somebody explain what NG stands for?
- Is the difference between NG and non-NG still relevant?
- If it is not relevant any more can I remove it from the issue summery?

This issue has been given a priority for major and tagged with "beta target" and "rc deadline".
- Does that mean that related sub-issues are also priority major and tagged with "beta target" and "rc deadline"?

Xano’s picture

NG stood for Next Generation which (mostly) was about typed data for entities. The backwards compatibility layer was removed a couple of months ago and as far as I know the concept of NG no longer exists in core.

Berdir’s picture

NG is no longe relevant, but what this actually is and always was is the separation between content (NG) and config entities.

daffie’s picture

So the NG and the non-NG stuff can be removed from the issue summery?

Berdir’s picture

No, but replaced with Content/Config.

daffie’s picture

Issue summary: View changes
daffie’s picture

@Berdir: Thanks for clearing that up.

I have updated the issue summery with the content/config part.

This issue has been given a priority for major and tagged with "beta target" and "rc deadline".
- Does that mean that related sub-issues are also priority major and tagged with "beta target" and "rc deadline"?

tim.plunkett’s picture

Once #2224833: Remove redundant ID manipulation in ConfigEntityStorage::save() goes in, then all of the public $id (or whatever key it is) can be made protected. We can revisit the entity types that were already converted, but the new conversions can make this change in their dedicated issue.

Wim Leers’s picture

It would be nice if this issue explained that your entity type has to implement toArray() once you switch the properties to protected. Just wasted quite a bit of time on debugging while working on #2030605: Expand Editor with methods.

xjm’s picture

Per discussion with @Berdir, the most important task to move these issues forward is architectural review of the child issues.

Edit: Also, it'd be awesome if someone could incorporate the explanations on-issue of what the purpose of all this is, that'd be valuable. Suggestions on what to look for in a code review would also be valuable.

xjm’s picture

Issue summary: View changes
YesCT’s picture

I opened #2246695: replace all core usages of id() with getid() just to clarify the discussion about using id() instead of getId().

justafish’s picture

Issue summary: View changes
daffie’s picture

Issue summary: View changes
Sharique’s picture

There is no separate issue for terms, so should it be as part of #2030669 - Expand Vocabulary with methods, or create a separate issue? I prefer to do on same issue, what other's have to say?

Berdir’s picture

Terms were done in #2016701: Expand TermInterface to provide methods, what else would you want to do there?

Sharique’s picture

Oops, I miss that.
Fields are missing in Drupal\taxonomy\Entity\Term class.

mgifford’s picture

kristiaanvandeneynde’s picture

Issue summary: View changes
Mile23’s picture

Just want to point out that most of the config entity issues linked from the original post have some work on them, and are awaiting review and maybe even RTBC. :-)

#2030595: Expand ConfigTest with methods and #2030637: Expand FieldConfig/BaseFieldOverride/FieldConfigBase with methods might be 'won't fix' at this point.

YesCT’s picture

Title: [Meta] Expand Entity Type interfaces to provide methods » [Meta] Expand Entity Type interfaces to provide methods, protect the properties
Category: Task » Bug report
Issue summary: View changes

when we first opened this meta, we planned to keep the properties public, .. since then we realized how important it is to have the properties protected and use methods instead. I think we realize this even more now. in #2030645-31: Expand Menu with methods @alexpott reclassified it as a bug, and explained why these changes are allowed in the beta.

updating the issue summary with that information.

xjm’s picture

Issue summary: View changes

Updated the "disruption" section with specifics (please double-check them).

xjm’s picture

Issue summary: View changes
xjm’s picture

Issue summary: View changes
daffie’s picture

Issue summary: View changes

Moved #2030645: Expand Menu with methods to the completed tasks list

yched’s picture

Issue summary: View changes

Updated the IS for the new names of Field config entities (FieldStorageConfig, FieldConfig, BaseFieldOverride)

daffie’s picture

Issue summary: View changes

The module custom_block has been changed to block_content.

daffie’s picture

This is what alexpott said in #2030645: Expand Menu with methods comment #31:

Reclassifying as a bug since exposure of properties as public allows code to not use the API eg ->id vs ->id(). This makes Drupal more stable and prevents bugs. Nice work.

The problem is that the following Config Entities have variables that are public and they are on the are on the completed tasks list:
- NodeType
- FilterFormat
- ShortcutSet
- Migration
- RDFMapping
- ImageStyle
- Searchpage
- Action
- ConfigurableLanguage

If we want to do what alexpott is saying we need to update them. Do we open new issues and attach them to this meta issue or do we need to solve this some other way?

daffie’s picture

daffie’s picture

Issue summary: View changes

The issue is all about encapsulation. One of the pillars of object-oriented programming. As a community we must get this fixed for drupal core. The problem is that patches made for the sub-issues are open for a long time. So I would like to make a proposition. If you write a patch for a sub-issue, then I will do a good review. Hopefully gets this issue solved before the first release candidate. At the moment there are 9 sub-issues left and probable 9 more to follow. So who will write a patch.

YesCT’s picture

@daffie in #73

If we want to do what alexpott is saying we need to update them. Do we open new issues and attach them to this meta issue or do we need to solve this some other way?

There was a time we would add on little follow-ups to existing issues, but we dont anymore.

Make new issues. (note dreditor has a clone issue button you might find helpful)
Make the parent of them this issue. Make them "related" to the issue that added the methods but left the properties protected.

daffie’s picture

@YesCT: I will make new issues for them tomorrow. Thank you for the help. If you can help with some "novice" patch makers, I shall do the reviews. I would be really nice if we would finish this issue before the first release candidate.

daffie’s picture

Issue summary: View changes
daffie’s picture

Issue summary: View changes
Mile23’s picture

bojanz’s picture

Opened #2399965: Config entity get() and set() should invoke getters/setters, which I feel addresses a major problem with how this was implemented for config entities.

Also, __construct() modifies the properties on its own, without even calling ->set(), so that's a third code path for setting properties, but also the one that's easiest to fix (by making it call ->set()).

filijonka’s picture

Issue summary: View changes
Mile23’s picture

daffie’s picture

daffie’s picture

Issue tags: +Needs tests

I would be nice if we could add a test that would test if there are public class variables in subclasses of ContentEntityBase and ConfigEntityBase.

daffie’s picture

daffie’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update, -Needs tests

Added #2527114: Create PHPUnit test that Entity class variables are protected or are allowed public to make sure that there will be no new public class variables added as a accident.

daffie’s picture

Issue summary: View changes
daffie’s picture

I do not know if we can mark this meta issue as fixed.
All class variables are now protected, but there are some issues open:

  1. In #2527114: Create PHPUnit test that Entity class variables are protected or are allowed public there is a discussion if we should allow contrib module to have public class variables.
  2. In #2030637: Expand FieldConfig/BaseFieldOverride/FieldConfigBase with methods user mpdonadio wants a change record for the issue.
  3. In #2532776: Add the undeclared variable $in_preview to the class Comment is related to this meta issue.
andypost’s picture

Related also needs to be fixed

catch’s picture

Title: [Meta] Expand Entity Type interfaces to provide methods, protect the properties » Expand Entity Type interfaces to provide methods, protect the properties
Category: Bug report » Plan
Priority: Major » Normal

Downgrading to normal and moving to a plan. I think everything important is tracked in its own issue now or already fixed.

xjm’s picture

Issue tags: -beta target, -rc deadline

Also, AFAIK, there aren't any remaining children that are actually RC deadline -- if there are though, we'd put that on the child issue.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

andypost’s picture

Version: 8.9.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.