Symfony2: событие жизненного цикла PrePersist / PreUpdate не запущено - PullRequest
6 голосов
/ 13 марта 2012

Две сущности GalleryAlbum и GalleryImage имеют отношения OneToMany / ManyToOne:

One GalleryAlbum ==== can have ====> Many GalleryImage

Many GalleryImage === can be in ===> One GalleryAlbum

(источники ниже)

В чем проблема?

  1. Добавление (выгрузка) файлов в GalleryAlbum

  2. $ em-> сохраняются ($ альбом)

  3. $ em-> заподлицо ()

  4. Для каждого загруженного файла класс GalleryAlbum создает и добавляет к $ images новую сущность GalleryImage

  5. Мой тест ECHO / EXIT не отображается (функция обратного вызова события GalleryImage prePersist / preUpdate с именем preUpload не запускается!)

  6. Мои новые изображения не сохраняются в базе данных? Почему?

Что странно! Если я это сделаю:

  1. Добавление (загрузка) файлов

  2. $ em-> сохраняются ($ альбом)

  3. $ em-> заподлицо ()

  4. снова $ em-> flush ()

  5. Показан мой тест ECHO / EXIT (запущена функция обратного вызова события GalleryImage prePersist / preUpdate с именем preUpload!)

  6. (если я удаляю эхо / выход) Моя новая галерея Изображения теперь сохранены !!!

Почему?

Почему preUpload никогда не запускается, когда я flush () один раз, и срабатывает, когда я flush () дважды?

# src GalleryAlbum.php

    <i>/**
     * @ORM\Entity
     * @ORM\HasLifecycleCallbacks
     * @ORM\Table(name="gallery_album")
     */</i>
    class <strong>GalleryAlbum</strong>
    {
        // some properties like <em>id, name, description, etc</em>

        <i>/**
         * @ORM\OneToMany(targetEntity="GalleryImage", mappedBy="parent")
         */</i>
        protected <b>$images</b>;

        <i>/* Files container. Used for upload service. Must not be persisted. */</i>

        protected <b>$files</b>;    

        <i>/* @ORM\Column(type="boolean", nullable=TRUE)
         *
         * if set to true will updateing object and calling preUpdate event callback
         * becouse it's always set to null in database by prePersist event callback */</i>

        protected <b>$files_added</b>;

        <i>/**
         * Set container files
         * 
         * @return GalleryAlbum
         */</i>
         <b>public function</b> setFiles(<b>$files</b>)
         {
             <b>$this</b>->files = <b>$files</b>;
             <b>$this</b>->files_added = <b>true</b>;
             <i>/* setting files_added to true forces EntityManager to update 
              * this GalleryAlbum even if no other properties have changed */</i>

             return <b>$this</b>;
         }

        <i>/**
         * @ORM\PrePersist()
         * @ORM\PreUpdate()
         */</i>
        <b>public function</b> preUpload()
        {
            if(<b>null</b> !== <b>$this</b>->files) {
                foreach(<b>$this</b>->files as <b>$key</b> => <b>$file</b>) {
                  <b>$this</b>->addGalleryElement(<b>$file</b>);
                  unset(<b>$this</b>->files[<b>$key</b>]);
                }
            }
            <i>/* Resetting property files_added to NULL 
             * so it always stays null in database */</i>
            <b>$this</b>->files_added = null;
        }


        <i>/**
         * Constructing new GalleryImage and setting it's file and parent
         */</i>
        <b>public function</b> addGalleryElement(<b>$file</b>)
        {      
            <b>$element</b> = <b>new</b> GalleryImage(<b>$this</b>, <b>$file</b>);
            <b>$this</b>->addGalleryImage(<b>$element</b>);
        }
    }

# src GalleryImage.php

    <i>/**
     * @ORM\Entity
     * @ORM\HasLifecycleCallbacks
     * @ORM\Table(name="gallery_image")
     */</i>
    class <strong>GalleryImage</strong>
    {
        // some properties like <em>id, name, description, etc</em>

        <i>/**
         * @ORM\ManyToOne(targetEntity="GalleryAlbum", inversedBy="images")
         * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
         */</i>
        protected <b>$parent</b>;

        <i>/* Constructing new GalleryImage */</i> 

        <b>public function</b> __construct(<b>$parent</b> = <b>null</b>, <b>$file</b> = <b>null</b>)
        {
            if(<b>$parent</b>) <b>$this</b>->setParent(<b>$parent</b>);
            if(<b>$file</b>) <b>$this</b>->setFile(<b>$file</b>);     
        }

        <i>/**
         * @ORM\PrePersist()
         * @ORM\PreUpdate()
         */</i>
        <b>public function</b> preUpload()
        {
            <b>echo</b> 'TEST: is this event callback function fired?'; <b>exit</b>;

            if(<b>null</b> !== <b>$this</b>->file) {
                <b>$this</b>->path = <b>$this</b>->file->guessExtension();
            }

            <b>$this</b>->file_added = <b>null</b>;
        }
    }

1 Ответ

6 голосов
/ 14 марта 2012

В первый раз, когда вы вызовете постоянную доктрину, будет сохранен только $ album, а не его изображения.Вы должны указать, что вы хотите, чтобы доктрина каскадно сохранялась, указав ее в объявлении $ images:

    /**
     * @ORM\OneToMany(targetEntity="GalleryImage", mappedBy="parent", cascade={"persist", "remove"})
     */
    protected $images;

Таким образом, когда вы вызываете persist ($ album), она также сохранит ваши изображения и должна вызвать preUpload вВаш GalleryImage.Существует несколько различных вариантов каскадирования, и они хорошо объяснены здесь:

Доктрина транзитивных каскадных операций персистентности

...