The branch we work in is "field-api-displays-xxx"

  • Create EntityDisplay entity type so it's not yet aware of layouts/regions and not tied to field api
  • Make sure field UI "manage display" can write and read EntityDisplay's
  • Make sure field_attach_view (entity_view) uses the EntityDisplays + Remove $instance['display'] in favor of CMI files
    • Make sure the formatter target function is called with the EntityDisplay
    • Make sure we can still view a single field with custom settings
    • Make sure we have a method in EntityDisplay to set field settings
    • Make sure a default fields (Cfr drupal standard install profile) use the new api function to create a display object or at least put the created field in a display
    • Create the API methods to write settings for a field in a display. E.G. $entity->display->set($field_name, $settings)
    • Create tests to integrate the "Manifest" config file. See active store directory for 'manifest.{prefix}.yml'
    • Make sure field_bundle_settings() disappears. Might not be the function but at least the variable. We need to check if this api function is still desirable.
      We can only do this as the field api cmi patch is in. Also see http://drupal.org/node/1735118#comment-6690422. This includes the removal of extras field weight and status on display
    • Create display object for the form as well, removing extras field weight and status on form
    • Make sure the status of enabled and disabled view modes (and thus displays) is owned by the display object. This is related to #1826602: Allow all configuration entities to be enabled/disabled, Please revisit.
    • Create upgrade path for the fields. Important: don't use field_update_instance() but _update_7000_field_create_instance() instead, already included in field.install. We need to check with yched for the use of the batch api
  • Introduce the layout regions to extends Sam Boyer's display classes
  • Adapt field_ui for regions (see #1786198: Make consistent regions in code for fields UI overview screens
  • Put list of active view_modes in CMI instead of variables

Notes

The Display object only will be posted in the queue at #367498: Introduce 'display' as a way to group and reuse instance and formatter settings..
The branch name in this sandbox for this issue is called field-api-displays-1830868.

Subtasks

#1838034: [EntityDisplay] Get rid of field_set_display()
#1847130: [EntityDisplay] Write upgrade path
#1847132: [EntityDisplay] Convert view modes config to CMI
#1848858: [EntityDisplay] Add hidden extra fields to the display object so they are always stored

Comments

Stalski’s picture

Branch name: field-api-displays-1830868

Stalski’s picture

StatusFileSize
new308.28 KB
new344.4 KB

People interested in the *roadmap*, see images

IMG_20121102_202226.jpg IMG_20121103_144154.jpg
andypost’s picture

It looks like EntityDisplay could be used for entityRenderController

Stalski’s picture

Yes, that comes into play indeed

yched’s picture

I'll try to give this another round of review soon. Do you guys still have pending code changes ?

And yeah, how this might tie to the render controller is one thing I want to explore.

yched’s picture

Issue summary: View changes

Updated issue summary.

Stalski’s picture

Issue summary: View changes

Updated issue summary.

yched’s picture

Also, just occurred to me:
- The yml file should list elements in the correct order. The save() method needs to order elements by weight, and put the 'content' array in the correct order before handing to parent::save().
- Field UI submit handler should renumber weights starting from 0, and going by increments of 1 (tabledrag sometimes produces fairly large weight values.
Will make git diffs on the display.yml files more friendly

Stalski’s picture

We'll put that on the todo list in the summary as well, thx.
So I've updated the summary of this issue and plan to do so while refactoring so we know what has been done in the end.
@todo rename the field_create_display back to field_set_display for now

I'll also have some remarks.

We can actually save a field's settings with field_set_display. The naming of this function implies we are setting a display for a field. We know it's actually the other way around and you add a field with it's display settings to the display object. Also we needed to have the possibility to create displays for 1 or more view modes at once (see forum.install for instance). Sometimes defaults are enough, sometimes we want to explicitly say what the settings for the field for 'full' need to be.
We also consider the fact that a module can drop by delivering a new view mode. The module actually knows then that it wants a display with stuff in it, and actually this stuff are not necessarily fields, but they might be blocks or views or whatever.
Taking all this in consideration, and also what yched said in Ghent, we need the entity module (back). Currently we are putting some display (api) functions in field module but it might be better to have the display stuff moved to an entity module, which is also much more obvious to define the EntityDisplay in the first place.
Thoughts?

Stalski’s picture

Problem

EntityRenderController::buildContent has calls to field_attach_prepare_view and field_attach_view. For performance reasons the field_attach_view can be run per entity while the field_attach_prepare_view does its job on multiple entities. In the concept of a display per view mode on entity render, field_attach_view is never a problem.
However with field_attach_prepare_view there are problems. It invokes _field_invoke_multiple and field_invoke_method_multiple.
The target_function in "field_invoke_method_multiple('prepareView', _field_invoke_formatter_target($entity_display), $prepare, $view_mode, $null, $options);" does not make much sense anymore as the $prepare parameter contains all entities. This means display_settings are bound to 1 entity and not multiple entities.
This also implies that function field_invoke_method_multiple($method, ...) can not deal with several $method's in the same way anymore.

Proposed solution

  • Move things a level up to EntityRenderController::buildContent. There is a comment like: "Prepare and build field content, grouped by view mode." which now boils down to attaching displays to the entity.
  • Add a method "setDisplay" to ContentEntityInterface or through an extension. Call this function from EntityRenderController::buildContent while looping the entities.
  • Create a separate api function for the $method=='prepareView' based on field_invoke_method_multiple.
  • Make sure all calls to field_invoke_method_multiple function with 'prepareView' are refactored.
    Very important: This function currently only is invoked once in the complete drupal project, with $method == 'prepareView', which makes these decisions a ton easier.

Questions

  • Is the reason why field_attach_prepare_view exists only the fact that we can do things cheaper on multiple entities? The question does not necessarily imply that we want to drop field_attach_prepare_view or anything.
  • What are the reasons, pro and cons to have an entity module? Very likely this already has been discussed in issues I am not following (yet). What are the chances to get it back? (more related to previous post)

I am currently working on this and will post the link of the git difflog here so you can easily review this piece.

@yched, @swentel, @others: It would be nice to have some feedback on this reasoning.

yched’s picture

I do plan to have a close look at the code, notably at the render side. Will try to do so this weekend.

sun’s picture

Ahoy! EM stands for emphasis, not code. :P ;)

On the questions (both AFAIK):

1) We're preparing the view on multiple entities, for performance, and because of multidimensional extensions being involved; i.e., if you pass the full stack of entities being prepared for view, then an integrating module can go ahead and fetch all the data for all the entities/fields in one go, instead of issuing individual storage lookups for every single entity. The multiple processing is definitely preferred from a performance perspective.

