Skip to main content
Version: 2024.1

Precondition Filter

The precondition filter is used to reduce the amount of objects that will be saved in the alternative element tree. You can set an implemented precondition filter in the configuration window from the Data Source tab at Precondition.

The precondition filter is applied when updating or adding elements and while generating the database table for the alternative element tree. Precondition filters are not part of the bundle and must be implemented specifically to your needs.

Implementing a Precondition Filter

To implement your own precondition filter you must extend AbstractPreconditionFilter. The abstract class implements the PreconditionFilterInterface and specifies an abstract method configureCondition(). You have to implement all the interface methods and the abstract method of the abstract class.

The class also provides a ConditionObject which stores query and params data. The ConditionObject is also used to apply the condition to an element listing. Ensure to provide a valid query to avoid getting an InvalidQueryException.

    // How the condition object is used in the code
/** @var PreconditionFilterInterface $preconditionFilter */
$preconditionFilter = new $preconditionFilterClass;

$condition = $preconditionFilter->getCondition();

$objects->addConditionParam($condition->getQuery(), $condition->getParams());
<?php
declare(strict_types=1);

namespace App\Services\PreconditionFilter;

use Pimcore\Bundle\BackendPowerToolsBundle\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\BackendPowerToolsBundle\Utils\ValueObjects\ConditionObject;

final class TheTruth extends AbstractPreconditionFilter
{
// the name is used to display it in the config
public function getName(): string
{
return 'The answer to life, the universe, and everything';
}

// if you want the condition only to apply for a specific type
public function isValidForType(string $type): bool
{
return $type === 'object';
}

// you must create a new ConditionObject here with first query and params as input params
// you have to either use placeholder ? or named params like in the example below:
protected function configureCondition(): void
{
$this->conditionObject = new ConditionObject('id = :id', ['id' => 42]);
}
}

Register a Precondition Filter

Every precondition filter must be registered with the pimcore.backend_power_tools.precondition_filter tag, e.g. in services.yaml. Registering a class without implementing the PreconditionFilterInterface will result in an exception.

    App\Services\PreconditionFilter\TheTruth:
tags: ['pimcore.backend_power_tools.precondition_filter']

Usage Examples for More Complex Conditions

In case you need a more complex query for your precondition, you can always inject other services into the precondition filter.

The following examples show a variety of query builder usages:

V8 Engines Only

You can use the query builder here to execute a query to get only object ids for which the car has a V8 engine. The result is then used in the condition like the following: id IN (17, 42, 73).

<?php
declare(strict_types=1);

namespace App\AlternativeElementTree\PreconditionFilter;

use Doctrine\DBAL\Exception;
use Pimcore\Bundle\BackendPowerToolsBundle\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\BackendPowerToolsBundle\Utils\ValueObjects\ConditionObject;
use Pimcore\Bundle\StaticResolverBundle\Db\DbResolverInterface;

final class V8 extends AbstractPreconditionFilter
{
public function __construct(private readonly DbResolverInterface $dbResolver)
{
parent::__construct();
}

/**
* @throws Exception
*/
protected function configureCondition(): void
{
$builder = $this->dbResolver->getConnection()->createQueryBuilder();

$builder
->select('id')
->from('object_brick_query_Engine_CAR')
->where('cylinders = :v8')
->setParameter('v8', 8);

// execute the query builder and use the ids for a sub select
$ids = array_map(static fn($value) => $value, [...$builder->executeQuery()->iterateColumn()]);

$this->conditionObject = new ConditionObject(
'id IN (:ids)',
['ids' => $ids]
);
}

public function getName(): string
{
return 'V8 Engines';
}

public function isValidForType(string $type): bool
{
return $type === 'object';
}
}

Reworked Cars and Soon Available

If you do not want to execute a query beforehand, you can also use the query builder to get a SQL sub-query. In this case, you can add the parameters to the ConditionObject params. The sub-query is then executed when the listing is loaded.

<?php
declare(strict_types=1);

namespace App\AlternativeElementTree\PreconditionFilter;

use Pimcore\Bundle\BackendPowerToolsBundle\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\BackendPowerToolsBundle\Utils\ValueObjects\ConditionObject;
use Pimcore\Bundle\StaticResolverBundle\Db\DbResolverInterface;

final class Reworked extends AbstractPreconditionFilter
{

public function __construct(private readonly DbResolverInterface $dbResolver)
{
parent::__construct();
}

protected function configureCondition(): void
{
$builder = $this->dbResolver->getConnection()->createQueryBuilder();

$builder
->select('id')
->from('object_brick_query_SaleInformation_CAR')
->where('`condition` = :condition AND (`availabilityType` = :availabilityTypeDays OR `availabilityType` = :availabilityTypeWeeks)');

// build sql with named parameters and inject named parameters into the condition object parameters
$this->conditionObject = new ConditionObject(
"id IN ({$builder->getSql()})",
[
'condition' => 'reworked',
'availabilityTypeDays' => 'couple-days',
'availabilityTypeWeeks' => 'couple-weeks'
]
);
}

public function getName(): string
{
return 'Reworked available in a couple of days/weeks';
}

public function isValidForType(string $type): bool
{
return $type === 'object';
}
}

(Not) Null Check

If you want to check if a field is (not) null, you can use the following example:

<?php
declare(strict_types=1);

namespace App\AlternativeElementTree\PreconditionFilter;

use Pimcore\Bundle\BackendPowerToolsBundle\PreconditionFilter\AbstractPreconditionFilter;
use Pimcore\Bundle\BackendPowerToolsBundle\Utils\ValueObjects\ConditionObject;

final class NotNullCheck extends AbstractPreconditionFilter
{

public function __construct()
{
parent::__construct();
}

protected function configureCondition(): void
{
$this->conditionObject = new ConditionObject(
"title IS NOT NULL",
['title' => ''],
);
}

public function getName(): string
{
return 'Example implementation for a not null check.';
}

public function isValidForType(string $type): bool
{
return $type === 'object';
}
}