Skip to content

Instantly share code, notes, and snippets.

@axelvnk
Created February 21, 2019 12:42
Show Gist options
  • Save axelvnk/492eb3c698ecc298f92b3e4eec811bea to your computer and use it in GitHub Desktop.
Save axelvnk/492eb3c698ecc298f92b3e4eec811bea to your computer and use it in GitHub Desktop.
Make classes from your bundles overridable
<?php
namespace Axelvnk\ResourceBundle\EventListener;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Axelvnk\ResourceBundle\Service\Registry;
class MappedSuperClassSubscriber implements EventSubscriber
{
/**
* @var RuntimeReflectionService
*/
private $reflectionService;
/**
* @var string[]|array
*/
private $allEntities;
/**
* @var Registry
*/
private $registry;
public function __construct(Registry $registry)
{
$this->allEntities = [];
$this->registry = $registry;
}
/**
* @return array
*/
public function getSubscribedEvents()
{
return [
Events::loadClassMetadata,
];
}
/**
* @param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$configuration = $eventArgs->getEntityManager()->getConfiguration();
$this->loadEntitiesArray($configuration);
$metadata = $eventArgs->getClassMetadata();
$this->convertToEntityIfNeeded($metadata);
if ($metadata->isMappedSuperclass) {
$this->unsetAssociationMappings($metadata);
return;
}
$this->setAssociationMappings($metadata, $configuration);
}
/**
* @param ClassMetadataInfo $metadata
*/
private function convertToEntityIfNeeded(ClassMetadataInfo $metadata)
{
if (false === $metadata->isMappedSuperclass) {
return;
}
if ($this->registry->containsResource($metadata->getName()) === false) {
return;
}
if ($this->hasSubclasses($metadata->getName())) {
return;
}
$metadata->isMappedSuperclass = false;
}
/**
* @param ClassMetadataInfo $metadata
* @param Configuration $configuration
*/
private function setAssociationMappings(ClassMetadataInfo $metadata, $configuration)
{
$classParents = class_parents($metadata->getName());
foreach ($classParents as $parent) {
if (false === $this->isEntity($parent)) {
continue;
}
$parentMetadata = new ClassMetadata($parent, $configuration->getNamingStrategy());
$parentMetadata->wakeupReflection($this->getReflectionService());
$configuration->getMetadataDriverImpl()->loadMetadataForClass($parent, $parentMetadata);
if (false === $parentMetadata->isMappedSuperclass) {
continue;
}
foreach ($parentMetadata->getAssociationMappings() as $key => $value) {
if ($this->hasRelation($value['type'])) {
$metadata->associationMappings[$key] = $value;
}
}
}
}
/**
* @param ClassMetadataInfo $metadata
*/
private function unsetAssociationMappings(ClassMetadataInfo $metadata)
{
foreach ($metadata->getAssociationMappings() as $key => $value) {
if ($this->hasRelation($value['type'])) {
unset($metadata->associationMappings[$key]);
}
}
}
/**
* @param int $type
*
* @return bool
*/
private function hasRelation($type)
{
return in_array(
$type,
[
ClassMetadataInfo::MANY_TO_MANY,
ClassMetadataInfo::ONE_TO_MANY,
ClassMetadataInfo::ONE_TO_ONE,
],
true
);
}
protected function getReflectionService()
{
if ($this->reflectionService === null) {
$this->reflectionService = new RuntimeReflectionService();
}
return $this->reflectionService;
}
/**
* @param string $mappedSuperClass
*
* @return bool
*/
private function hasSubclasses($mappedSuperClass): bool
{
foreach ($this->allEntities as $entityClass) {
if (is_subclass_of($entityClass, $mappedSuperClass)) {
return true;
}
}
return false;
}
/**
* @param string $class
*
* @return bool
*/
private function isEntity($class): bool
{
return in_array($class, $this->allEntities);
}
/**
* @param Configuration $configuration
*/
private function loadEntitiesArray(Configuration $configuration)
{
if (count($this->allEntities) === 0) {
$this->allEntities = $configuration->getMetadataDriverImpl()->getAllClassNames();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment