Skip to content

Instantly share code, notes, and snippets.

@juanwilde
Created September 14, 2025 10:02
Show Gist options
  • Select an option

  • Save juanwilde/1a999f3ebc7241c8273b0e63c913cbb1 to your computer and use it in GitHub Desktop.

Select an option

Save juanwilde/1a999f3ebc7241c8273b0e63c913cbb1 to your computer and use it in GitHub Desktop.
// EventImport
<?php
declare(strict_types=1);
namespace App\Application\UseCase;
use App\Application\Service\EventProviderInterface;
use App\Domain\Repository\EventRepository;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
use Throwable;
use function iterator_count;
use function sprintf;
final readonly class EventImport
{
/**
* @param iterable<EventProviderInterface> $providers
*/
public function __construct(
#[AutowireIterator('app.event.provider')]
private iterable $providers,
private EventRepository $eventRepository,
private LoggerInterface $logger,
) {}
public function execute(): void
{
$this->logger->info(sprintf('Providers: %s', iterator_count($this->providers)));
foreach ($this->providers as $provider) {
try {
$events = iterator_to_array($provider->fetchEvents());
if (!empty($events)) {
$this->eventRepository->bulkUpsert($events);
}
} catch (Throwable $e) {
$this->logger->error(sprintf('Provider %s failed with error <%s>', $provider->getName(), $e->getMessage()));
continue;
}
}
}
}
// EventRepository
<?php
declare(strict_types=1);
namespace App\Domain\Repository;
use App\Domain\DTO\EventDTO;
use App\Domain\Entity\Event;
interface EventRepository
{
public function findOneByProviderAndExternalId(string $provider, string $externalId): ?Event;
/**
* @return array<int, Event>
*/
public function findByDateRange(int $startTimestamp, int $endTimestamp): array;
public function persist(Event $event): void;
public function flush(): void;
/**
* @param array<EventDTO> $eventDTOs
*/
public function bulkUpsert(array $eventDTOs): void;
}
// DoctrineEvent Repository
<?php
declare(strict_types=1);
namespace App\Adapter\Persistence\Doctrine;
use App\Domain\DTO\EventDTO;
use App\Domain\Entity\Event;
use App\Domain\Repository\EventRepository;
use DateTimeImmutable;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Ramsey\Uuid\Uuid;
/**
* @extends ServiceEntityRepository<Event>
*/
final class DoctrineEventRepository extends ServiceEntityRepository implements EventRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Event::class);
}
// ...existing code...
/**
* @param array<EventDTO> $eventDTOs
*/
public function bulkUpsert(array $eventDTOs): void
{
if (empty($eventDTOs)) {
return;
}
$connection = $this->getEntityManager()->getConnection();
$sql = <<<'SQL'
INSERT INTO events (
id, external_id, event_provider, title, starts_at, ends_at,
min_price, max_price, sell_mode, ever_online
) VALUES %s
ON CONFLICT (event_provider, external_id)
DO UPDATE SET
title = EXCLUDED.title,
starts_at = EXCLUDED.starts_at,
ends_at = EXCLUDED.ends_at,
min_price = EXCLUDED.min_price,
max_price = EXCLUDED.max_price,
sell_mode = EXCLUDED.sell_mode,
ever_online = events.ever_online OR (EXCLUDED.sell_mode = 'online')
SQL;
$values = [];
$params = [];
$types = [];
foreach ($eventDTOs as $i => $dto) {
$values[] = sprintf(
'($%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d)',
$i * 10 + 1, $i * 10 + 2, $i * 10 + 3, $i * 10 + 4, $i * 10 + 5,
$i * 10 + 6, $i * 10 + 7, $i * 10 + 8, $i * 10 + 9, $i * 10 + 10
);
$params = array_merge($params, [
Uuid::uuid4()->toString(),
$dto->externalId,
$dto->eventProvider->value,
$dto->title,
$dto->startsAt,
$dto->endsAt,
$dto->minPrice,
$dto->maxPrice,
$dto->sellMode,
$dto->sellMode === 'online'
]);
$types = array_merge($types, [
'string', 'string', 'string', 'string', 'datetimetz_immutable',
'datetimetz_immutable', 'decimal', 'decimal', 'string', 'boolean'
]);
}
$finalSql = sprintf($sql, implode(', ', $values));
$connection->executeStatement($finalSql, $params, $types);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment