-
Notifications
You must be signed in to change notification settings - Fork 729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Elastica/Query params converted to array on setters #783
Comments
Or the best way implement ArrayAccess interface to Param and another classes? And in this case we haven't BC but can work with queries parts as objects. |
@ewgRa I understand the issue. In case we change this, we would have to change this across the hole library I think. Because this "issue" exists for almost any object. Most of the time the objects are directly transformed to arrays to not have to deal with it at a later stage. I like the idea with ArrayAccess, but perhaps it could make even more sense to use ArrayObject as a foundation? We should discuss the pros and cons of the different options we have in detail as this would mean quite a radical change to the library. |
@ruflin ArrayAccess and ArrayObject will be also BC, or than it must be cloned, because can be such code: On my mind there is two options: '1. Create new class that will be decorator of Query, and on final call make DecoratorQuery->toQuery, on "search" methods add "if $query instanceof DecoratorQuery then call toQuery". Props: Cons: '2. Make Params as ArrayObject and all toArray replace to clone, to avoid BC. '3. Remove toArray everywere and call toArray on final build stage. This is how I see it, you as Elastica author can have different view and maybe have better ideas, at least how make 1. option much better. First option is longer way, but definitely have less surprises :) |
@ruflin I wrote tests that fix current state for Query class. See #802 There is many another classes that call toArray, did you think that this classes also must be covered with similar tests? It is about 65 places: grep toArray . -R | grep function -v | grep parent -v | grep @see -v | wc -l If there will be BC, tests will be broken and we will see this BC. Please merge it and say your opinion of which one way we can go. I prefer third one, but question in BC. Also as must be another toArray places covered by tests or not. |
tests, that fix toArray cast logic for #783
@ewgRa Sorry for the huge delay in answering. I think it is now time to pick this up again together with #878 I'm also in favor of method number 3. The main problem I see here is that no all toArray functions are the same and some need to raise exceptions etc. So the question is where and how this would be handled in the future? |
Really big question. I need more time to research code, also as to understand QueryBuilder work. As quick research:
I grep and see that they all have signature like "public function toArray()", I think they all can implement kind of Arrayable interface. What I miss or you mean something else?
As I understand #878 changes give us objects that always in valid state and in this case we will haven't exceptions in toArray and this problem is disappear. If not, I think there is only one option to handle it - only at toArray at final state, because we can say something about valid this object or not only on final state when object translated to elasticsearch query. This is also will be BC and I think must be covered by tests to understand this BC. |
Nope, it's not about it. It's about consistency of querybuilder methods and constructors.
If this is already BC, we could also instead of |
@ewgRa What I was meaning by the different toArray functions is that some check if all the params are set and are in the right type. The function name and parameters are always the same. @im-denisenko So if \Elastica\Param would implement JsonSerialisable all objects would support it and it would replace the toArray function. The part I don't like about this, is that the library then is built on top of the solution that it always must end in JSON. I know that Thrift etc. are deprecated, but I still don't think we should link it to a certain format before the data is transferred. |
@ruflin If we can't guarantee that object is valid until it will be converted to string - than we can handle exceptions only at final convertation to string - in our case - right before query will be executed. We can add "public function validate()" method, if someone want to check is object valid or not earlier and use it in toArray
Can't say anything, even haven't experience with recursive json serialization. Props and cons? Can we implement it both that jsonSerialize will just call toArray? |
@ewgRa Not so much, indeed. First difference is that JsonSerializable it's native php interface and we don't reinvent wheel with Arrayable which is almost same thing. Second is that toArray must serialize all inner objects when called, while jsonSerialize just returns them. JsonSerialize-way quite simpler, because you don't need to handle all these convertions by hand. public function toArray()
{
return ['foo' => $this->filter->toArray()];
}
public function jsonSerialize()
{
return ['foo' => $this->filter];
} In example above $this->filter is just an instance of AbstractFilter, but in case if there will be complex nested structure, we should iterate over it and call toArray from every structure's member. |
@ruflin Agree, haven't thought about it. |
Just a thought: we could provide BC layer using this trick: class Elastica\Param implements JsonSerializable
{
/**
* Hackish way to support convertion to array but use jsonSerialize internally.
*/
final public function toArray()
{
return json_decode(json_encode($this), true);
}
} |
Actually I like idea with JsonSerializable and I think we can implement it both. How about this https://gist.github.com/ewgRa/45e632b15bc523de03c4 ? |
Overhead and kind of tricky |
@ewgRa If we implement this
|
This way, in future, when php 5.3 would finally die, we could add support for JsonSerializable (just for convenience) with few lines of code: class Elastica\Param implements ArraySerializable, JsonSerializable
{
final public function jsonSerialize()
{
return $this->toArray();
}
} |
@im-denisenko toArray() for now must return only arrays, without objects. If we later will just call toArray at jsonSerialize - we lost advantage of this native recursion calls by JsonSerializable interface. Maybe extract this question to another issue? Our goal is fast working json serialization, but also have toArray. We can add to interface three methods: How to not drop 5.3 - we can have some extra logic and make it work like symfony work with IntlDateFormatter for example. Have custom replacement for JsonSerializable, implement \JsonSerializable, then check in code if it is native JsonSerializable interface, call json_encode(Object), if not - json_encode(Object->toArray) or something like this. Anyway, if we will have toArray that call toArrayWithObjects, later we can add jsonSerialize without break BC. On this week I go to vacation, and return at 12 July and will have time for make PR for this issue. |
I'm not sure if we mix here 3 problems:
For the last one I don't really understand what the problem is having it in the transport layer. Conversion to JSON (or any non PHP format) should happen as late as possible, which is in the transport layer. The first 2 are the ones we should focus on. My assumption in the beginning was that every object knows best how it is converted to an array, that is why the toArray function exists in every object. I really have to take a closer look again and think about it in more depth by going through all the comments above. Keep up the good discussion. |
Ok, lets focus on first two and then discuss third. I will prepare PR after 12 July. |
Mostly finished https://github.com/ewgRa/Elastica/tree/no-to-array-at-setters There is some places left, where toArray used, will be check it soon |
Looks promising. I like that most of the ->toArray() disappear. Make sure to use the $this->_convertArrayable() as it is a protected function. It's quite some time I have seen a recursive function 👍 During the brief review I got the felling that the following appeared multiple times (or similar functions): if (isset($array[$this->_getBaseName()]['query'])) {
$array[$this->_getBaseName()]['query'] = $array[$this->_getBaseName()]['query']['query'];
} Perhaps this could also be packaged in a function in case it is "really" the same. Haven't checked in detail ;-) |
PR - #916
If you have better idea how to make it more beautiful - let me know. I think about this code and haven't better idea how to rewrite it. Problem is that before there is no store objects in params, in many places there was $this->setParams($object->toArray()). Now we need store objects in params and at toArray this adds one extra key, that must be collapsed (in some cases with additional logic). |
I would suggest we merge it first and then see if we can find a better solution later. |
PR for this ticket merged. |
Thanks |
I have case, when Query must be created by two classes, for example there is BaseFooClass that set some basic logic like CompanyId match or Enabled match. And next one FooClass that add to this query additional logic, like Category match for example.
Problem is that when BaseFooClass create query and set Filter to Query, this filter cast and stored as array and next FooClass can't just get "getPostFilter" and add there some additional logic.
In this case I set object, but get array back and can't build query step by step in different places.
Can someone describe me a way to achieve desired in my case with current Elastica code? For now I create something like custom decorator that finally build Query with calling method "toQuery" for example, but I want have this functionality in Elastica.
I understand that this is a BC changes, but maybe there is possible to have decorator, or QueryBuilder (not DSL, DSL not working in this case).
I can create pull request for this, but first need feedback to understand is it is a good idea.
The text was updated successfully, but these errors were encountered: