Skip to content

Catalog Export Internals

Pipeline overview

ExportConfig (per-exporter config snapshot)
└── CatalogExportService::processNextChunk()
    ├── Acquires file lock (export.lock) — prevents concurrent runs
    ├── Reads state.json — tracks current_chunk, processed_products, status
    ├── ProductFetcher::retrieve($config, $offset, $limit) — fetches one page of products
    ├── For each ProductRowEnricherInterface:
    │   └── enrich($rows, $config) — adds/transforms columns
    ├── For each ExportType (FULL, LANG, COUNTRY):
    │   └── CsvChunkWriter::write(chunkPath, filteredRows, isFirstChunk)
    ├── Updates state.json
    └── If last chunk: assembleChunks() → renames chunk file to output file

ExportConfig

A readonly value object passed through the pipeline. Built by the CatalogExport Symfony console command from the FbpCatalogExporter entity and the shop's FbpPixelSetting.

Key fields: exportId, token, shopId, langId, currencyId, countryId, productsPerChunk, isStorePerChunkEnabled, exportCombinations, gtinField, categoryIds, manufacturerIds, supplierIds.

ProductFetcher

Queries the PS database for products matching the export config's filters (categories, manufacturers, suppliers, stock). Returns an array of raw product rows. Results are cached.

Enricher pipeline

ProductRowEnricherInterface — implement this to add or transform columns in the product rows before they are written to CSV.

interface ProductRowEnricherInterface
{
    /** @param array<array<string, mixed>> $rows
     *  @return array<array<string, mixed>> */
    public function enrich(array $rows, ExportConfig $config): array;
}

Register enrichers as Symfony services tagged with fabfacebookpixel.catalog_enricher.

ExportType

A PHP 8.1 backed enum with three cases:

Case Output file Columns
FULL feed_{token}.csv All catalog columns (id, title, description, image_link, price, gtin, brand, size, color, etc.)
LANG language_{token}.csv Language-specific override columns (id, title, description, product_type, link, override)
COUNTRY country_{token}.csv Country-specific price override columns (id, price, sale_price, override, link)

Chunk mode and file system layout

All working files for an export are stored in modules/fabfacebookpixel/var/export/{exportId}/:

File Description
export.lock Created at start of chunk, deleted on completion. Prevents concurrent runs.
state.json JSON state: status, current_chunk, processed_products, started_at, completed_at
chunk_full.csv Accumulating CSV during chunked export
chunk_lang.csv Accumulating CSV (LANG type)
chunk_country.csv Accumulating CSV (COUNTRY type)
feed_{token}.csv Final output (FULL) — present only after export completes
language_{token}.csv Final output (LANG)
country_{token}.csv Final output (COUNTRY)

When a new export cycle starts and the previous state is complete, all files are deleted and the process starts fresh.

Symfony console command

php bin/console fbp:catalog-export [--token=TOKEN] [--all]
  • Without --token: processes all configured exporters.
  • With --token: processes only the exporter matching that token.
  • Without --all: processes one chunk per exporter (cron-safe).
  • With --all: loops until the export is complete (suitable for manual full regeneration).

HTTP endpoints

CatalogExportController — chunk processing

GET /module/fabfacebookpixel/catalogexport?token={token}

Shells out to php bin/console fbp:catalog-export --token={token} (blocking, one chunk), then reads state.json and returns progress. The JS poller calls this endpoint repeatedly until status is complete, then fetches the file via catalogfeed.

Requires exec() to be enabled in PHP.

  • If token is missing: HTTP 400
  • If token does not match any exporter: HTTP 404
  • If the command exits with a non-zero code: HTTP 500
  • Otherwise: HTTP 200 with JSON { status, currentChunk, processedProducts }

status is one of idle, in_progress, or complete. The endpoint always returns JSON — it never streams a CSV file.

CatalogfeedController — download only

GET /module/fabfacebookpixel/catalogfeed?token={token}&type={full|lang|country}

Serves the pre-built output file. Does not trigger export generation.

  • If the output file does not exist (export not yet run): HTTP 404
  • If the file exists: streams the CSV as Content-Type: text/csv