我在我的 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
功能不起作用?谢谢
可能发生的情况是带注释的侦听器比创建 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>
哦,别忘了测试!
假设您使用
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
监听器服务本身已在此处注册(如果已从配置中启用)。