Possible to dynamically change Doctrine Entity mappings?

时间:2016-07-11 21:47:53

标签: php doctrine-orm

I have a PSR-loaded package that defines a series of relationships around a 'User' entity it provides.

In many of the use cases where you use this package, you may want to keep all entities intact, but, substitute your own User entity.

As concrete example, the package gives me this Entity (using Annotations here to keep things clear):

namespace CirclicalUser\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * An example entity that represents an action rule.
 *
 * @ORM\Entity
 * @ORM\Table(name="acl_actions_users")
 *
 */
class UserActionRule
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="CirclicalUser\Entity\ActionRule", inversedBy="user_exceptions")
     * @ORM\JoinColumn(name="action_rule_id", referencedColumnName="id")
     */
    protected $action_rule;

    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="CirclicalUser\Entity\User")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $user;

}

Given the above, is there any way I could supplant the user relationship in UserActionRule::$user, that targets CirclicalUser\Entity\User, with my own user: Acme\Entity\User (assuming it is a Doctrine Entity in its own right)

e.g., pretend PHP:

function onBoostrap( $e ){
    DoctrineMagic::getMapping(UserActionRule::class)->get('user')->getManyToOne()->setTargetEntity(Acme\Entity\User::class);
}

Thank you!

1 个答案:

答案 0 :(得分:1)

我设法通过监听loadClassMetadata事件来解决这个问题。

namespace CirclicalUser\Listener;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\Common\EventSubscriber;

class UserEntityListener implements EventSubscriber
{
    const DEFAULT_ENTITY = 'CirclicalUser\Entity\User';

    private $userEntity;

    public function __construct($userEntity)
    {
        $this->userEntity = $userEntity;
    }

    public function getSubscribedEvents()
    {
        return ['loadClassMetadata'];
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        /** @var \Doctrine\ORM\Mapping\ClassMetadata $classMetadata */
        $classMetadata = $eventArgs->getClassMetadata();

        if ($this->userEntity == self::DEFAULT_ENTITY) {
            return;
        }

        switch ($classMetadata->getName()) {
            case 'CirclicalUser\Entity\UserActionRule':
                $classMetadata->associationMappings['user']['targetEntity'] = $this->userEntity;
                break;
        }
    }
}

此侦听器成功地将映射替换为用户定义的实体类。

添加监听器(Zend Framework)是微不足道的:

'doctrine' => [
    'eventmanager' => [
        'orm_default' => [
            'subscribers' => [
                UserEntityListener::class,
            ],
        ],
    ],

另外,在服务管理器配置中:

'service_manager' => [

    'invokables' => [
        UserAuthenticationLogMapper::class => UserAuthenticationLogMapper::class,
    ],

    'factories' => [
        UserEntityListener::class => UserEntityListenerFactory::class,
    ],

],