-
-
Notifications
You must be signed in to change notification settings - Fork 344
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
Add Array filter to search value in @ORM\Column(type="array")
#1042
Add Array filter to search value in @ORM\Column(type="array")
#1042
Conversation
fb1ef06
to
4e72ee7
Compare
4e72ee7
to
f892b8c
Compare
If I got you wrong, you have to input the string |
IMHO we should not support filter for a IIUC the implementation, it only works with plain arrays of strings, but this field could contain basically anything. If someone wants to query a field like that, IMHO should consider using another type field or mecanism. |
No it works like the ChoiceFilter, you can provide an array or a single element, since there is the following code:
You can use it
Or
This dont works with strings only. For example if you look for the value
The This PR close an opened issue, which was approved by others, and we have a working solution to provide.
This only means that we need to document it here https://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/filter_field_definition.html. I'll add documentation. |
Please do atomic commits, right now you have one commit for the new feature, one commit for its documentation, and that second commit contains unrelated things, and then there is one more commit about improving documentation that does not say why there is an improvement or even what that improvement is. |
8ff3d74
to
8266739
Compare
Should be better now @greg0ire |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gave this a technical review, but maybe concerns raised by @franmomu are justified?
Developers doesn't always have the hand over the Database.
Surely if you develop such an application you can request a column to be added or things like that, can't you?
The ORM\Column(type="array") is may not the best to make query but if someone use it, he has his reasons.
I think that happened to me in the distant past, and I think the reason was I did not have the filtering requirement from the beginning, so I ended up either using LIKE
as you did or, when I had the time and motivation, move to a separate enum-like entity.
It does work but I didn't contribute it because it has a few implications, like what if the user saves an associative array? What if the user uses values or keys that are literally s:
? That last one make me switch to json_array
. Maybe there should be some restrictions, to avoid generating support.
There are also performance implications, this will not perform well on big tables because of the LIKE %
makes indices unusable.
What I'm trying to say is that giving power to developers, "treating them like adults" like some people like to say, can lead to weird bugs/performance issues that can generate a lot of support. I'm a bit undecided on this feature, but one thing I am sure of is that this shouldn't be merged without at least big fat warnings in the documentation, and requires maybe even some restrictions in the code.
ArrayFilter | ||
----------- | ||
|
||
``Sonata\AdminBundle\Form\Type\ChoiceType`` supports filtering on value saved in database as a serialized array with ``@ORM\Column(type="array")`` annotation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
``Sonata\AdminBundle\Form\Type\ChoiceType`` supports filtering on value saved in database as a serialized array with ``@ORM\Column(type="array")`` annotation. | |
``Sonata\AdminBundle\Form\Type\ChoiceType`` supports filtering on values saved in databases as serialized arrays with the ``@ORM\Column(type="array")`` annotation. |
|
||
``Sonata\AdminBundle\Form\Type\ChoiceType`` supports filtering on value saved in database as a serialized array with ``@ORM\Column(type="array")`` annotation. | ||
It is recommended to use another table and ``OneToMany`` relations if you want to make complex ``SQL`` queries. | ||
But this filter can provide some basic queries like searching a specific ``string`` value inside an array of ``string`` values:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please comply with the sf docs standards:
It is recommended to use another table and ``OneToMany`` relations if you want to make complex ``SQL`` queries. | ||
But this filter can provide some basic queries like searching a specific ``string`` value inside an array of ``string`` values:: | ||
|
||
protected function configureDatagridFilters(DatagridMapper $datagridMapper) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected function configureDatagridFilters(DatagridMapper $datagridMapper) | |
protected function configureDatagridFilters(DatagridMapper $datagridMapper): void |
src/Filter/ArrayFilter.php
Outdated
|
||
final class ArrayFilter extends Filter | ||
{ | ||
public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data) | |
public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data): void |
tests/Filter/ArrayFilterTest.php
Outdated
|
||
class ArrayFilterTest extends TestCase | ||
{ | ||
public function testEmpty(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public function testEmpty(): void | |
public function testItStaysDisabledWhenFilteringWithAnEmptyValue(): void |
tests/Filter/ArrayFilterTest.php
Outdated
$this->assertFalse($filter->isActive()); | ||
} | ||
|
||
public function testNullValue(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public function testNullValue(): void | |
public function testFilteringWithNullReturnsArraysThatContainNull(): void |
tests/Filter/ArrayFilterTest.php
Outdated
$this->assertTrue($filter->isActive()); | ||
} | ||
|
||
public function testContains(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using a data provider with
{
yield 'explicit contains' => [ContainsOperatorType::TYPE_CONTAINS];
yield 'implicit contains' => [null];
}
tests/Filter/ArrayFilterTest.php
Outdated
$filter->filter($builder, 'alias', 'field', ['value' => 'asd', 'type' => null]); | ||
$this->assertSame(['alias.field LIKE :field_name_0'], $builder->query); | ||
$this->assertSame(['field_name_0' => '%s:3:"asd";%'], $builder->parameters); | ||
$this->assertTrue($filter->isActive()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason not to do this assertion the first time?
tests/Filter/ArrayFilterTest.php
Outdated
$this->assertTrue($filter->isActive()); | ||
} | ||
|
||
public function testMultipleValues(): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be more tests with multiple values IMO, because the behavior is debatable: should it return arrays that contain all the values or any of them? That should be clearly expressed in the test.
It's a bit better indeed, for instance the 3rd commit is ok, apart from one thing; it should be first, and all the other commits should be squashed together, because it makes no sense to separate them:
|
It's indeed easily possible to add new column, but not always easy to migrate some existing columns when the
I tried a general approach without too much context in the filter and be as far as possible usable and re-usable. But I'm ok with the fact to add restrictions. How would you add them ? I can also change the name of the filter, if it helps. Since the most useful cases are when you use it with an array of string, I change to something like
I was more like "This is already useful for me, this will certainly be useful for others, let's share it. Plus thanks to open-source and contribution, this will be permanently improved other time.". But I understand your point.
I'm open to any "big fat warnings" or "restrictions" to add. @greg0ire ;) |
I would maybe disallow searching for characters used for serialization, like
Then please do. Some can be forbidden in the code directly, like the above, some others should be warned about: "You should use this if you can't have that list in a separate table, and the list is not used with a table that is too big, and your list consist only in simple strings that don't contain metacharacters like |
I do like
Since I search for the serialize value
Yes I need to add a warning indeed. |
You can save any serializable thing: <?php
$object = new \StdClass();
$object->a = [
's' => 's:1:"s"'
];
$object->s = 's:1:"s"';
$data = [
$object,
['s' => 's:1:"s"'],
['s' => [
's' => 's'
]]
]; resulting in:
That's why I said it could be complex. What I meant is what @greg0ire said, doing this could lead to more issues (as it is not a full solution). In the case of a list of string I guess it makes more sense to use |
|
f59e88e
to
93cab74
Compare
93cab74
to
e61e0b9
Compare
@greg0ire Is this filter now technically OK for you ? @sonata-project/contributors Can we discuss about the pro/con about adding this filter ? |
e61e0b9
to
00527a7
Compare
00527a7
to
238deff
Compare
Subject
This filter allow to search for specific value when you use
@ORM\Column(type="array")
.Let's say you have in database
1 => ['a']
2 => ['b']
3 => ['c']
4 => ['a', 'b']
5 => ['a', 'c']
6 => ['a', 'b', 'c']
If you search
['a']
; you'll get 1,4,5,6.['a']
; you'll get 2,3.['a']
; you'll get 1.['a', 'b']
; you'll get 4,6.['a', 'b']
; you'll get 3.['a', 'b']
; you'll get 4.I am targeting this branch, because BC.
Closes #1029
Changelog