2) entity.inc got moved into an entity.module in D8 before we had the PSR-0 and "frameworkification" master plan. Back then, the idea was: "It invokes hooks, so it should be a module." Later, we realized that entity.module is a pure, architectural service component and does not do anything on its own. Also, we had introduced entity classes and storage classes, which reduced its procedural aspect. Therefore, we moved it it "back", but not into includes/entity.inc, but Drupal\Core\Entity. :)

HTH.

swentel’s picture

Yeah, a quick str_replace from <em> to <code> would make that comment more readable :)

Stalski’s picture

@sun about the em's you are totally correct, I thought it was easier to for "quick reads" :P I won't do it again ;)

Also thank you very much for the argumentation and pointing out the history of the decisions!

sun’s picture

Oh. And yeah, that question on why Entity is no longer a module is great. I actually considered that we should do the same with Field API, once we're done with pluginification and configurationification, since, frankly, what's really left except of classes then?

Stalski’s picture

I removed the em's.

@sun: I can see what you mean. Definitely worth considering.

yched’s picture

@sun, re: field module -> component
Yeah, dunno, we still have a couple hooks in here. I guess we'll see when we get there.
Right now it's more the lack of an entity.module that's annoying :-) We're introducing config entities that really belong to the entity system here, not field module.

nils.destoop’s picture

That's also why we are moving the display object now to the entity. Stalski is going to commit an update soon. The render controller will load the display then, and place it on the entity.

yched’s picture

Tell me when I can review. I'd really want to validate the render approach before we go to far along.

Stalski’s picture

yched, you can review :) or maybe better : help thinking where the code changes are not optimal. Last commits and especially the big one: http://drupalcode.org/sandbox/yched/1736366.git/commitdiff/fc5d57fa28616... .

At this stage, we are fixing the failing tests, where the most difficult one is a name clash in the file field , being "display" which is already used to show the delta's.
The other fixes are practically exceptions in tests. E.g. where field_attach_prepare_view or field_attach_view are called manually, like the node_preview function. I was hoping every entity was rendered through the EntityRenderController but it seems that is not a consistency in current codebase.

