如何在Symfony2中以编程方式禁用Blameable行为

时间:2014-12-22 10:29:33

标签: symfony doctrine-orm doctrine-extensions

我试图在symfony2中运行一个控制台命令,其中某个类的某些属性正在更新。其中一个属性有一个相应的reviewBy-property,它由可责行行为设置,如下所示:

/**
 * @var bool
 * @ORM\Column(name="public_cmt", type="boolean", nullable=true)
 */
private $publicCmt;

/**
 * @var User $publicCmtReviewedBy
 *
 * @Gedmo\Blameable(on="change", field="public_cmt")
 * @ORM\ManyToOne(targetEntity="My\Bundle\EntityBundle\Entity\User")
 * @ORM\JoinColumn(name="public_cmt_reviewed_by", referencedColumnName="id", nullable=true)
 */
private $publicCmtReviewedBy;

当我执行任务时,没有任何用户可以被指责为'所以我得到以下例外:

[Doctrine\ORM\ORMInvalidArgumentException]                                   
EntityManager#persist() expects parameter 1 to be an entity object, NULL given.

但是我也无法禁用责备,因为在我开始执行任务并以编程方式尝试设置用户时,它没有注册为过滤器:

// create the authentication token
        $token = new UsernamePasswordToken(
            $user,
            null,
            'main',
            $user->getRoles());
        // give it to the security context
        $this->getService('security.context')->setToken($token); 

不起作用。有人有想法吗?

3 个答案:

答案 0 :(得分:4)

如果您使用StofDoctrineExtensionsBundle,您只需执行以下操作:

$this->container->get('stof_doctrine_extensions.listener.blameable')
            ->setUserValue('task-user');

请参阅:https://github.com/stof/StofDoctrineExtensionsBundle/issues/197

答案 1 :(得分:2)

首先,我不确定' field'如果您使用数据库列或属性,则会很小心,但您可能需要将其更改为field="publicCmt"

您应该做的是覆盖Blameable Listener。我假设你正在使用StofDoctrineExtensionsBundle。在配置中首先覆盖:

# app/config/config.yml
stof_doctrine_extensions:
    class:
        blameable: MyBundle\BlameableListener

现在只需扩展现有的侦听器。你有几个选项 - 你想要允许NULL值(没有责备),或者你想拥有一个默认用户。比如说你想跳过persist并允许null,你可以覆盖:

namespace MyBundle\EventListener;

use Gedmo\Blameable\BlameableListener;

class MyBlameableListener extends BlameableListener
{
    public function getUserValue($meta, $field)
    {
        try {
            $user = parent::getUserValue($meta, $field);
        }
        catch (\Exception $e) {
            $user = null;

        return $user;
    }

    protected function updateField($object, $ea, $meta, $field)
    {
        if (!$user) {
            return;
        }

        parent::updateField($object, $ea, $meta, $field);
    }
}

因此,它首先尝试使用父getUserValue()函数来获取用户,如果不是,则返回null。我们必须输入try / catch,因为如果没有当前用户,它会抛出Exception。现在,在updateField()功能中,如果没有用户,我们就不会做任何事情。

免责声明 - 您可能仍然需要updateField()功能的一部分......我还没有对此进行过测试。

这只是一个例子。另一个想法是拥有一个默认的数据库用户。您可以使用特定用户名将其放在配置文件中。然后,如果安全令牌中没有用户,则不是返回null,而是可以从数据库中获取默认用户并使用它(当然,您也必须在服务中注入实体管理器)。

答案 2 :(得分:2)

使用相同的config.yml-entry轻微修改上述答案:我们可以检查用户是否已设置,如果没有:因为我们可以访问updateField-method中的对象管理器,获取默认用户,设置它然后执行父方法。

namespace MyBundle\EventListener;

use Gedmo\Blameable\BlameableListener;

class MyBlameableListener extends BlameableListener
{
    protected function updateField($object, $ea, $meta, $field)
    {
        // If we don't have a user, we are in a task and set a default-user
        if (null === $this->getUserValue($meta, $field)) {
            /*  @var $ur UserRepository */
            $ur       = $ea->getObjectManager()->getRepository('MyBundle:User');
            $taskUser = $ur->findOneBy(array('name' => 'task-user'));
            $this->setUserValue($taskUser);
        }
        parent::updateField($object, $ea, $meta, $field);
    }
}