Symfony2: загрузка файла через Doctrine не запускает событие жизненного цикла PrePersist / PreUpdate - PullRequest
2 голосов
/ 05 сентября 2011

Я попытался осуществить загрузку файла с помощью обратных вызовов doctrine / lifecycle, как описано здесь:

http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html#using-lifecycle-callbacks

Пока это работает, но событие PrePersist / PreUpdate не запускается,Функция "preUpload" не вызывается.Такие функции, как «upload» и «removeUpload», запускаемые другими событиями жизненного цикла, вызываются правильно.

У кого-нибудь есть идея, почему событие не запускается или решение этой проблемы?

Спасибо

Ответы [ 8 ]

10 голосов
/ 22 октября 2012

У меня есть другое решение этой проблемы:

У моей сущности есть поле "updatedAt", которое является отметкой времени последнего обновления.Так как это поле в любом случае установлено (с помощью расширения Gedmo с меткой времени), я просто использую это поле, чтобы обманным путем заставить доктрину поверить в то, что права были обновлены.Прежде чем сохранить сущность, я установил это поле вручную, выполнив

if( $editForm['file']->getData() )
    $entity->setUpdateAt(new \DateTime());

. Таким образом, сущность сохраняется (потому что она изменилась), и функции preUpdate и postUpdate вызываются правильно.Конечно, это работает, только если у вашей сущности есть поле, которое вы можете использовать таким образом.

6 голосов
/ 05 сентября 2011
4 голосов
/ 24 февраля 2013

Хитрость заключается в том, чтобы изменить сущность независимо от того, что .. на postLoad.


1 Создать поле updatedAt.

/**
 * Date/Time of the update
 *
 * @var \Datetime
 * @ORM\Column(name="updated_at", type="datetime")
 */
private $updatedAt;

2 Создайте функцию postLoad(), которая в любом случае изменит вашу сущность:

/**
 * @ORM\PostLoad()
 */
public function postLoad()
{
    $this->updatedAt = new \DateTime();
}

3 Просто обновите это поле правильно в prePersist:

/**
 * @ORM\PrePersist()
 * @ORM\PreUpdate()
 */
public function preUpload()
{
    $this->updatedAt = new \DateTime();
    //...update your picture
}
4 голосов
/ 18 ноября 2012

есть гораздо более простое решение по сравнению с изменяющимися политиками отслеживания и другими решениями:

в контроллере:

if ($form->isValid()) {
    ...
    if ($form->get('file')->getData() != NULL) {//user have uploaded a new file
        $file = $form->get('file')->getData();//get 'UploadedFile' object
        $news->setPath($file->getClientOriginalName());//change field that holds file's path in db to a temporary value,i.e original file name uploaded by user
    }
    ...
}

таким образом вы изменили постоянное поле (здесь это поле пути), поэтому PreUpdate () и PostUpdate () срабатывают, тогда вам следует изменить значение поля пути на любое, что вам нравится (например, отметку времени) в функции PreUpdate () поэтому в конце правильное значение сохраняется в БД.

1 голос
/ 01 июня 2015

Это в основном небольшое изменение ответа @ philipphoffmann: Что я делаю, так это то, что я изменяю атрибут перед сохранением, чтобы вызвать событие preUpdate, затем я отменяю эту модификацию в слушателе:

$entity->setToken($entity->getToken()."_tmp");
$em->flush();

В моем слушателе:

public function preUpdate(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();

    if ($entity instanceof MyEntity) {
      $entity->setToken(str_replace('_tmp', '', $entity->getToken()));
      //...
    }
}
0 голосов
/ 03 февраля 2015

Вы проверили опцию драйвера кеша метаданных в файле config.yml?
Если он существует, просто попробуйте комментировать эту строку:

metadata_cache_driver: whateverTheStorage

Например:

#metadata_cache_driver: whateverTheStorage
0 голосов
/ 08 июня 2013

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

0 голосов
/ 25 января 2012

Другой вариант - отобразить поле базы данных, где имя файла хранится в виде скрытого поля ввода, и когда вход для загрузки файла изменится, установите его на пустое значение, чтобы в конечном итоге вызвать события обновления доктрины.Таким образом, в конструкторе форм вы можете получить что-то вроде этого:

->add('path', 'text', array('required' => false,'label' => 'Photo file name', 'attr' => array('class' => 'invisible')))
 ->add('file', 'file', array('label' => 'Photo', 'attr' => array('class' => 'uploader','data-target' => 'iddp_rorschachbundle_institutiontype_path')))

Путь - это свойство, управляемое доктриной (равное имени поля в таблице БД), а файл - это виртуальное свойство для обработки загрузки (неуправляемый доктриной).Класс css просто устанавливает отображение на none.А затем просто JS, чтобы изменить значение скрытого поля ввода

$('.uploader').change(function(){
        var t = $(this).attr('data-target');
        //clear input value
        $("#"+t).val('');
 });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...