vanta / temporal-doctrine
Integration temporal with doctrine
0.1
2025-06-05 10:42 UTC
Requires
- php: >=8.2
- doctrine/orm: ^2|^3
- temporal/sdk: ^2.7
Requires (Dev)
- doctrine/dbal: ^4.2
- friendsofphp/php-cs-fixer: ^3.46
- monolog/monolog: ^3.9
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.5
- sentry/sentry: ^3|^4
- symfony/cache: ^7.3
- symfony/var-dumper: ^6.0
README
Temporal is the simple, scalable open source way to write and run reliable cloud applications.
Introduction
Doctrine ORM for temporalio/sdk-php
Installation
composer require vanta/temporal-doctrine
Usage
Report open transaction to sentry
<?php declare(strict_types=1); use Sentry\SentrySdk; use Temporal\Interceptor\SimplePipelineProvider; use Temporal\WorkerFactory; use Vanta\Integration\Temporal\Doctrine\Interceptor\SentryDoctrineOpenTransactionInterceptor; use function Sentry\init; require_once __DIR__ . '/vendor/autoload.php'; init(['dsn' => 'https://1a36864711324ed8a04ba0fa2c89ac5a@sentry.temporal.local/52']); $hub = SentrySdk::getCurrentHub(); $client = $hub->getClient() ?? throw new \RuntimeException('Not Found client'); $factory = WorkerFactory::create(); $worker = $factory->newWorker( interceptorProvider: new SimplePipelineProvider([ new SentryDoctrineOpenTransactionInterceptor($hub, $client->getStacktraceBuilder()), ]) );
Report open transaction to monolog
<?php declare(strict_types=1); use Doctrine\DBAL\DriverManager; use Doctrine\ORM\ORMSetup; use Monolog\Handler\StreamHandler; use Monolog\Level; use Monolog\Logger; use Temporal\Interceptor\SimplePipelineProvider; use Temporal\WorkerFactory; use Vanta\Integration\Temporal\Doctrine\Interceptor\PsrLoggingDoctrineOpenTransactionInterceptor; require_once __DIR__ . '/vendor/autoload.php'; $config = ORMSetup::createAttributeMetadataConfiguration( paths: [__DIR__ . '/src'], isDevMode: true, ); $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'path' => __DIR__ . '/db.sqlite', ], $config); $logger = new Logger('stdout-logger'); $logger->pushHandler(new StreamHandler('php://stderr', Level::Debug)); $factory = WorkerFactory::create(); $worker = $factory->newWorker( interceptorProvider: new SimplePipelineProvider([ new PsrLoggingDoctrineOpenTransactionInterceptor($logger, $connection), ]) );
Clear UnitOfWork and reconnect db connection if connection lost
<?php declare(strict_types=1); use Doctrine\DBAL\DriverManager; use Doctrine\ORM\EntityManager; use Doctrine\ORM\ORMSetup; use Doctrine\Persistence\AbstractManagerRegistry as ManagerRegistry; use Temporal\Interceptor\SimplePipelineProvider; use Temporal\WorkerFactory; use Vanta\Integration\Temporal\Doctrine\Finalizer\DoctrineClearEntityManagerFinalizer; use Vanta\Integration\Temporal\Doctrine\Finalizer\DoctrinePingConnectionFinalizer; use Vanta\Integration\Temporal\Doctrine\Interceptor\DoctrineHandlerThrowsActivityInboundInterceptor; require_once __DIR__ . '/vendor/autoload.php'; $config = ORMSetup::createAttributeMetadataConfiguration( paths: [__DIR__ . '/src'], isDevMode: true, ); $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'path' => __DIR__ . '/db.sqlite', ], $config); $entityManager = new EntityManager($connection, $config); $managerRegistry = new class( 'test', ['default-connection' => 'default-connection'], ['default-manager' => 'default-manager'], 'default-connection', 'default-manager', \stdClass::class, ['default-connection' => $connection, 'default-manager' => $entityManager], ) extends ManagerRegistry { /** * @param array<string, string> $connections * @param array<string, string> $managers * @phpstan-param class-string $proxyInterfaceName * @param array<non-empty-string, object> $services */ public function __construct( string $name, array $connections, array $managers, string $defaultConnection, string $defaultManager, string $proxyInterfaceName, private readonly array $services ) { parent::__construct( $name, $connections, $managers, $defaultConnection, $defaultManager, $proxyInterfaceName ); } protected function getService(string $name): object { return $this->services[$name] ?? throw new RuntimeException(sprintf('Service "%s" not found', $name)); } protected function resetService(string $name): void { // TODO: Implement resetService() method. } }; $doctrinePingConnectionFinalizer = new DoctrinePingConnectionFinalizer($managerRegistry, 'default-manager'); $doctrineClearEntityManagerFinalizer = new DoctrineClearEntityManagerFinalizer($managerRegistry); $finalizers = [ $doctrinePingConnectionFinalizer, $doctrineClearEntityManagerFinalizer, ]; $factory = WorkerFactory::create(); $worker = $factory->newWorker( interceptorProvider: new SimplePipelineProvider([ new DoctrineHandlerThrowsActivityInboundInterceptor($doctrinePingConnectionFinalizer), ]) ); $worker->registerActivityFinalizer(function () use ($finalizers): void { foreach ($finalizers as $finalizer) { try { $finalizer->finalize(); } catch (\Throwable) { continue; } } });