In Drupal 7 EntityFieldQuery had three kinds of conditions / sorts: Entity (entity id, revision id, bundle and entity type), Property (properties on the entity table) and Field (columns of fields). The proposal is that if the entity type is a given then the Entity conditions can be merged into Property: for example if the entity type is known to be node then instead of 'entity id' you can query for 'nid', 'bundle' becomes 'type', 'revision id' becomes 'vid'. For further simplifying this API, we can merge Property and Field into one condition (or sort) method with a simple syntax: ->condition('body.format', 2) ie. field name, dot and column name. Also, just field name works and presumes the field column is "value". This entity / field specification also extends to every relevant method (exists, notExists, sort) making the API significantly simpler. A common interface for DBTNG, Views and EFQ conditions are in the plans.
It was often requested to add NULL support so exists() and notExists() methods have been added.
The conditions are handled by a proper condition interface, wrapped in the query much like DBTNG does. This allows for a DBTNG-like condition groupping as well. Instead of the truly whack and ugly delta and language grouping, there is clean AND/OR group support. Altogether, here is an example from the entity translation test:
$query = entity_query('entity_test');
$group = $query->andConditionGroup()
->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode)
->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode);
$result = $query
->condition($group)
->condition('name', $properties[$langcode]['name'], '=', $langcode)
->execute();
There is a drawback here: it is no longer possible to have a field column (like value or tid) called deleted. Every other field column is still valid. It's extremely unlikely this will be a problem.
The query result is very useful: it's a simple array where the values are entity IDs so it can always directly be fed into entity_load_multiple. If the entity supports revision IDs then the array keys will be revision IDs, otherwise entity IDs -- as this does not affect the operation of entity_load_multiple it allowed for a simple way to get revision IDs whenever possible.
| Comment | File | Size | Author |
|---|---|---|---|
| #60 | 1801726_60.patch | 223.18 KB | chx |
| #59 | 1801726_59.patch | 223.73 KB | chx |
| #53 | 1801726_53.patch | 223.79 KB | chx |
| #50 | 1801726_50.patch | 119.29 KB | chx |
| #48 | 1801726_48.patch | 119.28 KB | chx |
Comments
Comment #2
chx commentedTotally new tests need to be written, the other 14 EntityFieldQuery needs to be converted, the field_has_data needs to be pushed into field_sql_storage. But, this is the new system and I have seen it working by logging in or running the Entity UUID test (both of which loads by properties which has been converted).
Comment #2.0
chx commentedtrying to edit
Comment #3
bojanz commentedHere's the latest patch provided by chx (uploading it myself because drupal.org seems to hate him today).
Planning to review and write tests.
Edit from chx: I know this does not pass all tests but I think it passes most. Field info tests are failing for no apparent reason. This needs lots of doxygen and through testing the new classes and interfaces but the existing tests do a lot of that of verification already.
Comment #5
chx commentedAnother revision. Mostly simplification / code reorder but also age, isNull and isNotNull support.
Comment #6
chx commentedWrong _5 patch, doh!
Edit: there are remnants of superseded code in this patch: the classes FieldCountQuery, FieldCountQueryFactory, EntityQueryFactory.
Comment #8
chx commentedFixed the field SQL storage tests. Removed a bunch of files that were not in use anyways.
Comment #10
chx commentedSurely this won't pass but the API is coming along superb nicely. We have doxygen for the grouping -- thanks to jthorson and xjm for helping with those. I wrote doxygen for condition mostly by copying it over from the old one. The return value got meaningful keys: revision id if that exists, entity id if it doesn't. The values are still entity ids. A lot of thought went into making age work properly. The factory has been brutally simplified by getting the storage controller return the service name for the entity. Some method names have been renamed to be more generic / meaningful.
Comment #12
chx commentedInstead of deleting the old EFQ files, I am just neutering them to make this slightly easier to review. When this is commit ready, I will roll one with git rm. I hope this one actually passes. #1812056: field sql storage test failing on various MySQL engines due to indexing unbound text fields. has been filed.
Comment #13
chx commentedI added tests, more doxygen. The tests found two serious bugs in OR handling and other small tidbits.
Comment #14
plachHope to dive into this soon :)
Comment #15
chx commentedNew tests which brought in new bugfixes: sorts are now LEFT JOIN, the query is now distinct and addField indeed adds fields which is necessary for the distinct to work. sort and age and string operations are now tested.
Comment #17
chx commentedSorting of 1-N tables is VERY complicated to do right. I talked to das-peter, consulted stackoverflow and various SQL manuals and I believe this is correct. A new test has been added for counting the result set -- previously the test only passed because fetchAllKeyed collapsed multiple results into one row but pagination would've been broken as the count was incorrect. To offset the new complexity, an optimalization has been added which avoids the complex query if it is not necessary. It does not take a lot to have this optimization and it's worth it.
Comment #18
chx commentedSo, here's why do we need such ugly sort code. So if you do not want to make sorts to be also exists() calls you need to LEFT JOIN your field tables (edit: people will be dumbstruck if you order on a field and an entity is omitted from the results just because that field wasnt filled in). At this point, the result of pseudo-query SELECT ftid,figures.color,greetings.langcode FROM base LEFT JOIN figures LEFT JOIN greetings ORDER BY figures.color,greetings.langcode,ftid looks like this (I marked the first occurence of each entity with an *):
Now consider that for pagination reasons the result set must be made into 15 rows long, no matter what. How can you achieve that? You can GROUP BY ftid and then need to keep the order which can be done if you ORDER BY the lowest color value in the group first then the lowest langcode. This way the group containing (12, NULL, pl) and (12, NULL, tr) will be represented by (12, NULL, pl) which is exactly what we want. So the query will end up with GROUP BY ftid ORDER BY MIN(color), MIN(langcode). Very ugly but what can one do? As said, the system optimizes this away if the involved fields are single value.
Comment #19
chx commentedI talked to David Strauss at length and he considers this very ugly but correct but noted that MAX needs a DESC. He is right! New test for DESC for multivalue fields.
Comment #20
david strausschx asked me to review the sorting implementation explained in #18 for multi-value fields. Once the reverse sort order change I requested (that it use MAX versus MIN) is in place, I think this closely approximates user expectations. It's ugly but correct.
Comment #21
andypostThis implementation needs a follow-up and should be more lightweight. could be done after Dec1
From IRC
Comment #21.0
andypostfixed a little
Comment #21.1
chx commentedmore issue summary
Comment #21.2
chx commentedfixed
Comment #22
andypostneeds @todo code example
Core bundle? What for? Is database initialized?
please revert
Forward slash
Filename is different from class inside? Maybe better delete this?
is this constant accessible here?
only 3?
how it works before?
trailing whitespace
commented test?
Please mention about why this not needed any more
typo
Comment #23
chx commentedThanks for the review.
> needs @todo code example
Added.
>Core bundle? What for? Is database initialized?
Well, this needs to be somewhere where data is always accessible regardless which storages you use There's not a better place imo.
No, namespace separator is backslash not forward slash, sorry you are wrong in this.
> is this constant accessible here?
It is in field.module, so yes.
> only 3?
Actuallly might be just langcode and deleted. This reroll only contains those two.
> how it works before?
Before it was doing this crazy insane thing of saving fields without entities. Now it just saves 'em entities.
> Filename is different from class inside? Maybe better delete this?
> commented test?
As said in #12 , we can wait with deleting up to commit time until then they are just killed. It'd add 100kb needlessly to the patch.
> Please mention about why this not needed any more
Because it only fired from efq test which is not running any more.
Edit: I also added a lot of inline comments into Query about this sorting business.
Comment #25
chx commentedI could argue with #21 for a long time, but I won't, it's a minute detail which indeed can be debated later. I added tablesort, pager and lots of new comments. This patch should be close to ready (except that the old query class + test still needs a deletion which I still skip for the sake of easier review).
Comment #27
chx commentedbojanz gave it a look over and so there is even more comments and I added tests for pager and tablesort. The tests are based on unit tests to make sure they as speedy as they can be.
Comment #28
chx commentedComment #28.0
chx commentedadded return
Comment #28.1
chx commentedadded a drawback
Comment #29
sylvain lecoy commentedMarked #1179180: Custom pager for an EntityFieldQuery ? as closed duplicate.
Comment #30
sylvain lecoy commentedFrom a quick overview of the patch:
On Best practices for exception handling it is not recommended to create new custom exceptions if they do not have useful information for client code.
It is not giving any useful information to the client code, other than an indicative exception name. Do not forget that PHP Exception classes are like other classes, wherein you can add methods that you think the client code will invoke to get more information.
It is worth repeating that checked exceptions are to be used in situations where the client API can take some productive action based on the information in the exception. Prefer unchecked exceptions for all programmatic errors. They make your code more readable.
On your tests methods you are converting testOr, and testAndWhere to testor and testAndwhere. Why removing the camel case ?
Comment #31
chx commented> it is not recommended to create new custom exceptions if they do not have useful information for client code.
Get Crell to agree with this and I will remove them. Until then, this is what core does all over the place. Do not try to convince me, I am not the one to convince nor is this issue the place for that. Please file a separate issue. Thanks!
> On your tests methods you are converting testOr, and testAndWhere to testor and testAndwhere. Why removing the camel case ?
That's just an overblown search-and-replace, will restore.
Comment #32
das-peter commentedHere's my rough visual review. Just found some nit-picky stuff, I hope I'll find the time for a functional review over the weekend.
Shouln't there be something after
::?Param type don't seem to match, is this intended?
I think these classes would profit from a small docblock which explains what they are for.
Missing space in
.'Superfluous ;
Looks like the comments are a bit long and the last two lines seem to have a wrong indent.
I think according to the current coding standards a
break;</coed> in a <code>switchshould be followed by a blank line.I think this should be
Definition of Drupal\field_sql_storage\Entity\QueryFactory.How about
How about
Missing space in
.'Superfluous line break?
Looks like an unfinished sentence.
Comment #33
fagoSo, finally had a first look at this one. Dropping my thoughts:
+1000.
With the new Entity Field API, we also have knowledge about the data we query. For example, we could use that to automatically query for the 'text.value' if 'text' is given, or support passing in an entity when querying for entity references. That kind of stuff probably deserves its own issue though.
Reading the example query, I must say I have a hard time understanding it. I think it queries for an entity while looking for an entity in a special language and having a certain field translation in another language. Still, I'm confused of having
->condition('langcode', $langcode)as well as->condition("$this->field_name.langcode", $langcode);in the translation part. Why do we need both??I'd have seen "language" as a special, optional parameter when querying for any value, while the property/field 'langcode' is a regular property/field we use always when querying for the entity's (default/source) language. Such that you could simply do
?
Could we get a small
entity_query($entity_type)helper function here? That would be useful imo.We should move to an opt-in approach for access checking IMO. Having queries doing access checks by default is major DX WTF to me. I guess this deserves its own issue though?
Maybe this could even directly live in the DIC. Afaik it is able to spawn a new instance of a service each time it's used, so it could already serve as factory and use whatever has been registed there, e.g. at entity.query.ENTITY_TYPE ? Not sure about that though.
Comment #34
chx commented> 'text.value' if 'text' is given,
And how will you query for text.summary and text.format? Talked to fago on IRC and we agreed it's not really useful.
> Why do we need both?? (langcode and fieldname.langcode)
Because both the entity and fields are translatable and noone said the entity and the field will have the same langcode. This test gives an example (the only example in core in fact) where an entity has a base table and a data table which contains multiple translations of the same entity. We need the entity langcode. Similarly, a field can have multiple languages on the same entity. I didn't write this insanely complex system, I am merely querying it.
> as a special, optional parameter
Absolutely not. I refuse to make anything a special parameter again, we saw where that lead.
That's not from this patch, no idea where you found it.
> Could we get a small entity_query($entity_type) helper function here?
Talk to Crell, it's not me whom you need to convince. In general wrapping the DIC in functions is perhaps not desired.
> We should move to an opt-in approach for access checking IMO.
Why should we? Opt out is always better for security. Harder to forget. We grab the opportunity that we have semantic knowledge when the access check is (entity type node) and make the system more secure.
> entity.query.ENTITY_TYPE
would require a service per entity type. This sidesteps that need for very cheap.
Comment #35
fagoI think that's already common, see state() or typed_data().
Comment #36
chx commentedI have addressed all the minor concerns and have changed the code to use langcode as the last optional for condition/exists/notExists as fago asked and fago/bojanz/me discussed on IRC. I didn't change deleted, it's a mess. I have added better detection for configurable fields based on field_info_instances -- the new entity API is also based on that but it's not always working (perhaps because my entities are NG yet?) and so I thought this simple enough. It now defaults neatly to .value because it no longer needs to know about dots for recognizing a field. It just works. Do we want to add more magick to default to the single column of such fields? Still not removed the old code, the interdiff is 36kb already :)
Comment #36.0
chx commentedadded a few more words
Comment #37
fagoOverally, I like what I see :-) Here a review:
Unrelated, but this default value does not make much sense. Imho it's the implementations that does it wrong.
Misses docs. And is Condition the right term for it? It seems to contain multiple conditions.
Quite some methods misses docs there.
Again, is it a condition? From the itnerface, I see it allows me to add multiple conditions and has a conjunction. So it's a condition group?
As this is a group, the variable should be called conditionGroup.
I should be able to renable it, e.g. have a boolean parameter.
Let's use LANGUAGE_DEFAULT as default here? Also, docs should use the regular (optional) notation.
This can be simplified with entity_query(). :-)
Looks like the patch does a lot related to file references. Why that?
Comment #38
chx commented> And is Condition the right term for it? It seems to contain multiple conditions.
> Again, is it a condition? From the itnerface, I see it allows me to add multiple conditions and has a conjunction. So it's a condition group?
> As this is a group, the variable should be called conditionGroup.
DBTNG uses the class name Condition for it and the property is called conditions and I follow DBTNG. As I mentioned here and there, a unified condition system is planned as a followup and a rename can be done but only together with DBTNG. Having two extremely closely related things named differently is not to our advantage.
> Quite some methods misses docs there.
Fixed.
> I should be able to renable it, e.g. have a boolean parameter.
Changed. This is the only code change in this revision.
> Let's use LANGUAGE_DEFAULT as default here? Also, docs should use the regular (optional) notation.
I do not think so, if you want that, pass that in. Every optional $langcode uses NULL in core. I am just following patterns. Optional docs fixed.
> This can be simplified with entity_query(). :-)
I deliberately left repeating queries use the factory pattern as it is faster.
> Looks like the patch does a lot related to file references. Why that?
Because good ole' file_get_file_references ran a bunch of cross entity type queries and was quite broken in the process (I filed a separate issue which noone reviews, I think I found 5 or 6 bugs) and so I would need to run an even larger amount of queries and instead I rewrote it.
Comment #40
chx commentedKeep up with HEAD.
Comment #41
yched commentedFor this kind of stuff, please use the new field_info_field_map() instead. #1040790: _field_info_collate_fields() memory usage optimized field_info_instances($entity_type, $bundle) (with both params), but the other forms (no params or only $entity_type) are still extra costly and should be avoided. I'll probably open an issue to remove them altogether when I get back to my coding env in november.
Comment #42
plachThis patch is great! It looks damn close to what we need and what we want. Attached you can find an interdiff with some minor stuff you may wish to merge into the sandbox (I couldn't find it).
No setter is using the set prefix here, except this one. For consistency with rest this should be named
accessCheck().Sooner or later it would be nice to able to avoid accessing global functions here. Ideally we should exploit an injected OO pager implementation.
Same as a pager. I'm not even sure table sort should be part of the base class and not being a decorator or stuff like that instead.
Sorry, I missed the iteration where langcode stopped to be a reserved column: it's part of the PK of the default field SQL storage schema, how can it be non-reserved?
Lovely
Even more lovely :)
The sort clause was important in the old code: it allowed to test proper language grouping when sorting on multilingual properties. Isn't something similar needed here?
Comment #43
plachRelated: #1798140: Agree upon terminology for configurable fields.
Comment #44
bojanz commentedA review from my side is long overdue. I've been discussing this patch with chx since before a single line was written, and it has morphed into something amazing.
I've already reviewed the code documentation, and helped improve it on IRC, so I won't nitpick it (and I don't consider it critical on work of this size and importance).
In general, I believe it is a huge step forward and offer a +1 an RTBC any time of day.
It can be improved and build upon, but it already offers big benefits, the API is just miles ahead and syncs EFQ with the recent core advances (Property API, translatable properties, etc)
Quick recap:
1) Each query is now per-entity-type, which is a major part of the work needed to shift from Field Storage to Entity Storage (#1497374: Switch from Field-based storage to Entity-based storage), which is a desired cleanup with broad support. This allows for a much more sensible API, and allows us to treat properties and fields the same way.
2) Cleaner code, since the query is now built only in one place. Old EFQ had one query builder for "property queries" and another for "field queries" (queries that contain at least one field). Duplicate code paths--.
3) Unified condition API (->condition() instead of ->entityCondition(), ->fieldCondition(), propertyCondition()).
Condition groups, OR support. One of the biggest EFQ feature requests I've seen.
The new API is also very DBTNG like, which gives a better DX, and allows further unification of condition interfaces & classes across the board.
It also removes the delta and langcode group numbers and other related hacks which were becoming a huge DX WTF.
Plus, I'll never again have to see people on StackExchange/forums/IRC wondering why ->fieldCondition('nid', 20) doesn't work (this was really common)
Thoughts:
- It's great that ->condition($field_name) assumes the "value" column. We might want to extend this to all single column fields, so when
entityreference lands and gives us "target_id" columns, I can still just do ->condition('related_node', 10);
(EDIT: Or maybe this is too much magic? DamZ says "eeewww". I'm not married to the idea.). Also ER might not stay a single column field for too long (we need to store the revision id / uuid as well) so it might not be the best example
- I too dislike the pager and tablesort code in the base class. However, the rewrite was not supposed to remove any features, so we should attack that
in a followup. I would personally remove the tablesort completely, and rewrite the pager code so that it's pluggable & injectable.
Comment #45
chx commented> field_info_field_map()
used.
> this should be named accessCheck().
done.
> Sorry, I missed the iteration where langcode stopped to be a reserved column: it's part of the PK of the default field SQL storage schema, how can it be non-reserved?
So reserved is only necessary when you write something like fieldname.deleted -- if were to allow a field column called deleted, how would we know whether you query the 'deleted' meta data or the field column deleted? (which is stored as fieldname_deleted in the SQL table but is exposed as ->delete[LANGUAGE_NONE][0]['value']). There was a point where langcode was like that too but now it's a separate value on condition and sort.
> The sort clause was important in the old code: it allowed to test proper language grouping when sorting on multilingual properties. Isn't something similar needed here?
Is it. I added langcode to sorts as well. This actually simplified the Condition code because it no longer needs to create andConditionGroups -- the langcode is added to the join condition, instead.
> [single column magic] DamZ says "eeewww". I'm not married to the idea.
I side with DamZ on this.
> [thoughts about injecting pager and tablesort]
Please look at the functions we use for pager and for tablesort. They are not injectable, they are not SQL bound. They are mere data-shuffling simple functions. It is not impossible to move those into classes, sure but that's far out of scope.
Comment #46
plachSure, I was noting that because it's the only part of the patch I don't really like, but this should totally be a separate issue. Sorry for not making it clear.
As @Bojanz said, I think this is RTBC or very close to it. I'll have another look to this tomorrow. But it won't probably be necessary :)
Comment #48
chx commentedNo change just made it compatible with PHP 5.3 :)
Comment #49
fubhy commentedCan we remove the constructor from the interface? Dries just recently committed a patch which did away with those in various places.
Comment #50
chx commentedI have not mentioned above but the GROUP BY now happens on every query where necessary not just the sorts. This now got a test. And I removed the constructor from the interface.
Comment #51
bojanz commentedThe feedback so far has been addressed, plach and fago seem satisfied. Let's move forward.
Comment #52
plachI guess @chx owe us ;) the complete patch nuking the old EFQ before actual RTBC.
Edit: As per #12.
Comment #53
chx commentedI take that as your approval of the RTBC -- if you have no other concerns than that, great! Reviewers: #50 is easier to do. This patch is the exact same just with two files deleted.
Comment #54
plachHopefully I'll be able to perform another review tonight but I don't want to unnecessarily block this one on my personal agenda. I fully trust @bojanz's feedback.
Comment #56
chx commented#53: 1801726_53.patch queued for re-testing.
Comment #57
chx commentedStatus reset after bot fluke.
Comment #58
catchI had a first proper look through this. Overall I can't find anything much to complain about, looks like a really, really great job. There's several nitpicks here, none of them really block a commit (well maybe the test hack does). I'm not awake enough to try to do a meaningful review of the field_sql_storage implementation of this, there's a lot of complexity in there but most of it looks (unfortunately) justified due to the complexity of our current entity storage.
Leaving RTBC but I don't plan to commit for another day or so to leave some time for additional reviews. If someone fancies tackling the nitpicks before then, great, but this is a major step towards entity-centric storage, as well as potentially efq_views in core and similar, so would like to see it go in sooner rather than later as well.
I still think we should separate ConfigEntity and ContentEntity more (separate info hooks, possibly separate interface) - this is a method that just shouldn't be on the ConfigEntity interface at all no? Not introduced by this patch at all regardless.
Why do we need to count these?
Not sure we should re-use these constants here. It breaks encapsulation of the class, we're querying rather than loading, and this eventually won't only apply to fields anyway.
I was a bit confused why $this->condition isn't documented as a property. Additionally why conjunction is passed into the constructor at all. But this looks like just convenience to avoid having to specify AND everywhere, and you can still add OR, could possibly use more docs though but not enough to hold the patch up.
I can see people getting caught out by accessCheck() defaulting to TRUE, since it doesn't for normal queries where you have to add a tag. Why reverse the assumption we have elsewhere? Running a n access checked query when you're expecting one that's not can result in data loss/inconsistency (i.e. if you only bulk update a fraction of the nodes you meant to), so it's a case of balancing the potential for that vs. the potential for access bypass.
Yep, too messy to do this reliably now: #1082292: Clean up/refactor revisions
Does the 'keys are revision IDs' hold even if you query for FIELD_LOAD_CURRENT? Seems a bit odd.
This comment wasn't carried over to the new code though.
This is lovely, so much nice r than the removed lines.
Why's this necessary?
We should sort out the entity info so it can be injected, but that's likely to be easier once entity types as plugins is in, so OK leaving it for now.
Apart from that, I'm not awake enough to meaningfully review this hunk. There's a lot of complexity there, but the SQL storage for entities is complex and inconsistent, so...
oooh fancy.
Much nicer.
This got a bit more complicated. Any particular reason?
This also got considerably more complex. Why can't it be a straight port of the query?
This looks like a good case for the new unit test base that sun's working on. For now WebTestCase would be better though than installing system module within the unit test.
;)
Yeah this should definitely just use WebTestCase.
hehe. Yes, yes it is.
Comment #59
chx commented> Why do we need to count these?
No bloody idea. DBTNG does, so why not?
> This got a bit more complicated. Any particular reason?
Yeah. It queries across entity types which is not support and also I dare you to give the old query some semantic meaning. It's exploiting the fact that the SQL implementation INNER JOINs the tables.
> This also got considerably more complex. Why can't it be a straight port of the query?
The old one didn't even work, there's a separate issue filed with five bugs listed but noone reviewed that. And, this query is much like the previous one, cross entity query.
> This looks like a good case for the new unit test base that sun's working on. For now WebTestCase would be better though than installing system module within the unit test.
> Yeah this should definitely just use WebTestCase.
Except this is faster and much more contained. I would rather keep it especially as you say sun's patch is coming.
Deleted the debug statements, opsie.
Comment #60
chx commentedcatch asks for webtests. Sure. Deleting code is easy.
Comment #61
webchickI really hate to do this, since we are way above thresholds atm, but I don't see how this can be classified as a task. :(
Comment #62
yched commentedA couple remarks - those are not criticals, and do not have to affect RTBC status.
You receive $field as a param, so field_info_field_by_id() should not be needed ?
Same applies to _options_values_in_use().
I'm not sure I get the logic for what is being done here. field_create_field() should raise an exception if a column name is forbidden anyway, right ?
That's a block of 100+ lines, could really use a couple empty line separators :-)
Since this seems to be the very heart of the whole thing, it would help to make it visually digestible.
To a lesser extent, also applies to the methods in Drupal\field_sql_storage\Entity\Tables.
Looks like this could also be simplified/optimized by using field_info_field_map(). As is, code does field_info_instances($entity_type, $bundle); on all entity types and bundles, and is thus a drag memory-wise, since we keep those lists in statics for the rest of the request .
Also, this code block could use some air too...
Comment #63
yched commentedNow the nitpicks :
I thought we didn't do that ?
(also applies to several other places, @see, @var or @return statements - a search for \Drupal should raise a couple)
[edit: scratch that, turns out code standards promote leading antislashes on namespaces in comments... http://drupal.org/coding-standards/docs#namespaces]
$field should be hinted as a string in the phpdoc, like for other methods in ConditionInterface ?
Also applies to the methods in QueryInterface.
Doesn't seem to be needed, we never refer to QueryFactory directly in this file, we call drupal_container()->get('entity.query');
Same applies to options.module and EfqTest.php
A couple methods have no phpdoc block at all.
Comment #64
damien tournoud commentedThis patch comes with precisely zero new features, so I cannot see how this can be classified as a feature request.
Comment #65
pounardI think webchick did this for triage purpose because it raises the number of tasks way above threshold. For that I'd leave her this choice to make.
Comment #66
damien tournoud commentedI will defer to webchick, but this is not a feature request in any way, shape or form.
Comment #67
pounardIf you defer to webchick, do not change again the status. And yes this can be treated as a feature request, since it adds features to the EFQ.
Comment #68
sinasalek commentedDoes this issue also address (cross-entity-join) http://drupal.org/node/1446600 ?
Because it's not mentioned in summary
Comment #69
bojanz commented@sinasalek
It doesn't.
Comment #70
catchI discussed the category with webchick. IMO this is straightforward refactoring, making it a task - it's exactly the sort of thing we should be doing after feature freeze - trying to bring subsystems up-to-date with each other. It does introduce some new features to EntityFieldQuery but that's mostly a byproduct of the refactoring.
However it's also a sufficiently large refactoring that it should probably be blocked on the critical bug threshold while it's so ridiculously over.
Comment #71
chx commentedCross entity joins are a followup and the syntax is scheduled for discussion with David Strauss (at least) next week and anyone else relevant I can hold of during BADcamp. I iwll try to get hold floretan cos of his remote entities article.
Comment #72
webchickI'm ambivalent to how it's classified, I just wanted to note that it's huge refactoring and I strongly believe we need to be under the criticals threshold to let it in. I believe catch and I are on the same page about that, so no need to dicker about with the category.
Comment #73
webchickGetting there on thresholds now! Some persnickety major bugs.
This is all catch, all the time, so assigning to him for review/commit.
Comment #74
catchThings are looking much better with thresholds, so I've gone ahead and committed this. Will need a change notice. Please also open a follow-up for yched's points before marking this one fixed.
Comment #75
yesct commentedThe change notice will help clarify what to do to reroll other patches on other issues (like #1188388-206: Entity translation UI in core, right? (Forgive the novice-ish Q; I'm still getting familiar with current core workflow stuff.)
Comment #76
tim.plunkett#63 needs a follow-up to be created before this is closed, but the change notice is good.
Comment #77
chx commented#1827476: Docs cleanup for EFQ v2 I copied #63 there.
Comment #78
berdirHm, would it make sense to maybe have a simple, typical 7.x EFQ query in the change notice with just 2-3 simple conditions and the result then passed to entity_load().
Because that example in the change notice is a) very complicated and b) not actually 7.x EFQ, there is no such thing as translatable properties in 7.x and therefore also no propertyLanguageCondition(), that was added in 8.x.
Comment #79
yched commentedThanks, but #63 was only minor doc stuff. #62 has the more important remarks.
Comment #80
yched commentedthus, reopening until #62 is addressed or a corresponding followup is created.
Comment #81
chx commented#1827588: Followup to EFQ v2 keeping open for the change notice fix.
Comment #82
plachRelated: #1828790: Entity count query not working with fields shared among different entity types.
Comment #83
pounardI was reading this patch yet again, and I saw this:
public function &conditions();Returning a direct reference to an object property wakes up buggy PHP behaviors, see #1671848: by reference getter on objects such as dbSelect may break the __clone behavior of such objects.
I think the right way to go is to have methods such as
addCondition()andremoveCondition(ConditionInterface $condition)altogether.Comment #84
sinasalek commentedWill it be possible to backport EntityFieldQuery v2 to Drupal 7 ? (in terms of dependencies)
Comment #85
bojanz commentedMaybe as a contrib module (but does it even have a point then?), to Drupal 7 core never (it's a complete API change).
Comment #86
catchComment #87
sylvain lecoy commentedRe #31, done: #1874254: Provide more context in typed exceptions :)
Comment #88
yched commented#1969136: Move field_reserved_columns() to a static method would welcome some feedback from the authors of the patch.
The code contains no explanation on the logic behind this.
@catch in #58 and myself in #62 asked for some, but this was left unanswered.
Comment #89
yched commentedFeedback also welcome in #1931900: EFQ calls field_info_field() too liberally (perf issue).
See #3 and following over there.
Comment #90
georgir commentedWhile you are changing EFQ anyway, how about allowing it to select fields instead of just filtering by them?
https://drupal.org/project/efq_extra_field in core! :)
Comment #91
cweagans@georgir, that's out of scope for this issue. Also, we've already passed API freeze, so please open a feature request against Drupal 9.
Comment #92
dawehner@georgir
This is probably the worst question you could have asked, sorry. That module is fundamental wrong in terms of API design of drupal.
All what drupal supports is entities, that's it.
If you are crazy you could get this information by using the aggregated query feature :)
Comment #92.0
dawehnerupdated
Comment #93
alan d. commentedThis feels like a regression to me as it implies (doesn't actually stop us, although we are departing from the interface) that you need to couple the query with a load_multiple to do anything useful
This idiom is now the norm in D7
While about 50% of the usages of this that I have seen were to simply get lists of node titles.
It was a trivial task to extend D7 EntityFieldQuery::finishQuery() to insert additional fields like node.title or whatever, drastically reducing server loads, but now if we do this in D8 we are breaking the expected returned output of REVISION_ID => ID as defined in QueryInterface.
For example in D7, an overridden finishQuery() to do this:
Note
- note no i18n considerations here, but it could easily be extended to include these as required
- assumes SQL storage, if it matters, I have never had to support anything else
I only found this after searching to see if multi-entity type queries were dead so that we never needed to do this every again:
Big plus to this and everything else though!
[edit]
It is trivial to define your own method ::getEntityStubs() or something, I guess that is just less obvious to developers that you don't actually need to couple execute() with a load() ;)
Comment #94
pounardI don't think this is a regression, on the contrary: returning only identifiers forces you to load entities, but thanks to entity caching in core, this won't hurt to much: 2 queries (including one on the cache backend in best case scenario) won't hurt you, and it ensures that all your entities have been fully loaded, hooks and events passed, and data is consistent. Using the partial entity from EFQ even in Drupal 7 is a real risk you are taking because some modules might change stuff on your entity titles or other fields and you skip that step, the whole stuff may be inconsistent. In Drupal 8 you are supposed to use the Entity accessors and not using direct database data manipulation. You are supposed to always access fields and not direct properties, if I understand the whole well.
Comment #95
chx commented#94 is right. The data you find in the database might be the same you find in an entity or it might not. Even if the data is the same, you might have access to it or you might not. Drupal has APIs. Use them and forget about talking to the database directly.
Comment #96
chx commentedAlso, #597236: Add entity caching to core should seriously decrease the cost of mass entity loading.
Comment #97
alan d. commentedYep, point taken. Thank goodness that Moore’s Law has broken yet. Really a non-issue. ;)
Comment #98
andypostis this fixed?
Comment #99
bojanz commented