Use a deterministic method to generate parameter names for filters, to allow for proper caching of queries
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled

This commit is contained in:
Jan Böhmer 2025-09-09 23:05:03 +02:00
parent fcdeb0479a
commit 1a0fab0615
7 changed files with 29 additions and 7 deletions

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/ */
namespace App\DataTables\Filters; namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\AbstractConstraint;
use App\DataTables\Filters\Constraints\BooleanConstraint; use App\DataTables\Filters\Constraints\BooleanConstraint;
use App\DataTables\Filters\Constraints\DateTimeConstraint; use App\DataTables\Filters\Constraints\DateTimeConstraint;
use App\DataTables\Filters\Constraints\EntityConstraint; use App\DataTables\Filters\Constraints\EntityConstraint;
@ -32,6 +33,7 @@ use App\DataTables\Filters\Constraints\TextConstraint;
use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\AttachmentType;
use App\Services\Trees\NodesListBuilder; use App\Services\Trees\NodesListBuilder;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Omines\DataTablesBundle\Filter\AbstractFilter;
class AttachmentFilter implements FilterInterface class AttachmentFilter implements FilterInterface
{ {
@ -51,6 +53,9 @@ class AttachmentFilter implements FilterInterface
public function __construct(NodesListBuilder $nodesListBuilder) public function __construct(NodesListBuilder $nodesListBuilder)
{ {
//Must be done for every new set of attachment filters, to ensure deterministic parameter names.
AbstractConstraint::resetParameterCounter();
$this->dbId = new IntConstraint('attachment.id'); $this->dbId = new IntConstraint('attachment.id');
$this->name = new TextConstraint('attachment.name'); $this->name = new TextConstraint('attachment.name');
$this->targetType = new InstanceOfConstraint('attachment'); $this->targetType = new InstanceOfConstraint('attachment');

View file

@ -28,10 +28,7 @@ abstract class AbstractConstraint implements FilterInterface
{ {
use FilterTrait; use FilterTrait;
/** protected ?string $identifier;
* @var string
*/
protected string $identifier;
/** /**

View file

@ -28,6 +28,7 @@ trait FilterTrait
{ {
protected bool $useHaving = false; protected bool $useHaving = false;
protected static int $parameterCounter = 0;
public function useHaving($value = true): static public function useHaving($value = true): static
{ {
@ -50,8 +51,18 @@ trait FilterTrait
{ {
//Replace all special characters with underscores //Replace all special characters with underscores
$property = preg_replace('/\W/', '_', $property); $property = preg_replace('/\W/', '_', $property);
//Add a random number to the end of the property name for uniqueness return $property . '_' . (self::$parameterCounter++) . '_';
return $property . '_' . uniqid("", false); }
/**
* Resets the parameter counter, so the next call to generateParameterIdentifier will start from 0 again.
* This should be done before initializing a new set of filters to a fresh query builder, to ensure that the parameter
* identifiers are deterministic so that they are cacheable.
* @return void
*/
public static function resetParameterCounter(): void
{
self::$parameterCounter = 0;
} }
/** /**

View file

@ -88,7 +88,7 @@ class TagsConstraint extends AbstractConstraint
//Escape any %, _ or \ in the tag //Escape any %, _ or \ in the tag
$tag = addcslashes($tag, '%_\\'); $tag = addcslashes($tag, '%_\\');
$tag_identifier_prefix = uniqid($this->identifier . '_', false); $tag_identifier_prefix = $this->generateParameterIdentifier('tag');
$expr = $queryBuilder->expr(); $expr = $queryBuilder->expr();

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/ */
namespace App\DataTables\Filters; namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\AbstractConstraint;
use App\DataTables\Filters\Constraints\ChoiceConstraint; use App\DataTables\Filters\Constraints\ChoiceConstraint;
use App\DataTables\Filters\Constraints\DateTimeConstraint; use App\DataTables\Filters\Constraints\DateTimeConstraint;
use App\DataTables\Filters\Constraints\EntityConstraint; use App\DataTables\Filters\Constraints\EntityConstraint;
@ -44,6 +45,9 @@ class LogFilter implements FilterInterface
public function __construct() public function __construct()
{ {
//Must be done for every new set of attachment filters, to ensure deterministic parameter names.
AbstractConstraint::resetParameterCounter();
$this->timestamp = new DateTimeConstraint('log.timestamp'); $this->timestamp = new DateTimeConstraint('log.timestamp');
$this->dbId = new IntConstraint('log.id'); $this->dbId = new IntConstraint('log.id');
$this->level = new ChoiceConstraint('log.level'); $this->level = new ChoiceConstraint('log.level');

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/ */
namespace App\DataTables\Filters; namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\AbstractConstraint;
use App\DataTables\Filters\Constraints\BooleanConstraint; use App\DataTables\Filters\Constraints\BooleanConstraint;
use App\DataTables\Filters\Constraints\ChoiceConstraint; use App\DataTables\Filters\Constraints\ChoiceConstraint;
use App\DataTables\Filters\Constraints\DateTimeConstraint; use App\DataTables\Filters\Constraints\DateTimeConstraint;
@ -103,6 +104,9 @@ class PartFilter implements FilterInterface
public function __construct(NodesListBuilder $nodesListBuilder) public function __construct(NodesListBuilder $nodesListBuilder)
{ {
//Must be done for every new set of attachment filters, to ensure deterministic parameter names.
AbstractConstraint::resetParameterCounter();
$this->name = new TextConstraint('part.name'); $this->name = new TextConstraint('part.name');
$this->description = new TextConstraint('part.description'); $this->description = new TextConstraint('part.description');
$this->comment = new TextConstraint('part.comment'); $this->comment = new TextConstraint('part.comment');

View file

@ -21,6 +21,7 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
namespace App\DataTables\Filters; namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\AbstractConstraint;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
class PartSearchFilter implements FilterInterface class PartSearchFilter implements FilterInterface