Skip to content

Commit

Permalink
Introduce FilterCollection#restore method (#10537)
Browse files Browse the repository at this point in the history
* Introduce FilterCollection#restore method

* Add suspend method instead

* Add more tests
  • Loading branch information
VincentLanglet committed Jul 28, 2023
1 parent 24df74d commit 8e20e15
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 3 deletions.
31 changes: 31 additions & 0 deletions docs/en/reference/filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,34 @@ object.
want to refresh or reload an object after having modified a filter or the
FilterCollection, then you should clear the EntityManager and re-fetch your
entities, having the new rules for filtering applied.


Suspending/Restoring Filters
----------------------------
When a filter is disabled, the instance is fully deleted and all the filter
parameters previously set are lost. Then, if you enable it again, a new filter
is created without the previous filter parameters. If you want to keep a filter
(in order to use it later) but temporary disable it, you'll need to use the
``FilterCollection#suspend($name)`` and ``FilterCollection#restore($name)``
methods instead.

.. code-block:: php
<?php
$filter = $em->getFilters()->enable("locale");
$filter->setParameter('locale', 'en');
// Temporary suspend the filter
$filter = $em->getFilters()->suspend("locale");
// Do things
// Then restore it, the locale parameter will still be set
$filter = $em->getFilters()->restore("locale");
.. warning::
If you enable a previously disabled filter, doctrine will create a new
one without keeping any of the previously parameter set with
``SQLFilter#setParameter()`` or ``SQLFilter#getParameterList()``. If you
want to restore the previously disabled filter instead, you must use the
``FilterCollection#restore($name)`` method.
82 changes: 82 additions & 0 deletions lib/Doctrine/ORM/Query/FilterCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ class FilterCollection
*/
private $enabledFilters = [];

/**
* Instances of suspended filters.
*
* @var SQLFilter[]
* @psalm-var array<string, SQLFilter>
*/
private $suspendedFilters = [];

/**
* The filter hash from the last time the query was parsed.
*
Expand Down Expand Up @@ -83,6 +91,17 @@ public function getEnabledFilters()
return $this->enabledFilters;
}

/**
* Gets all the suspended filters.
*
* @return SQLFilter[] The suspended filters.
* @psalm-return array<string, SQLFilter>
*/
public function getSuspendedFilters(): array
{
return $this->suspendedFilters;
}

/**
* Enables a filter from the collection.
*
Expand All @@ -105,6 +124,9 @@ public function enable($name)

$this->enabledFilters[$name] = new $filterClass($this->em);

// In case a suspended filter with the same name was forgotten
unset($this->suspendedFilters[$name]);

// Keep the enabled filters sorted for the hash
ksort($this->enabledFilters);

Expand Down Expand Up @@ -135,6 +157,54 @@ public function disable($name)
return $filter;
}

/**
* Suspend a filter.
*
* @param string $name Name of the filter.
*
* @return SQLFilter The suspended filter.
*
* @throws InvalidArgumentException If the filter does not exist.
*/
public function suspend(string $name): SQLFilter
{
// Get the filter to return it
$filter = $this->getFilter($name);

$this->suspendedFilters[$name] = $filter;
unset($this->enabledFilters[$name]);

$this->setFiltersStateDirty();

return $filter;
}

/**
* Restore a disabled filter from the collection.
*
* @param string $name Name of the filter.
*
* @return SQLFilter The restored filter.
*
* @throws InvalidArgumentException If the filter does not exist.
*/
public function restore(string $name): SQLFilter
{
if (! $this->isSuspended($name)) {
throw new InvalidArgumentException("Filter '" . $name . "' is not suspended.");
}

$this->enabledFilters[$name] = $this->suspendedFilters[$name];
unset($this->suspendedFilters[$name]);

// Keep the enabled filters sorted for the hash
ksort($this->enabledFilters);

$this->setFiltersStateDirty();

return $this->enabledFilters[$name];
}

/**
* Gets an enabled filter from the collection.
*
Expand Down Expand Up @@ -177,6 +247,18 @@ public function isEnabled($name)
return isset($this->enabledFilters[$name]);
}

/**
* Checks if a filter is suspended.
*
* @param string $name Name of the filter.
*
* @return bool True if the filter is suspended, false otherwise.
*/
public function isSuspended(string $name): bool
{
return isset($this->suspendedFilters[$name]);
}