So Yched, shoot, but not too hard ;)

Stalski’s picture

I also notices while refactoring that there is hook called "hook_field_extra_fields_display_alter" where displays can be changed. This hook will need be changed as well, maybe even remove it, depends a bit on how and where the entity displays will find their home.

yched’s picture

Title: Refactor new field api so it uses display objects to render fieldable entities » Store entity display settings in EntityDisplay config objects

More concise formulation for the title.

yched’s picture

StatusFileSize
new14.46 KB

So, I gave the code a first round of review, and pushed a couple changes, that is mostly 89d1179:
- Renames _field_entity_display_load() to entity_get_display(),
- moves it to entity.inc,
- removes the "switch to 'default' mode" logic (this only happens at render time, in EntityRenderController; other than that, we need to be able to do stuff with the diisplay object for a view mode that's not currently "enabled").

Attached is an interdiff with my whole set of changes.

Other than that, I'm doing some refactoring on the render callstack, but I'm not fully settled on on the best approach yet, will try to come back with some code soonish.
Meanwhile, I created #1838034: [EntityDisplay] Get rid of field_set_display(), would be cool if you guys could look into this.

yched’s picture

Also, merged current 8.x into the branch

Stalski’s picture

thx for the review. Your fixes are already in. Will commit everything later today.

nils.destoop’s picture

I see you renamed display_settings to display_properties. I saw it more as settings, because it are the display settings for that field.
Should we keep display_properties, and use it then everywhere? Because now it's mixed.

yched’s picture

@zuuperman #24:
I'm trying to settle on 'settings' being the settings for a specific formatter or widget (or more generally 'plugin').
So yeah, $display_properties for "the display parameters used by a given field". $display_options would work too, but the current code is semi-consistent on $display_properties / $widget_properties right now, so let's keep this.

yched’s picture

Merged latest 8.x and pushed some important changes, most notably :
- 228752c Inject display objects as params in field_attach_[prepare]_view().
This solves the "how do we pass display objects down to field_invoke_method()" question.
Previous code placed the $display in the $entity (DisplayEntityBase), which is a hack :-). The entity is the thing we're displaying, we shouldn't use it as a not be a dumping ground for "temporary" information about how we are rendering it. D6 had the awful $node->build_mode property, we removed that in D7, let's not reintroduce a similar pattern.
This change also restores field_invoke_method_multiple() as a generic method not tied to a specific method, we'll need it for other ops (load) when doing "field types as plugin".
- fccc601 Remove DisplayEntityBase class, not needed anymore.
- 7794307 Remove $view_mode param from f_a_*view(), inject it in the Display objects.
We still need to know down the stack what was the original view mode that was requested, even if we're backing up to 'default'. But this information is carried in the Display object (at run time, this doesn't get saved in the CMI file)

Thus, new signatures are :
field_attach_view($entity_type, Entity $entity, EntityDisplay $display) - "display the fields in this entity using these display properties"
field_attach_prepare_view($entity_type, Entity $entities, array $displays) - "prepare those entities using these display properties"
Which looks pretty reasonable IMO.

Next, I'm working on removing FieldInstance::getFormatter() and moving it somewhere else. Given that the $instance doesn't hold the display properties anymore, it has no reason to be the intermediary for instanciating a formatter.

Stalski’s picture

The entity is the thing we're displaying, it should not hold "state" information about how we are to rendering it.

Funny you say "state" since that is exactly what I had in mind. I can understand your reasoning though. And the approach is much better indeed.
I also do like the change in EntityRenderController removing the "call" variable et all.

I have a remark for later: field_attach_view($this->entityType, ...) could drop the $entityType as well, as it is always available in the $entity. Might be best in followup issues I guess.

yched’s picture

Yeah, $entity_type could definitely be dropped, but it needs to be done for all field_attach_*() functions, so not for that patch.

yched’s picture

