For arlanix/product-feed 1.0.0
Row transformers
This page is for the PHP developer whose feed needs what the mapping cannot express: a price your ERP decides, a product one market must not see, one row per pack size. A row transformer is your own code over a feed's rows. It runs between the built product and the mapping, so every channel, file, SFTP, Merchant API and Preview, sees what it returns. For the other ways to extend a feed, see Extend the module.
Write one
Implement Arlanix\Feed\Model\Delivery\RowTransformerInterface:
<?php
declare(strict_types=1);
namespace Vendor\Module\Model;
use Arlanix\Feed\Model\Delivery\RowTransformerInterface;
use Arlanix\Feed\Model\Feed;
use Arlanix\Feed\Model\Mapping\RowContext;
class PackSizes implements RowTransformerInterface
{
public function appliesTo(Feed $feed): bool
{
return $feed->getType() === 'google_shopping';
}
public function prepare(Feed $feed, array $rows): void
{
// Once per page of up to 500 rows, before any of them is transformed: read what you need in bulk here.
}
public function transform(Feed $feed, RowContext $row): array
{
if ($row->getValue('sku') === 'DISCONTINUED') {
return []; // left out
}
return [
$row->withVariant('6', ['title' => $row->getValue('name') . ', pack of 6']),
$row->withVariant('12', ['title' => $row->getValue('name') . ', pack of 12']),
];
}
}
transform() answers with the rows of the product it was given:
| It returns | What happens |
|---|---|
[$row->with([...])] |
The row goes on with those fields overwritten. |
[] |
The product is left out of the feed. A row delivered for it before is taken down. |
[$row->withVariant('a', [...]), $row->withVariant('b', [...])] |
One row per variant, each delivered and taken down on its own. A variant of a variant keeps both keys: a-x. A key is 1 to 64 characters, both keys together included; an empty or longer one throws InvalidArgumentException. |
Each row arrives with its prices, stock and addresses already in it (price, final_price, special_price, currency, url, …), so overwriting one of them is all it takes to change what the mapping reads.
A row of another product, or the same variant of a product twice, stops the run with a LogicException naming the transformer.
What a row holds
transform() and prepare() are given Arlanix\Feed\Model\Mapping\RowContext objects, one per product row. A row holds the product attributes the store view's feeds read, the fields the module computes for every row, and, for the child of a configurable product, its parent's fields under parent. An attribute is in the row only when a feed of the store view maps it, or a resolver in its mapping declares it; see Declare the attributes it reads.
| Method | Returns |
|---|---|
getValue(string $path): mixed |
A field's value, or null when the row has none. A dot reads into a nested field: parent.sku. |
has(string $path): bool |
Whether getValue() gives something other than null. |
with(array $overrides): RowContext |
The same row with these fields overwritten. A key with a dot is a field of that name, not a path. |
withVariant(string $key, array $overrides = []): RowContext |
One of several rows of the product, with these fields overwritten; see Write one. |
getVariantKey(): string |
The row's variant key, empty for a product's only row. |
getProductId(): int |
The product's id. |
getStoreId(): int |
The store view the row is for. |
getData(): array |
Every field of the row, as an array. |
A RowContext never changes: with() and withVariant() return a new row and leave the one they are called on as it was.
Register it
In your module's etc/di.xml, add the transformer to RowTransformerPool. sortOrder decides the order when there are several, each running on what the last one returned:
<type name="Arlanix\Feed\Model\Delivery\RowTransformerPool">
<arguments>
<argument name="transformers" xsi:type="array">
<item name="pack_sizes" xsi:type="array">
<item name="class" xsi:type="object">Vendor\Module\Model\PackSizes</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
</arguments>
</type>
An item may also be the object itself, with no sortOrder; it then counts as 0, and runs before every transformer with a positive one.
Something registered there that does not implement the interface fails at the first request, naming the item.
What the store sees
A product a transformer leaves out is counted in the grid's Health like one the mapping leaves out. Why? says a module of this installation left it out, and the feed's products list gives the reason as Excluded by row transformer "pack_sizes"., so the item name is the one to choose with the store in mind.