Published on

TYPO3 CLI/Symfony Command, Extbase Data Import & Validation

Authors

Recently I wanted to write an import script and instead of using the DataHandler, I used my existing Extbase repository and Extbase’s validation. Here’s a minimal example to get you started.

1) Register the Symfony Command

Configuration/Services.yaml:

services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  Vendor\MyExt\Command\ImportCommand:
    tags: ['console.command']

2) Implement the Command

Classes/Command/ImportCommand.php:

<?php

declare(strict_types=1);

namespace Vendor\MyExt\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use Vendor\MyExt\Domain\Repository\CustomerRepository;
use Vendor\MyExt\Domain\Model\Customer;
use TYPO3\CMS\Extbase\Validation\ValidatorResolver;

#[AsCommand(name: 'myext:import')]
final class ImportCommand extends Command
{
    public function __construct(
        private readonly CustomerRepository $customers,
        private readonly ValidatorResolver $validatorResolver,
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $data = [
            ['name' => 'Ada Lovelace', 'email' => 'ada@example.org'],
            // ...
        ];

        foreach ($data as $row) {
            $customer = new Customer();
            $customer->setName($row['name']);
            $customer->setEmail($row['email']);

            $validator = $this->validatorResolver->getBaseValidatorConjunction(Customer::class);
            $result = $validator->validate($customer);
            if ($result->hasErrors()) {
                $output->writeln('<error>Invalid row: ' . (string)$result . '</error>');
                continue;
            }

            $this->customers->add($customer);
        }

        $this->customers->persistAll();
        $output->writeln('<info>Import done.</info>');
        return self::SUCCESS;
    }
}

3) Domain model & validation

Classes/Domain/Model/Customer.php (simplified):

<?php
namespace Vendor\MyExt\Domain\Model;

use TYPO3\CMS\Extbase\Annotation as Extbase;

final class Customer extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
    #[Extbase\Validate(['validator' => 'NotEmpty'])]
    protected string $name = '';

    #[Extbase\Validate(['validator' => 'EmailAddress'])]
    protected string $email = '';

    public function setName(string $name): void { $this->name = $name; }
    public function setEmail(string $email): void { $this->email = $email; }
}

4) Run it

vendor/bin/typo3 myext:import

Notes

  • Use repositories for persistence; call persistAll() after batching
  • Favor attribute-based validators in TYPO3 v12+
  • Add DTOs and mappers for complex imports

This approach leverages Extbase validation and repositories directly in a Symfony Console command, keeping your import logic testable and clean.