Per Stalski's request, created new subtasks, that can be worked on independently of the work on the rendering pipeline :
#1847130: [EntityDisplay] Write upgrade path
#1847132: [EntityDisplay] Convert view modes config to CMI
(that's in addition to #1838034: [EntityDisplay] Get rid of field_set_display())

yched’s picture

Issue summary: View changes

Updated issue summary.

nils.destoop’s picture

@yched

We got some caching issues in tests. When formatter settings are changed on runtime, the formatter doesn't get rebuild.
Example: LinkFieldTests
in a foreach, all the different format settings are tested.

http://drupalcode.org/sandbox/yched/1736366.git/commitdiff/0ed44374c5551...

I think we got 4 options (for now, as i thought you were planning to move getFormatter away from fieldInstance):
1) leave it the way i committed. When users change a formatter on runtime, they have to clear the old formatter themselves.
2) The code that's now in LinkFieldTests moves to EntityDisplay->save(). For every field in the content array, the formatter gets resetted
3) In EntityDisplay->save(), field_info_cache_clear is called. Clearing all the field cache.
4) Remove resetFormatter again, and users should call field_info_cache_clear themselves.

Stalski’s picture

A question we had as well, is how likely will this happen in normal drupal behavior? Or is it just the reasoning like : "it was covered in D7 in the field_create/update_instance ... so we keep it, as it should be possible to use it".

nils.destoop’s picture

Project: D8 Field API » Drupal core
Version: » 8.x-dev
Component: Code » field system
Status: Active » Needs review
StatusFileSize
new132.85 KB

Quick run through testbot so we know what tests are left for conversion. Moving it back to sandbox after the test.

Status: Needs review » Needs work

The last submitted patch, 1830868-32-EntityDisplay.patch, failed testing.

yched’s picture

Project: Drupal core » D8 Field API
Version: 8.x-dev »
Component: field system » Code

Aw, so this finally hit us.
Yeah, that's why persisting formatters in the instance is problematic.
Everything works in "regular" situations where the $display isn't changed during the request, but we definitely want to allow code like this :

$display = something
field_attach_view($entity, $display);
$display->change_settings_for_field_foo;
field_attach_view($entity, $display);

without people going "wtf why doesn't it work".

Persisting in one place based on definitions stored in another place is a asking for trouble. That's why formatters were persisted in the $instance so far, and that's why they should be persisted in the EntityDisplay now.

I have been working on a branch that does that. I'll merge with latest and see how it goes with tests, and I'll report back.

yched’s picture

Oh, crap - I did not intend to set back to "D8 Field API", and it seems it wiped the test results :-/

I've been using #1848068: Helper issue for "EntityDisplay" to post patches for the bot today.
I reuploaded patch #32 over there : #1848068-4: Helper issue for "EntityDisplay" (comment #4)

yched’s picture

Issue summary: View changes

Added subtasks

yched’s picture

StatusFileSize
new135.39 KB

I pushed a couple important changes :

- 327da51 Persist formatters in the EntityDisplay, as per #30 / #34, so we can ditch them when the underlying definition changes.
The actual formatter creation still happens in $instance->getFormatter() (other code that needs to create formatters outside of the entity_view() callstack use that), but nothing is persisted there.
Thus, FieldInstance::resetFormatter() is removed, not needed anymore.

- 45ee059 Remove the $add_default parameter in EntityDisplay::getContent(). Providing defaults for 'hidden' fields was mainly done to ease the job of Field UI "display overview" code, but IMO that's Field UI's problem to decide how its form should behave for hidden fields.
If a field has no entry, getContent() returns NULL, and the calling code can act accordingly.

- e19207e Replace hook_field_display_alter() & hook_field_extra_fields_display_alter() by hook_entity_display_alter().
The new hook is called only once per entity_view_multiple(), while the others were called once per field & per entity. Thus, less hook invocations, and this simplifies the code flow quite a bit.

Tests are not too bad. Remaining failures are #1848858: [EntityDisplay] Add hidden extra fields to the display object so they are always stored, and a new fail introduced by #1292470: Convert user pictures to Image Field (probably only some test code that needs to be adapted, haven't looked into it so far).

I intend to run a couple perf tests tomorrow, and bring an initial patch to the issue queue. We need feedback from core committers see if they would take that as a post Dec 1st change, or if this needs to be done before feature freeze :-/.

Attached is the current patch against D8. No interdiff, the HEAD merges makes it difficult to generate.

Stalski’s picture

Great job!

yched’s picture

Pushed a couple changes after doing benchmarks, and merged latest 8.x.
Preparing a post for the core queue :-)

yched’s picture

Status: Needs work » Closed (duplicate)

Core issue was created at #1852966: Rework entity display settings around EntityDisplay config entity.
I think we can close this one now - the separate sub issues should still be useful though.

yched’s picture

Issue summary: View changes

added subtask