Skip to content
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

Conversation

Copy link
Member Author

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.

Comment on lines 697 to 701
public function excludeAny(): static
{
$filters = call_user_func_array([$this, 'normaliseFilterArgs'], func_get_args());
return $this->filterOrExclude($filters, false, true);
}
Copy link
Member Author

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.

Comment on lines -670 to +753
$list->items = array_unique($itemsToKeep ?? [], SORT_REGULAR);
$list->items = $itemsToKeep;
Copy link
Member Author

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.

Copy link
Member

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.

Comment on lines +712 to +713
// Convert null to an empty string for backwards compatability, since nulls are treated specially
// in the ExactMatchFilter
Copy link
Member Author

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.

Copy link
Member

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?

Copy link
Member Author

@GuySartorelli GuySartorelli Aug 28, 2023

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

Comment on lines +716 to +724
// 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']);
}
}
Copy link
Member Author

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.

Comment on lines -548 to 553
if (!$this->canFilterBy($column)) {
if (!$this->canFilterBy(explode(':', $column)[0])) {
throw new InvalidArgumentException("Can't filter by column '$column'");
}
Copy link
Member Author

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.

Comment on lines +40 to +44
/**
* 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;
Copy link
Member Author

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.

Comment on lines -440 to +468
* @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.
Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member Author

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

GuySartorelli added a commit to creative-commoners/developer-docs that referenced this pull request Aug 28, 2023
GuySartorelli added a commit to creative-commoners/developer-docs that referenced this pull request Aug 28, 2023
@GuySartorelli GuySartorelli force-pushed the pulls/5/searchfilter-static-lists2 branch from eb6fa35 to 69f06e5 Compare August 28, 2023 04:37
@GuySartorelli GuySartorelli marked this pull request as ready for review August 28, 2023 04:59
Copy link
Member

@emteknetnz emteknetnz left a 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

src/ORM/ArrayList.php Outdated Show resolved Hide resolved
Comment on lines +712 to +713
// Convert null to an empty string for backwards compatability, since nulls are treated specially
// in the ExactMatchFilter
Copy link
Member

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?

Comment on lines -670 to +753
$list->items = array_unique($itemsToKeep ?? [], SORT_REGULAR);
$list->items = $itemsToKeep;
Copy link
Member

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.

src/ORM/Filters/UsesSearchFilters.php Outdated Show resolved Hide resolved
src/ORM/Filters/ComparisonFilter.php Outdated Show resolved Hide resolved
src/ORM/Filters/ComparisonFilter.php Outdated Show resolved Hide resolved
src/ORM/Filters/ComparisonFilter.php Outdated Show resolved Hide resolved
src/ORM/Filters/ExactMatchFilter.php Outdated Show resolved Hide resolved
src/ORM/Filters/PartialMatchFilter.php Outdated Show resolved Hide resolved
src/ORM/Filters/SearchFilter.php Outdated Show resolved Hide resolved
Copy link
Member

@emteknetnz emteknetnz left a 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

@GuySartorelli
Copy link
Member Author

Add some unicode unit tests

Done.

@GuySartorelli GuySartorelli force-pushed the pulls/5/searchfilter-static-lists2 branch from e66b425 to 4998353 Compare August 29, 2023 02:21
@emteknetnz emteknetnz merged commit b4463d9 into silverstripe:5 Aug 29, 2023
15 checks passed
@emteknetnz emteknetnz deleted the pulls/5/searchfilter-static-lists2 branch August 29, 2023 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants