Closed (duplicate)
Project:
D8 Field API
Component:
Code
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
3 Nov 2012 at 10:02 UTC
Updated:
30 Nov 2012 at 13:28 UTC
Jump to comment: Most recent file
The branch we work in is "field-api-displays-xxx"
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.
#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
| Comment | File | Size | Author |
|---|---|---|---|
| #36 | entityDisplay-1830868-36.patch | 135.39 KB | yched |
| #32 | 1830868-32-EntityDisplay.patch | 132.85 KB | nils.destoop |
| #21 | interdiff.txt | 14.46 KB | yched |
| #2 | IMG_20121102_202226.jpg | 344.4 KB | Stalski |
| #2 | IMG_20121103_144154.jpg | 308.28 KB | Stalski |
Comments
Comment #1
Stalski commentedBranch name: field-api-displays-1830868
Comment #2
Stalski commentedPeople interested in the *roadmap*, see images
Comment #3
andypostIt looks like EntityDisplay could be used for entityRenderController
Comment #4
Stalski commentedYes, that comes into play indeed
Comment #5
yched commentedI'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.
Comment #5.0
yched commentedUpdated issue summary.
Comment #5.1
Stalski commentedUpdated issue summary.
Comment #6
yched commentedAlso, 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
Comment #7
Stalski commentedWe'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?
Comment #8
Stalski commentedProblem
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
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
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.
Comment #9
yched commentedI do plan to have a close look at the code, notably at the render side. Will try to do so this weekend.
Comment #10
sunAhoy! 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.
Comment #11
swentel commentedYeah, a quick str_replace from <em> to <code> would make that comment more readable :)
Comment #12
Stalski commented@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!
Comment #13
sunOh. 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?
Comment #14
Stalski commentedI removed the em's.
@sun: I can see what you mean. Definitely worth considering.
Comment #15
yched commented@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.
Comment #16
nils.destoop commentedThat'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.
Comment #17
yched commentedTell me when I can review. I'd really want to validate the render approach before we go to far along.
Comment #18
Stalski commentedyched, 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 ;)
Comment #19
Stalski commentedI 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.
Comment #20
yched commentedMore concise formulation for the title.
Comment #21
yched commentedSo, 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.
Comment #22
yched commentedAlso, merged current 8.x into the branch
Comment #23
Stalski commentedthx for the review. Your fixes are already in. Will commit everything later today.
Comment #24
nils.destoop commentedI 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.
Comment #25
yched commented@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.
Comment #26
yched commentedMerged 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.
Comment #27
Stalski commentedFunny 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.
Comment #28
yched commentedYeah, $entity_type could definitely be dropped, but it needs to be done for all field_attach_*() functions, so not for that patch.
Comment #29
yched commentedPer 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())
Comment #29.0
yched commentedUpdated issue summary.
Comment #30
nils.destoop commented@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.
Comment #31
Stalski commentedA 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".
Comment #32
nils.destoop commentedQuick run through testbot so we know what tests are left for conversion. Moving it back to sandbox after the test.
Comment #34
yched commentedAw, 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 :
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.
Comment #35
yched commentedOh, 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)
Comment #35.0
yched commentedAdded subtasks
Comment #36
yched commentedI 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.
Comment #37
Stalski commentedGreat job!
Comment #38
yched commentedPushed a couple changes after doing benchmarks, and merged latest 8.x.
Preparing a post for the core queue :-)
Comment #39
yched commentedCore 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.
Comment #39.0
yched commentedadded subtask