PHP-ETL - Operations
Transform - Filter Data
The Filter Data operation selectively skips items in the chain based on rules. It uses the Rule Engine to evaluate conditions; if the condition is not met, the item is not passed to subsequent operations.
Purpose
Use FilterDataConfig to:
- Remove unwanted items from the data stream
- Keep only items that meet specific criteria
- Filter based on field values or Symfony expressions
- Implement conditional data processing logic
Configuration
Basic Configuration
use Oliverde8\Component\PhpEtl\OperationConfig\Transformer\FilterDataConfig;
use Oliverde8\Component\RuleEngine\RuleConfig\GetRuleConfig;
// Keep items where field value is truthy
$config = new FilterDataConfig(new GetRuleConfig('IsSubscribed'));
Expression-Based Configuration
For a simple boolean condition, an Expression is often less verbose than a typed rule — a Symfony Expression Language string evaluated against data (the item’s data) and context (the execution context’s parameters):
use Oliverde8\Component\PhpEtl\Expression\Expression;
use Oliverde8\Component\PhpEtl\OperationConfig\Transformer\FilterDataConfig;
$config = new FilterDataConfig(new Expression('data["IsSubscribed"] == true'));
Constructor Parameters
public function __construct(
public readonly RuleConfigInterface|Expression|array $rules = [],
public readonly bool $negate = false,
string $flavor = 'default'
)
| Parameter | Type | Default | Description |
|---|---|---|---|
rules |
RuleConfigInterface\|Expression\|array |
[] |
A typed rule or an Expression. Item kept if the result is truthy. A plain array is also accepted but deprecated, see Legacy Array Syntax |
negate |
bool |
false |
If true, inverts the logic (keeps items that evaluate to falsy) |
flavor |
string |
'default' |
Operation flavor for custom implementations |
Input/Output
- Input:
DataItemobjects with data to filter - Output:
DataItemobjects that match the filter criteria (others are discarded)
Examples
Example 1: Simple Field Filter
Keep only subscribed customers:
use Oliverde8\Component\PhpEtl\ChainConfig;
use Oliverde8\Component\PhpEtl\Item\DataItem;
use Oliverde8\Component\PhpEtl\OperationConfig\Extract\CsvExtractConfig;
use Oliverde8\Component\PhpEtl\OperationConfig\Transformer\FilterDataConfig;
use Oliverde8\Component\PhpEtl\OperationConfig\Loader\CsvFileWriterConfig;
use Oliverde8\Component\RuleEngine\RuleConfig\GetRuleConfig;
$chainConfig = new ChainConfig();
$chainConfig
->addLink(new CsvExtractConfig())
->addLink(new FilterDataConfig(new GetRuleConfig('IsSubscribed')))
->addLink(new CsvFileWriterConfig('subscribed_customers.csv'));
$chainProcessor = $chainBuilder->createChain($chainConfig);
$chainProcessor->process(
new ArrayIterator([new DataItem(['file' => 'data/customers.csv'])]),
[]
);
Result: Only rows where IsSubscribed is truthy (non-null, non-false) are written to output.
Example 2: Negated Filter
Keep only non-subscribed customers using negate:
->addLink(new FilterDataConfig(
rules: new GetRuleConfig('IsSubscribed'),
negate: true
))
Result: Only rows where IsSubscribed is falsy (null or false) are written to output.
Example 3: Conditions with Expressions
For anything beyond a single truthy field, an Expression reads naturally and covers comparisons, boolean
logic, membership checks, and regex matching in one line:
use Oliverde8\Component\PhpEtl\Expression\Expression;
// Equality
new FilterDataConfig(new Expression('data["status"] == "published"'));
// Numeric range
new FilterDataConfig(new Expression('data["age"] >= 18'));
// AND
new FilterDataConfig(new Expression('data["status"] == "active" and data["verified"] == true'));
// OR / membership
new FilterDataConfig(new Expression('data["status"] in ["pending", "processing"]'));
// Pattern matching
new FilterDataConfig(new Expression('data["email"] matches "/@(company|partner)\\.com$/"'));
// Reading from the execution context alongside the item's data
new FilterDataConfig(new Expression('data["country"] == context["allowedCountry"]'));
See the Symfony Expression Language syntax reference for everything expressions support.
Example 4: Split into Multiple Files
Use ChainSplitConfig with filters to split data into multiple output files:
use Oliverde8\Component\PhpEtl\ChainConfig;
use Oliverde8\Component\PhpEtl\Item\DataItem;
use Oliverde8\Component\PhpEtl\OperationConfig\Extract\CsvExtractConfig;
use Oliverde8\Component\PhpEtl\OperationConfig\ChainSplitConfig;
use Oliverde8\Component\PhpEtl\OperationConfig\Transformer\FilterDataConfig;
use Oliverde8\Component\PhpEtl\OperationConfig\Loader\CsvFileWriterConfig;
use Oliverde8\Component\RuleEngine\RuleConfig\GetRuleConfig;
// Chain for subscribed customers
$subscribedChain = new ChainConfig();
$subscribedChain
->addLink(new FilterDataConfig(new GetRuleConfig('IsSubscribed')))
->addLink(new CsvFileWriterConfig('customers-subscribed.csv'));
// Chain for non-subscribed customers
$notSubscribedChain = new ChainConfig();
$notSubscribedChain
->addLink(new FilterDataConfig(
rules: new GetRuleConfig('IsSubscribed'),
negate: true
))
->addLink(new CsvFileWriterConfig('customers-not-subscribed.csv'));
// Main chain
$mainChain = new ChainConfig();
$mainChain
->addLink(new CsvExtractConfig())
->addLink(new ChainSplitConfig()
->addSplit($subscribedChain)
->addSplit($notSubscribedChain)
)
->addLink(new CsvFileWriterConfig('customers-all.csv'));
$chainProcessor = $chainBuilder->createChain($mainChain);
$chainProcessor->process(
new ArrayIterator([new DataItem(['file' => 'data/customers.csv'])]),
[]
);
Result: Three files are created:
customers-subscribed.csv- Only subscribed customerscustomers-not-subscribed.csv- Only non-subscribed customerscustomers-all.csv- All customers