Export

  1. Data providers
    1. Optional interfaces
  2. Full import
  3. Partial export
  4. Dry run
  5. Lock
  6. Options
  7. Events

Data providers

A data provider delivers the documents of one kind, e.g. products or blog posts, as DTOs of the SDK. Every service implementing DataProviderInterface is tagged automatically.

use Batteryincluded\BatteryincludedBundle\Provider\DataProviderInterface;
use BatteryIncludedSdk\Dto\ProductBaseDto;

final class ProductProvider implements DataProviderInterface
{
    public function __construct(private ProductRepository $products)
    {
    }

    public function getBatches(int $batchSize): \Generator
    {
        // load and yield page by page, the export never needs the whole catalog in memory
        foreach ($this->products->iterateActive($batchSize) as $products) {
            yield array_map($this->toDto(...), $products);
        }
    }

    private function toDto(Product $product): ProductBaseDto
    {
        $dto = new ProductBaseDto((string) $product->getId());
        $dto->setId((string) $product->getId());
        $dto->setName($product->getName());
        $dto->setPrice($product->getPrice());

        return $dto;
    }
}

The SDK documentation describes the DTOs, translations and availabilities.

Optional interfaces

Interface Method Effect
PartialDataProviderInterface getByIds(array $ids): iterable Delivers single documents for bi:sync, the Doctrine integration and the messages
CollectionAwareDataProviderInterface supportsCollection(string $collection): bool Restricts the provider to some collections, all others deliver to every collection
use Batteryincluded\BatteryincludedBundle\Provider\PartialDataProviderInterface;

final class ProductProvider implements PartialDataProviderInterface
{
    // ids are document ids like PRODUCT-5, ignore the ids of other types
    public function getByIds(array $ids): iterable
    {
        $productIds = array_map(
            static fn (string $id) => (int) mb_substr($id, 8),
            array_filter($ids, static fn (string $id) => str_starts_with($id, 'PRODUCT-')),
        );

        return array_map($this->toDto(...), $this->products->findActiveByIds($productIds));
    }
}

Full import

bin/console bi:export --dry-run   # loads and serializes everything, nothing is sent
bin/console bi:export             # asks for confirmation
bin/console bi:export --force     # cron jobs, deployments, CI

A full import sends all documents in one transaction. When it is committed, all other documents of the collection are deleted. Test it against a dedicated test collection.

The command sends the batches of all providers with the same transaction id and commits the transaction with the last batch. It protects the collection:

Situation Behaviour
The API answers with an error status Stops, the transaction is not committed, the collection is unchanged
The API rejects documents Stops before the commit and lists the rejected documents
The providers deliver no document Stops, an empty commit would empty the collection
No interaction and no --force Stops, nothing is sent
Another export into the same collection is running Stops, see lock
A PreExportEvent listener cancels Stops before the first document is loaded

At the end a table shows documents, batches and time per provider. With -v every API response is printed instead of the progress bar.

Partial export

bin/console bi:export --provider=ProductProvider

With --provider (class or short class name, repeatable) the documents of these providers are created or replaced without transaction, nothing is deleted. Documents the provider no longer delivers stay in the collection, use bi:delete or a full import to remove them.

Dry run

--dry-run loads every batch, dispatches the DocumentsEvent and serializes each document like the export would. It reports serialization errors (e.g. invalid UTF-8) and document ids delivered more than once. Nothing is sent and no lock is taken.

Lock

The export takes a lock per collection (batteryincluded-export-<name>, one hour). It uses the lock.factory of the application if symfony/lock is configured, otherwise a file lock, so cron jobs on one server never overlap. Configure a shared store (e.g. Redis) if exports can start on several servers.

Options

Option Default Meaning
--collection, -c default Name of the collection in the bundle configuration
--provider, -p all Export only these providers, create or replace, nothing is deleted
--batch-size, -b export.batch_size Documents per request
--dry-run   Load and serialize only
--force, -f   Skip the confirmation, required without interaction
-v   Print every API response

Exit codes: 0 success, 1 failure, 2 invalid options.

Events

bi:export dispatches the PreExportEvent, a DocumentsEvent per batch and the PostExportEvent: cancel the export, enrich or filter documents, react on the result.