-
Notifications
You must be signed in to change notification settings - Fork 823
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
NEW Enable ArrayList and EagerLoadedList to use search filters #10925
NEW Enable ArrayList and EagerLoadedList to use search filters #10925
Conversation
09bc9fb
to
c8992b8
Compare
1417710
to
eb6fa35
Compare
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.
I've moved a couple of methods in this class to be next to each other where they have similar functionality. I've only moved methods that are already being changed in this PR anyway.
src/ORM/ArrayList.php
Outdated
public function excludeAny(): static | ||
{ | ||
$filters = call_user_func_array([$this, 'normaliseFilterArgs'], func_get_args()); | ||
return $this->filterOrExclude($filters, false, true); | ||
} |
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.
Adding this new method isn't necessary by any means - but it's a very low effort, low risk change that helps align the ArrayList API with other lists. I think it's well worth adding and I've provided adequate test coverage.
$list->items = array_unique($itemsToKeep ?? [], SORT_REGULAR); | ||
$list->items = $itemsToKeep; |
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.
We absolutely shouldn't be sorting here. That's what the sort method is for.
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.
Yeah shouldn't .... you could argue it is a behaviour change so existing data on a website could change its presentation after upgrade. However, I'd counter and say we're fixing a bug here.
// Convert null to an empty string for backwards compatability, since nulls are treated specially | ||
// in the ExactMatchFilter |
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.
Converting null
to an empty string means we retain backwards compatability where it used to be doing a $value1 == $value2
check. ExactMatchFilter
is doing a string ===
comparison if there's a null value involved.
By swapping null out for an empty string here, we end up with a value that behaves identically to null with the looser comparison and therefore retains the same behaviour we had prior to this PR for ArrayList.
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.
Would it make sense to hae a Deprecation::notice() when it finds a null $filterValue and say that the behaviour will be changed in CMS 6?
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.
I don't think so - we're not going to deprecate passing in null
values, so deprecation isn't quite right. We'll just be changing how they're treated in CMS 6. I think calling it out in the CMS 6 changelog will be sufficient.
Note there is an issue to change this behaviour already: #10930
// Apply default case sensitivity for backwards compatability | ||
if (!str_contains($filterKey, ':case') && !str_contains($filterKey, ':nocase')) { | ||
$caseSensitive = Deprecation::withNoReplacement(fn() => static::config()->get('default_case_sensitive')); | ||
if ($caseSensitive && in_array('case', $searchFilter->getSupportedModifiers())) { | ||
$searchFilter->setModifiers($searchFilter->getModifiers() + ['case']); | ||
} elseif (!$caseSensitive && in_array('nocase', $searchFilter->getSupportedModifiers())) { | ||
$searchFilter->setModifiers($searchFilter->getModifiers() + ['nocase']); | ||
} | ||
} |
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.
ArrayList was implicitly case sensitive before, because it was just doing a simple ==
check. We therefore have to assume any filters that aren't adding a case
or nocase
filter will use the default case sensitivity.
I've made that default configurable so that people can set their projects to have a uniform default case sensitivity across all the list implementations.
if (!$this->canFilterBy($column)) { | ||
if (!$this->canFilterBy(explode(':', $column)[0])) { | ||
throw new InvalidArgumentException("Can't filter by column '$column'"); | ||
} |
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.
This exception is here for parity with DataList, so we need to make sure we can filter by the underlying field.
/** | ||
* Whether search filters should be case sensitive or not by default. | ||
* If null, the database collation setting is used. | ||
*/ | ||
private static ?bool $default_case_sensitive = null; |
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.
This configuration property isn't strictly necessary for this functionality to work, but it makes testing a lot easier and allows developers to declare a default case sensitivity for their project without having to muck about with database configuration, which is the current way to define the default case sensitivity.
I've added some tests for this in DataList.
* @return Mixed TRUE or FALSE to enforce sensitivity, NULL to use field collation. | ||
* @return ?bool TRUE or FALSE to enforce sensitivity, NULL to use field collation. |
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.
I haven't actually changed the return type - it was always returning only these types.
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.
This implementation is just a straight cut & paste from DataList::createSearchFilter()
- turned it into a trait to avoid code duplication since it's now used in three separate places and we want to keep the implementations in sync to avoid regressions.
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.
Some of the new test scenarios are from DataListTest
but most are brand new
eb6fa35
to
69f06e5
Compare
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.
Looks good, love all the tests. Some minor changes, mostly just naming
// Convert null to an empty string for backwards compatability, since nulls are treated specially | ||
// in the ExactMatchFilter |
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.
Would it make sense to hae a Deprecation::notice() when it finds a null $filterValue and say that the behaviour will be changed in CMS 6?
$list->items = array_unique($itemsToKeep ?? [], SORT_REGULAR); | ||
$list->items = $itemsToKeep; |
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.
Yeah shouldn't .... you could argue it is a behaviour change so existing data on a website could change its presentation after upgrade. However, I'd counter and say we're fixing a bug here.
0977590
to
e66b425
Compare
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.
Add some unicode unit tests
Done. |
e66b425
to
4998353
Compare
Replaces #10910
Issue
ArrayList
orEagerLoadedDataList
should support SearchFilter syntax for filter/exclude #5911