使用 DoctrineExtensios 更新 slug 创建的另一个字段

问题描述 投票:0回答:2

我在我的 Symfony 2 项目中使用 DoctrineExtensions,我有一个简单的实体类,我在属性上使用 Sluggable,然后我想根据 slug 将值设置为另一个属性,但是,即使当使用

Lifecycle Callbacks
@ORM\PrePersist
@ORM\PreFlush
,此时 slug 属性仍然为空,意味着还没有生成 slug,这是我的类,为了简短起见,我不打算将
get and set
放在这里每个属性的功能,只是该示例中重要的类的一部分(请阅读评论)

<?php

namespace My\LearnBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * Banner
 *
 * @ORM\Table(name="banner")
 * @ORM\HasLifecycleCallbacks()
 */
class Banner {

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=128, nullable=false)
     * @Assert\NotBlank()
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="slug", type="string", length=256, nullable=false)
     * @Gedmo\Slug(fields={"name"})
     */
    private $slug;

    /**
     * @var string
     *
     * @ORM\Column(name="tracking_url", type="string", length=256, nullable=false)
     */
    private $trackingUrl;

    
    /**
     * Set slug
     *
     * @param string $slug
     * @return Banner
     */
    public function setSlug($slug) {
        $this->slug = $slug;
        $this->trackingUrl = $slug."/tracking"; //Doesn't work
        return $this;
    }

    /**
     * Set trackingUrl value
     * 
     * @ORM\PreUpdate
     */
    public function setTrackingUrlValue() {
        //the slug is empty. Doesn't work
        $this->trackingUrl = $this->slug."/tracking";
        return $this;
    }

    /**
     * Set trackingUrl value
     * 
     * @ORM\PreFlush
     */
    public function setTrackingUrlValueOnFlush() {
        //the slug is empty. Doesn't work
        return $this->setTrackingUrlValue();
    }

}

我尝试过什么?好吧,使用

setSlug
函数但它不起作用(注意上面示例的注释),似乎没有调用它。使用
Lifecycle Callbacks
@ORM\PrePersist
@ORM\PreFlush
@ORM\PreUpdate
也不起作用。
现在我在控制器中解决了这个问题,在
flush
上调用
EntityManager
之后,根据 slug 设置属性值并再次调用
flush
,因此,在单个请求中进行 2 个数据库查询,一个用于插入,一个用于插入用于更新。我不想使用
Event Listener
,因为此行为仅适用于该特定实体,或者是否存在将事件侦听器附加到单个实体的方法?.

但是现在,我想知道:

为什么我尝试使用

Lifecycle Callbacks
所做的事情不起作用?
为什么使用
setSlug
功能不起作用?
一种更干净的方式来完成我想要的事情?

谢谢

php symfony orm doctrine-orm
2个回答
1
投票

可能发生的情况是带注释的侦听器比创建 slug 的侦听器具有更高的优先级(或者它们具有相同的优先级,在这种情况下带注释的侦听器可能会在之前添加)。

恐怕您必须放弃注释,创建一个实际的侦听器并为事件注册编译器传递标记它才能拾取它。这个包的令人讨厌之处在于该包似乎使用

onFlush
来创建 slug(code)。

听众

namespace Acme\DemoBundle\Listener;

use Acme\DemoBundle\Model\TrackingUrlUpdateable;
use Doctrine\ORM\Event\OnFlushEventArgs;

class TrackingUrlUpdater
{
    public function onFlush(OnFlushEventArgs $eventArgs)
    {
        $em  = $eventArgs->getEntityManager();
        $uof = $em->getUnitOfWork();

        // Let's process both types of entities in a single loop.
        $entities = array_merge(
            $uof->getScheduledEntityInsertions(),
            $uof->getScheduledEntityUpdates()
        );

        foreach ($entities as $entity) {
            // Using a fictional interface (e.g. for making testing easier).
            if (!($entity instanceof TrackingUrlUpdateable)) {
                 continue;
            }

            // `Banner::updateTrackingUrl()` would internally change the
            // tracking url to the correct one.
            $entity->updateTrackingUrl();

            // The change-set must be recomputed as its fields were modified
            // in the previous step.
            $uof->recomputeSingleEntityChangeSet(
                $em->getClassMetadata(get_class($entity)),
                $entity
            );
        }
    }
}

报名

现在剩下的就是以比 Sluggable 侦听器

更低
优先级注册侦听器。

<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:doctrine="http://symfony.com/schema/dic/doctrine">

    <services>
        <service id="acme.listener.tracking_url" class="Acme\DemoBundle\Listener\TrackingUrlUpdater">
            <tag name="doctrine.event_listener" event="onFlush" priority="-1" />
        </service>
    </services>
</container>

哦,别忘了测试!


0
投票

假设您使用

StofDoctrineExtensionsBundle
来集成库,另一种方法是提高
sluggable
侦听器的优先级,以便在
sluggable
侦听器之后调用带注释的回调。

一个编译器通行证可能会成功。

namespace Acme\DemoBundle\DependencyInjection\CompilerPass;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class SluggableListenerPriorityChangingPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $id  = 'stof_doctrine_extensions.listener.sluggable';
        $tag = 'doctrine.event_subscriber';

        $definition = $container->getDefintion($id);
        $attributes = $definition->getTag($tag);

        if (!$attributes) {
            throw new \LogicException("The listener (`$id`) must have a `$tag` tag.");
        }

        $attributes['priority'] = 10;

        $definition
            ->clearTag($tag);
            ->addTag($tag, $attributes)
        ;
    }
}

sluggable
监听器服务本身已在此处注册(如果已从配置中启用)。

© www.soinside.com 2019 - 2024. All rights reserved.