2013-11-18 3 views
1

Я использую DoctrineExtensions в моем проекте Symfony 2, у меня есть простой класс Entity, где я использую Sluggable для свойства, тогда я хотел бы установить значение на другое свойство на slug, но даже при использовании Lifecycle Callbacks@ORM\PrePersist, @ORM\PreFlush, в это время свойство slug все еще пустое, что означает, что slug еще не создан, вот мой класс, чтобы сохранить это короткое, я не собираюсь ставить здесь get and set функция каждого свойства, просто часть класса, которые являются важными для данного примера (пожалуйста, прочитайте комментарии)Обновление другого поля при создании пула с помощью DoctrineExtensios

<?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, снова установив значение свойства на основе пули и вызывая flush, поэтому, делая 2 запроса базы данных в одном запросе, один для вставки, один для обновления. Я не хочу использовать Event Listener, потому что это поведение просто для этого конкретного объекта или существует способ привязать прослушиватель событий к одному объекту ?.

Но сейчас я хотел бы знать:

почему то, что я пытался сделать, используя работу Lifecycle Callbacks Ждут»?
Почему использование функции setSlug не работает?
Чистый способ выполнить то, что я хочу?

благодаря

+0

Есть ли существенные причины для сохранения URL отслеживания? Если нет, вы могли бы просто «getTrackingUrl» строить URL каждый раз вместо этого. – gilden

+0

Хорошая идея, то же самое натолкнуло на мой взгляд, но меня попросили перенести отслеживаниеUrl в базу данных –

ответ

0

Что, вероятно, происходит, что аннотированные слушатели имеют более высокий приоритет, чем та, создающего слизня (или они имеют одинаковый приоритет, и в этом случае аннотированные те получают обычно добавляемые ранее).

Я боюсь, что вам нужно вырезать аннотации, создать фактический прослушиватель и пометить его для компилятора регистрации событий, чтобы забрать его. Что неприятно с этим, так это то, что пул, похоже, использует onFlush для создания пули (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

Я не хочу использовать Event Listener, потому что это поведение только для этой конкретной сущности, но теперь я начинаю думать, что у меня нет другого выбора –

+0

@ Kstro21, извинения, я, должно быть, пропустил эту часть вопроса. У вас могут быть некоторые с ретроактивным изменением приоритета 'SluggableListener'. – gilden

+0

Вы так думаете? Как я могу это сделать? извините за многие вопросы –

0

Предполагая, что вы используете StofDoctrineExtensionsBundle интегрировать библиотеку, альтернатива была бы повысить приоритет на sluggable слушателя так, что ваши аннотированные обратные вызовы будут получать вызываются после sluggable слушателя.

A compiler pass, вероятно, сделает трюк.

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 слушатель service itself зарегистрирован here, если его включен в конфигурации.

Смежные вопросы