Add context aware enttity manager and support for multiple entity managers
parent
7efe056ba0
commit
46443a477f
@ -1,7 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "bitcommunism/doctrine",
|
"name": "bitcommunism/doctrine",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"require": {
|
"require": {
|
||||||
"doctrine/orm": "^2.6"
|
"doctrine/orm": "^2.6"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"BitCommunism\\Doctrine\\": "src/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,273 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace BitCommunism\Doctrine;
|
||||||
|
|
||||||
|
|
||||||
|
use DI\Container;
|
||||||
|
use Doctrine\ORM\Tools\Setup;
|
||||||
|
|
||||||
|
class ContextAwareEntityManager implements EntityManagerLike
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Container
|
||||||
|
*/
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DefaultEntityManager[]
|
||||||
|
*/
|
||||||
|
private $entityManagers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $entityMangerKeyCache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $entityManagerKeys = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $entityManagerPaths = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $entityManagerKeyMap = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $entityManagerPathMap = [];
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(Container $c)
|
||||||
|
{
|
||||||
|
$this->container = $c;
|
||||||
|
$connectionNames = $c->get('doctrine.connections');
|
||||||
|
|
||||||
|
foreach ($connectionNames as $connectionName) {
|
||||||
|
$this->indexConnection($connectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->finishIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function indexConnection(string $name)
|
||||||
|
{
|
||||||
|
$fullConnectionKey = 'doctrine.connection.' . $name;
|
||||||
|
$fullEntityPathKey = 'doctrine.entity-paths.' . $name;
|
||||||
|
|
||||||
|
if (!$this->container->has($fullEntityPathKey) || !$this->container->has($fullConnectionKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entityPaths = $this->container->get($fullEntityPathKey);
|
||||||
|
|
||||||
|
foreach ($entityPaths as $entityPath) {
|
||||||
|
$this->entityManagerPathMap[$entityPath] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManagerPaths = array_merge($this->entityManagerPaths, $entityPaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function finishIndex()
|
||||||
|
{
|
||||||
|
sort($this->entityManagerPaths, SORT_DESC);
|
||||||
|
sort($this->entityManagerKeys, SORT_DESC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $object
|
||||||
|
* @return DefaultEntityManager
|
||||||
|
* @throws \Doctrine\ORM\ORMException
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public function getEntityManagerForObject($object): DefaultEntityManager
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForClass(get_class($object));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $className
|
||||||
|
* @return DefaultEntityManager
|
||||||
|
* @throws \Doctrine\ORM\ORMException
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public function getEntityManagerForClass(string $className): DefaultEntityManager
|
||||||
|
{
|
||||||
|
if (!isset($this->entityMangerKeyCache)) {
|
||||||
|
$this->entityMangerKeyCache[$className] = $this->resolveEntityManagerKeyForClass($className);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getEntityManager($this->entityMangerKeyCache[$className]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $className
|
||||||
|
* @return string
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
private function resolveEntityManagerKeyForClass(string $className): string
|
||||||
|
{
|
||||||
|
if (isset($this->entityManagerKeyMap[$className])) {
|
||||||
|
return $this->entityManagerKeyMap[$className];
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflection = new \ReflectionClass($className);
|
||||||
|
$filePath = $reflection->getFileName();
|
||||||
|
|
||||||
|
foreach ($this->entityManagerPaths as $entityManagerPath) {
|
||||||
|
if (strlen($entityManagerPath) > strlen($filePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (substr($filePath, 0, strlen($entityManagerPath)) === $entityManagerPath) {
|
||||||
|
return $this->entityManagerPathMap[$entityManagerPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->entityManagerKeys as $entityManagerKey) {
|
||||||
|
if (strlen($entityManagerKey) > strlen($className)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (substr($className, 0, strlen($entityManagerKey)) === $entityManagerKey) {
|
||||||
|
return $this->entityManagerKeyMap[$entityManagerKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @return DefaultEntityManager
|
||||||
|
*/
|
||||||
|
public function getEntityManager(string $name): DefaultEntityManager
|
||||||
|
{
|
||||||
|
if (!isset($this->entityManagers[$name])) {
|
||||||
|
$this->entityManagers[$name] = $this->createEntityManager($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->entityManagers[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @return DefaultEntityManager
|
||||||
|
*/
|
||||||
|
protected function createEntityManager(string $name): DefaultEntityManager
|
||||||
|
{
|
||||||
|
if (!$this->container->has('doctrine.connection.' . $name)) {
|
||||||
|
throw new \RuntimeException("Connection '{$name}' doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = $this->container->get('doctrine.connection.' . $name);
|
||||||
|
|
||||||
|
if (!$this->container->has('doctrine.entity-paths.' . $name)) {
|
||||||
|
throw new \RuntimeException("No entity paths defined for connection '{$name}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
$paths = $this->container->get('doctrine.entity-paths.' . $name);
|
||||||
|
|
||||||
|
$config = Setup::createAnnotationMetadataConfiguration($paths, $this->container->get('doctrine.debug'));
|
||||||
|
return DefaultEntityManager::create($connection, $config, null, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $className
|
||||||
|
* @param $id
|
||||||
|
* @return null|object
|
||||||
|
* @throws \Doctrine\ORM\ORMException
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public function find($className, $id)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForClass($className)->find($className, $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function persist($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->persist($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->remove($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function merge($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->merge($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear($objectName = null)
|
||||||
|
{
|
||||||
|
// TODO: Implement clear() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detach($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->detach($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refresh($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->refresh($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush($entity = null)
|
||||||
|
{
|
||||||
|
if ($entity === null) {
|
||||||
|
return $this->getEntityManagerForObject($entity)->flush($entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->entityManagers as $entityManager) {
|
||||||
|
$entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRepository($className)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForClass($className)->getRepository($className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassMetadata($className)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForClass($className)->getClassMetadata($className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initializeObject($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->initializeObject($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function contains($object)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($object)->contains($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
foreach ($this->entityManagers as $entityManager) {
|
||||||
|
$entityManager->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copy($entity, $deep = false)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($entity)->copy($entity, $deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lock($entity, $lockMode, $lockVersion = null)
|
||||||
|
{
|
||||||
|
return $this->getEntityManagerForObject($entity)->lock($entity, $lockMode, $lockVersion);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace BitCommunism\Doctrine;
|
||||||
|
|
||||||
|
|
||||||
|
use Doctrine\Common\EventManager;
|
||||||
|
use Doctrine\DBAL\Connection;
|
||||||
|
use Doctrine\ORM\Configuration;
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use Doctrine\ORM\ORMException;
|
||||||
|
|
||||||
|
class DefaultEntityManager extends EntityManager implements EntityManagerLike
|
||||||
|
{
|
||||||
|
protected $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DefaultEntityManager constructor.
|
||||||
|
* @param string $name
|
||||||
|
* @param Connection $conn
|
||||||
|
* @param Configuration $config
|
||||||
|
* @param EventManager $eventManager
|
||||||
|
*/
|
||||||
|
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager, string $name = null)
|
||||||
|
{
|
||||||
|
parent::__construct($conn, $config, $eventManager);
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @param Configuration $connection
|
||||||
|
* @param Configuration $config
|
||||||
|
* @param EventManager|null $eventManager
|
||||||
|
* @return EntityManager|static
|
||||||
|
* @throws ORMException
|
||||||
|
*/
|
||||||
|
public static function create($connection, Configuration $config, EventManager $eventManager = null, string $name = null)
|
||||||
|
{
|
||||||
|
if (!$config->getMetadataDriverImpl()) {
|
||||||
|
throw ORMException::missingMappingDriverImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = static::createConnection($connection, $config, $eventManager);
|
||||||
|
|
||||||
|
return new static($connection, $config, $connection->getEventManager(), $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEntityManager(string $name): DefaultEntityManager
|
||||||
|
{
|
||||||
|
if ($name !== $this->name) {
|
||||||
|
throw new \RuntimeException("This DefaultEntityManager instance only has em with the name '{$name}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace BitCommunism\Doctrine;
|
||||||
|
|
||||||
|
|
||||||
|
interface EntityManagerLike
|
||||||
|
{
|
||||||
|
public function getEntityManager(string $name): DefaultEntityManager;
|
||||||
|
public function find($className, $id);
|
||||||
|
}
|
Loading…
Reference in New Issue