получить автоматически сгенерированный идентификатор для дополнительного поля, используя post-persist - PullRequest
1 голос
/ 04 мая 2019

У меня есть продукт с идентификатором autogenarete, а также поле с кодом продукта, которое собирает значения на основе выбора пользователя в сочетании с автоматически сгенерированным ключом для создания кода продукта.Однако я не могу взять идентификатор автогената при вставке нового продукта.

Я использовал первые предварительные списки и предварительные версии, но это не захватывает идентификатор при вставке нового продукта.только при обновлении захватывает идентификатор

/**
 * @ORM\PrePersist
 * @ORM\PreUpdate
 */
public function setProductcode() 
{


  $option1 = $this->option1;   
  $option2 = $this->option2; 
  $id = $this->id;

  $whole = $option1.''.$option2.''.$id;    

  $this->productcode = $whole;


}

я пытаюсь использовать postpersist, и меняю свое поле на nullablae true, но он сохраняет код продукта как ноль.

/**
 * @var string
 *
 * @ORM\Column(type="string", length=191, unique=true, nullable=true)
 */
private $productcode;

Я использовал postloadи postpersist вместе, и он действительно показывает код продукта как вывод ... но он не сохраняет его в БД.

 * @ORM\PostLoad
 * @ORM\PostPersist

Как я могу получить идентификатор в сущности, чтобы поместить его в дополнительное поле?Заранее спасибо!


edit

Я сделал easyadminsubcriber, и он работает, когда я использую возвращение pre_persist.Однако приведенный ниже код обновляется до post_persist.но у меня проблемы с реализацией функции сброса вместе с lifecycleeventargs.

я получил следующую ошибку

Argument 2 passed to App\EventSubscriber\EasyAdminSubscriber::setProductcode() must be an instance of Doctrine\Common\Persistence\Event\LifecycleEventArgs, string given, called in 

ниже мой код post_persist

<?php 
# src/EventSubscriber/EasyAdminSubscriber.php
namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use App\Entity\Product;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
class EasyAdminSubscriber implements EventSubscriberInterface
{


    public static function getSubscribedEvents()
    {
        return array(
            'easy_admin.post_persist' => array('setProductcode'),
        );
    }


    /**
     * @param LifecycleEventArgs $args
     */
    public function setProductcode(GenericEvent $event, LifecycleEventArgs $args)
    {

      $entityManager = $args->getEntityManager();


        $entity = $event->getSubject();



        if (!($entity instanceof Product)) {
            return;
        }


        $whole = 'yooo'; 


        $entityManager->flush();

        $entity->setProductcode($whole);

        $event['entity'] = $entity;
    }
}

Ответы [ 3 ]

2 голосов
/ 05 мая 2019

Вам действительно нужно сохранить код продукта, если это просто объединение других столбцов? А как насчет использования эффективного добытчика?

public function getProductcode() 
{
  if(!empty($this->productcode)){
    return $this->productcode;
  }

  if(empty($this->id)){
    return "to be determined";
  }

  $this->productcode = $this->option1 . $this->option2 . $this->id;

  return $this->productcode;
}
2 голосов
/ 04 мая 2019

по умолчанию идентификатор устанавливается только тогда, когда объект сбрасывается в базу данных. это означает, что вы должны сгенерировать код продукта после того, как вы сбросили сущность, а затем сбросили снова. Доктрина не может использовать какую-то причудливую магию для определения идентификатора до того, как он действительно услышит информацию из базы данных, так что другого пути нет. (если вы хотите сделать все это в сущности, я не могу представить себе другого практичного и чистого способа сделать это)

обновление

Вы должны использовать PostPersist (сохраняя PreUpdate).

Событие postPersist наступает для объекта после того, как объект стал постоянным. Он будет вызван после операций вставки базы данных. Сгенерированные значения первичного ключа доступны в событии postPersist. ( источник )

Итак, сгенерированный первичный ключ доступен там. Однако это только после того, как вы сбросили сущность. Таким образом, вам нужно будет сбросить еще раз , чтобы записать код продукта в базу данных.

создать правильные обработчики событий (потому что "setProductcode" является установщиком, а не обработчиком событий, по крайней мере, по имени)

/**
 * PostPersist triggers after the _creation_ of entities in db
 * @ORM\PostPersist
 */
public function postPersist(LifecycleEventArgs $args) {
    $this->setProductcode();
    // need to flush, so that changes are written to database
    $args->getObjectManager()->flush();
}   

/**
 * PreUpdate triggers before changes are written to db
 * @ORM\PreUpdate
 */
public function preUpdate() {
    $this->setProductcode(); 
    // don't need to flush, this happens before the database calls
}

(см. https://www.doctrine -project.org / projects / doctrine-orm / en / latest / reference / events.html # lifecycle-callbacks-event-аргумент для получения дополнительной информации)

(отказ от ответственности: этот ответ был сильно отредактирован с момента его создания, оставив связанные комментарии частично без соответствующих ссылок)

0 голосов
/ 05 мая 2019

Хорошо, теперь у меня есть 2 решения для установки идентификатора автогенерации в другом поле (без использования контроллера).Первый из них находится непосредственно в самом файле сущностей, как показано в ответе @jakumi.

   public function setProductcode()
    {

      $part = $this->producttype->gettypenumber();
      $id1 = $this->id;
      $part = sprintf("%03d", $id1);

      $whole = $part1.''.$part2;    

      return $this->productcode= $whole;

    }


/**
 * PostPersist triggers after the _creation_ of entities in db
 * @ORM\PostPersist
 */
public function postPersist(LifecycleEventArgs $args) {


    $this->setPoductcode();
    // need to flush, so that changes are written to database
    $args->getObjectManager()->flush();
}   

/**
 * PreUpdate triggers before changes are written to db
 * @ORM\PreUpdate
 */
public function preUpdate() {


    $this->setProductcode();
    // don't need to flush, this happens before the database calls
}

Другое решение - это использовать eventsubscriber.

<?php 
# src/EventSubscriber/EasyAdminSubscriber.php
namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Product;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
class EasyAdminSubscriber implements EventSubscriberInterface
{




    public function __construct(EntityManagerInterface $em) {

        $this->em = $em;
    }



    public static function getSubscribedEvents()
    {
        return array(
            'easy_admin.post_persist' => array('setProductcode'),
        );
    }



    public function setProductcode(GenericEvent $event)
    {


        $entity = $event->getSubject();

        if (!($entity instanceof Product)) {
            return;
        }


        $this->em->flush();

        $entity->setProductcode();

        $this->em->flush();

    }
}

и мой код сущности с postpersist & preupdate

/**
 * @ORM\PostPersist
 * @ORM\PreUpdate
 */
public function setProductcode() 
{


    $part1 = $entity->getProducttype()->getTypenumber();
    $id1 = $entity->getId();
    $part2 = sprintf("%03d", $id1);
    $whole = $part1.$part2; 

  $this->productcode = $whole;


}

Спасибо @Jakumi за объяснения и рекомендации для обоих решений.

...