/**
* Checks if the filter collection is clean.
*
Expand Down
96 changes: 93 additions & 3 deletions tests/Doctrine/Tests/ORM/Query/FilterCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,54 @@ public function testEnable(): void

self::assertCount(0, $filterCollection->getEnabledFilters());

$filterCollection->enable('testFilter');
$filter1 = $filterCollection->enable('testFilter');

$enabledFilters = $filterCollection->getEnabledFilters();

self::assertCount(1, $enabledFilters);
self::assertContainsOnly(MyFilter::class, $enabledFilters);

$filterCollection->disable('testFilter');
$filter2 = $filterCollection->disable('testFilter');
self::assertCount(0, $filterCollection->getEnabledFilters());
self::assertSame($filter1, $filter2);

$filter3 = $filterCollection->enable('testFilter');
self::assertNotSame($filter1, $filter3);

$filter4 = $filterCollection->suspend('testFilter');
self::assertSame($filter3, $filter4);

$filter5 = $filterCollection->enable('testFilter');
self::assertNotSame($filter4, $filter5);

self::assertCount(1, $enabledFilters);
self::assertContainsOnly(MyFilter::class, $enabledFilters);
}

public function testSuspend(): void
{
$filterCollection = $this->em->getFilters();

self::assertCount(0, $filterCollection->getEnabledFilters());

$filter1 = $filterCollection->enable('testFilter');
self::assertCount(1, $filterCollection->getEnabledFilters());

$filter2 = $filterCollection->suspend('testFilter');
self::assertSame($filter1, $filter2);
self::assertCount(0, $filterCollection->getEnabledFilters());

$filter3 = $filterCollection->restore('testFilter');
self::assertSame($filter1, $filter3);
self::assertCount(1, $filterCollection->getEnabledFilters());
}

public function testRestoreFailure(): void
{
$filterCollection = $this->em->getFilters();

$this->expectException(InvalidArgumentException::class);
$filterCollection->suspend('testFilter');
}

public function testHasFilter(): void
Expand All @@ -49,7 +88,6 @@ public function testHasFilter(): void
self::assertFalse($filterCollection->has('fakeFilter'));
}

/** @depends testEnable */
public function testIsEnabled(): void
{
$filterCollection = $this->em->getFilters();
Expand All @@ -59,6 +97,41 @@ public function testIsEnabled(): void
$filterCollection->enable('testFilter');

self::assertTrue($filterCollection->isEnabled('testFilter'));

$filterCollection->suspend('testFilter');

self::assertFalse($filterCollection->isEnabled('testFilter'));

$filterCollection->restore('testFilter');

self::assertTrue($filterCollection->isEnabled('testFilter'));

self::assertFalse($filterCollection->isEnabled('wrongFilter'));
}

public function testIsSuspended(): void
{
$filterCollection = $this->em->getFilters();

self::assertFalse($filterCollection->isSuspended('testFilter'));

$filterCollection->enable('testFilter');

self::assertFalse($filterCollection->isSuspended('testFilter'));

$filterCollection->suspend('testFilter');

self::assertTrue($filterCollection->isSuspended('testFilter'));

$filterCollection->restore('testFilter');

self::assertFalse($filterCollection->isSuspended('testFilter'));

$filterCollection->disable('testFilter');

self::assertFalse($filterCollection->isSuspended('testFilter'));

self::assertFalse($filterCollection->isSuspended('wrongFilter'));
}

public function testGetFilterInvalidArgument(): void
Expand All @@ -74,6 +147,11 @@ public function testGetFilter(): void
$filterCollection->enable('testFilter');

self::assertInstanceOf(MyFilter::class, $filterCollection->getFilter('testFilter'));

$filterCollection->suspend('testFilter');

$this->expectException(InvalidArgumentException::class);
$filterCollection->getFilter('testFilter');
}

public function testHashing(): void
Expand All @@ -99,6 +177,18 @@ public function testHashing(): void
self::assertTrue($filterCollection->isClean());
self::assertSame($hash, $filterCollection->getHash());

$filterCollection->suspend('testFilter');

self::assertFalse($filterCollection->isClean());
self::assertSame($oldHash, $filterCollection->getHash());
self::assertTrue($filterCollection->isClean());

$filterCollection->restore('testFilter');

self::assertFalse($filterCollection->isClean());
self::assertSame($hash, $filterCollection->getHash());
self::assertTrue($filterCollection->isClean());

$filterCollection->disable('testFilter');

self::assertFalse($filterCollection->isClean());
Expand Down

0 comments on commit 8e20e15

Please sign in to comment.