EntityManager.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace PhpDevCommunity\PaperORM;
  3. use PhpDevCommunity\Listener\EventDispatcher;
  4. use PhpDevCommunity\Listener\ListenerProvider;
  5. use PhpDevCommunity\PaperORM\Cache\EntityMemcachedCache;
  6. use PhpDevCommunity\PaperORM\Driver\DriverManager;
  7. use PhpDevCommunity\PaperORM\Event\PreCreateEvent;
  8. use PhpDevCommunity\PaperORM\Event\PreUpdateEvent;
  9. use PhpDevCommunity\PaperORM\EventListener\CreatedAtListener;
  10. use PhpDevCommunity\PaperORM\EventListener\UpdatedAtListener;
  11. use PhpDevCommunity\PaperORM\Mapper\EntityMapper;
  12. use PhpDevCommunity\PaperORM\Parser\DSNParser;
  13. use PhpDevCommunity\PaperORM\Platform\PlatformInterface;
  14. use PhpDevCommunity\PaperORM\Proxy\ProxyFactory;
  15. use PhpDevCommunity\PaperORM\Repository\Repository;
  16. use Psr\EventDispatcher\EventDispatcherInterface;
  17. use Psr\EventDispatcher\ListenerProviderInterface;
  18. use Psr\Log\LoggerInterface;
  19. class EntityManager implements EntityManagerInterface
  20. {
  21. private PaperConnection $connection;
  22. private UnitOfWork $unitOfWork;
  23. /**
  24. * @var array<string, Repository>
  25. */
  26. private array $repositories = [];
  27. private EntityMemcachedCache $cache;
  28. private ListenerProviderInterface $listener;
  29. private EventDispatcherInterface $dispatcher;
  30. private ?PlatformInterface $platform = null;
  31. public static function createFromDsn(string $dsn, bool $debug = false, LoggerInterface $logger = null, array $listeners = []): self
  32. {
  33. if (empty($dsn)) {
  34. throw new \LogicException('Cannot create an EntityManager from an empty DSN.');
  35. }
  36. $params = DSNParser::parse($dsn);
  37. $params['extra']['debug'] = $debug;
  38. if ($logger !== null) {
  39. $params['extra']['logger'] = $logger;
  40. }
  41. $params['extra']['listeners'] = $listeners;
  42. return new self($params);
  43. }
  44. public function __construct(array $config = [])
  45. {
  46. if (!isset($config['driver'])) {
  47. throw new \InvalidArgumentException('Missing "driver" in EntityManager configuration.');
  48. }
  49. $this->connection = DriverManager::createConnection($config['driver'], $config);
  50. $this->unitOfWork = new UnitOfWork();
  51. $this->cache = new EntityMemcachedCache();
  52. $this->listener = (new ListenerProvider())
  53. ->addListener(PreCreateEvent::class, new CreatedAtListener())
  54. ->addListener(PreUpdateEvent::class, new UpdatedAtListener());
  55. $listeners = $config['extra']['listeners'] ?? [];
  56. foreach ((array) $listeners as $event => $listener) {
  57. foreach ((array) $listener as $l) {
  58. $this->addEventListener($event, $l);
  59. }
  60. }
  61. $this->dispatcher = new EventDispatcher($this->listener);
  62. }
  63. public function persist(object $entity): void
  64. {
  65. $this->unitOfWork->persist($entity);
  66. }
  67. public function remove(object $entity): void
  68. {
  69. $this->unitOfWork->remove($entity);
  70. }
  71. public function flush(): void
  72. {
  73. foreach ($this->unitOfWork->getEntityInsertions() as &$entity) {
  74. $repository = $this->getRepository(get_class($entity));
  75. $repository->insert($entity);
  76. $this->unitOfWork->unsetEntity($entity);
  77. }
  78. foreach ($this->unitOfWork->getEntityUpdates() as $entityToUpdate) {
  79. $repository = $this->getRepository(get_class($entityToUpdate));
  80. $repository->update($entityToUpdate);
  81. $this->unitOfWork->unsetEntity($entityToUpdate);
  82. }
  83. foreach ($this->unitOfWork->getEntityDeletions() as $entityToDelete) {
  84. $repository = $this->getRepository(get_class($entityToDelete));
  85. $repository->delete($entityToDelete);
  86. $this->unitOfWork->unsetEntity($entityToDelete);
  87. }
  88. $this->unitOfWork->clear();
  89. }
  90. public function getRepository(string $entity): Repository
  91. {
  92. $repositoryName = EntityMapper::getRepositoryName($entity);
  93. if ($repositoryName === null) {
  94. $repositoryName = 'ProxyRepository'.$entity;
  95. }
  96. $dispatcher = $this->dispatcher;
  97. if (!isset($this->repositories[$repositoryName])) {
  98. if (!class_exists($repositoryName)) {
  99. $repository = new class($entity, $this, $dispatcher) extends Repository
  100. {
  101. private string $entityName;
  102. public function __construct($entityName, EntityManager $em, EventDispatcherInterface $dispatcher = null) {
  103. $this->entityName = $entityName;
  104. parent::__construct($em, $dispatcher);
  105. }
  106. public function getEntityName(): string
  107. {
  108. return $this->entityName;
  109. }
  110. };
  111. }else {
  112. $repository = new $repositoryName($this, $dispatcher);
  113. }
  114. $this->repositories[$repositoryName] = $repository;
  115. }
  116. return $this->repositories[$repositoryName];
  117. }
  118. public function getPlatform(): PlatformInterface
  119. {
  120. if ($this->platform === null) {
  121. $driver = $this->connection->getDriver();
  122. $this->platform = $driver->createDatabasePlatform($this->getConnection());
  123. }
  124. return $this->platform;
  125. }
  126. public function getConnection(): PaperConnection
  127. {
  128. return $this->connection;
  129. }
  130. public function getCache(): EntityMemcachedCache
  131. {
  132. return $this->cache;
  133. }
  134. public function clear(): void
  135. {
  136. $this->getCache()->clear();
  137. }
  138. public function addEventListener(string $eventType, callable $callable): self
  139. {
  140. $this->listener->addListener($eventType, $callable);
  141. return $this;
  142. }
  143. }