Support multiple finder arguments#12787
Conversation
|
With this change one won't be able to stack finder calls, that's sad. Let's say one make's a custom finder $table->find('all', ['conditions' => '..'])->find('custom', $someEntity); |
|
@ADmad why not? What makes it impossible with this implementation? |
|
NVM, for some reason I remembered that the options used for 1st find call are passed down to subsequent calls but that's not the case. We will have to add clarification to the docs that if 2nd argument for |
That's my main concern with this. I was wondering that maybe we should remove this part: https://github.com/cakephp/cakephp/pull/12787/files#diff-d36d5650ddbf69668bdd04f31f4a7a42R2217 And set options on query explicitly in build-in finders that support options array. I imagine that this change would stay BC but would require people to update those custom finders that for some reason expect that the options are set on query (even though those still should be accessible from the argument). |
I am not in favor of any change which requires updating custom finders. 4.0 is supposed to a be smooth upgrade from 3.x and finders are a very important and well used feature of the framework. |
| * @return \Cake\Datasource\QueryInterface | ||
| */ | ||
| public function find(string $type = 'all', $options = []); | ||
| public function find(string $type = 'all', ...$args); |
There was a problem hiding this comment.
Doc string needs to be updated too.
There was a problem hiding this comment.
@markstory from my initial comment:
I didin't want to update the docs and haven't added any new tests as I'm not sure if this is a good way forward.
| $options = $query->getOptions(); | ||
| if ($args) { | ||
| $options = $args[0]; | ||
| if (is_array($options)) { |
There was a problem hiding this comment.
What about ArrayAccess things? Those were in the old doc string type information.
There was a problem hiding this comment.
Query::applyOptions(array $options) accepts array only. Looks like doc type info is wrong?
There was a problem hiding this comment.
Possible. We may have not ever actually had checks that were array specific before either.
b700ac2 to
87c7ef6
Compare
|
Does it still make sense, can I continue with that? |
|
I dont like the change tbh. |
|
Why not? |
|
Let me ask this:
|
|
@dereuromark I'm not able to answer your questions but let it be clear: this is not a breaking change. You can still use options array as before. This change allows you to pass anything to the For me personally being able to leverage PHP 7 type checking instead doing it manually in every finder would be a great feature and I'd be willing to sacrifice a bit of code discoverability. But this change does not force you to write finders the new way, it just opens a path for being able to write less error-prone code. |
87c7ef6 to
000a41d
Compare
There was a problem hiding this comment.
The fact that when 2nd argument to Table::find() is an array it's treated as a special case to maintain BC is my only concern with this change. I hope that doesn't trip users.
Also shouldn't BehaviorRegistry::callFinder() also be updated similar to Table::classFinder()?
| public function find(string $finder, array $options = []); | ||
|
|
||
| public function find(string $finder, ...$args); | ||
There was a problem hiding this comment.
Looks like whitespace at end of line.
| { | ||
| /** @var \Cake\ORM\Table $table */ | ||
| $table = $this->getRepository(); | ||
| if (!$args) { |
There was a problem hiding this comment.
This is sad. Those who have overridden find() in their models won't realize they will have to add similar if block to their method.
There was a problem hiding this comment.
What is a chance that someone overridden ORM Query::find() and used it instead? Cake\ORM\Query is more like internal class, isn't it?
There was a problem hiding this comment.
Not much chance of overridden Query::find(). But I see similar if block in Table::find() as well a table class of test app which has overridden Table::find().
| { | ||
| $query->applyOptions($options); | ||
| $options = $query->getOptions(); | ||
| if ($args) { |
There was a problem hiding this comment.
Perhaps use if (isset($args[0]) && is_array($args[0])) { and avoid the nested if below?
|
ping @robertpustulka |
|
Yes. Does it look OK as it is or do we need another approach? I'd like to know before I fix conflicts and add tests. |
|
I like the idea of this, but the interface is awkward now. I would prefer to see query options pulled out as a separate parameter. Treating the first argument in a variable list as the query options parameter causes a lot of one-off and note style documentation that is hard to read. The fact that they were merged with other general table-specific finder options is more or less a miracle that just happens to work and feels nicely hidden because everyone can just read examples or docs of a single array argument ... there's never a special case where someone reads an example without an options array as the first argument. |
I'm not sure I understand you, but you can pass anything to the query with the proposed interface. The first argument is treated as query options by default only for the BC. Eg: $this->find('foo', ['foo' => 'bar']); //the BC way
$this->find('bar', $foo, $bar); // $foo and $bar ca be anything and get passed to the finder as below:
public function findBar($query, $foo, $bar) {}The arrayish options can still be pulled from the query object with I agree that the interface in the 3.x was a bit hacky with mixed finder and general options but this have been done to keep the BC with 2.x, where you called finders like: $this->Articles->find('all', [
'conditons' => [...],
]);Maybe it's too late now to do this for 4.x, but maybe with 5.0 we should remove the "special" options that are proxied to the query methods (like |
I'm saying the backwards compatible part is what makes this extremely awkward. |
|
@othercorey OK. Do you have an idea how to handle this more conveniently? |
I would require calling a reserved
This will enforce splitting the query options from find parameters while letting the user know they need to upgrade. I'd prefer to just throw exceptions, but depending when the change is made, you can throw deprecation warning. |
|
With this solution you'd need to locate and replace all I have another idea - maybe we should have a new find method (both on repository and query) to support the new API? This way we could still use the old API with option array and the new one with variadic arguments. This is can be introduced in a minor release without breaking people's code. The new method could be named $this->findBy('foo', $object1, $object2)->find('bar', $array); |
|
How is that any different? The finder names will conflict with existing methods. |
|
How would they conflict? |
Only for those that pass in query options. |
Yes, but that is still a big breaking change in all community plugins and userland code. Please note that this applies not only to the pre 3.x find calls with |
Well, you can fix the mess or not, lol. |
|
I don't think that it's a mess. I don't even think that option arrays are inconvenience, because a lot of people like "named" arguments for options. With #12784 I just wanted to introduce more convenient way of passing objects into finders while leveraging built in PHP7.1+ type checking. |
|
Just offering my opinion that mixing query options + custom finder options in an array that's treated as a special parameter in variadic magic finder methods is really awkward. But, I it isn't up to me. |
|
OK I see that's awkward but it had to be done one way or the other to keep the BC. But now I realise that the variadic parameter support can be introduced as a new method without breaking the existing API and the BC. I'll come up with a new PR soon but this will probably target 4.1 now. @ADmad please remind me - we can still introduce new method to interfaces in minors with 4.x? |
|
Usually you would soft add new methods through docblock. |
We can't update the interface in minor. But we could add the new method to Table class and add annotation to the RepositoryInterface as a compromise. |
|
@robertpustulka Instead of making While Cake conventionally uses methods named like |
|
I can’t chain finders using custom method. |
|
True that. If only the ORM required |
|
I didn't mean for this to get closed, I was removing the now stale 4.x branch. If you could open the pull request against master that would be appreciated as I cannot change the base branch now. |
First take on implementing #12784.
Existing tests pass with very few changes.
I didin't want to update the docs and haven't added any new tests as I'm not sure if this is a good way forward.