Symfony2 - Doctrine - Есть ли способ сохранить объект в одной строке?

Чтобы сохранить объект с доктриной, я должен сделать это

$em = $this->getDoctrine()->getEntityManager();
$em->persist($product);
$em->flush();

Но, может быть, я могу как-то сделать это в одной строке, например

$product->save();

или

$this->saveEntity($product);

или

$this->getDoctrineEntityManager()->persistAndFlush($product);

Если мне нужно создать эти методы самостоятельно, то как это сделать с помощью symfony?

Ответ 1

Ну persist() и flush() - совершенно разные и независимые операции. Когда вы сохраняете объект сущности, вы говорите диспетчеру объекта отслеживать изменения объекта. Когда вы вызываете метод flush(), диспетчер сущностей будет вызывать изменения объектов сущности, которые диспетчер объектов отслеживает в базе данных в одной транзакции. Большую часть времени менеджер объектов должен управлять несколькими объектами. Например, помимо вашего объекта product вы также можете отслеживать объект tag или cart. Вызов persistAndFlush() каждый раз, когда вы сохраняете объект сущности, вы будете вызывать множественное подключение ввода-вывода к БД. Это неэффективно. Поэтому я считаю, что лучше рассматривать их как отдельную операцию.

Ответ 2

Если вы используете контроллер в комплекте с инфраструктурой и записываете свою логику персистентности в своих контроллерах, вы можете расширить Symfony\Bundle\FrameworkBundle\Controller\Controller со следующими

namespace ExampleNameSpace\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BaseController extends Controller
{
    public function persistAndSave($entity)
    {
        $em = $this->getDoctrine()->getEntityManager();
        $em->persist($entity);
        $em->flush();
    }
}

Во всех ваших других контроллерах вы затем расширяете свой ExampleNameSpace\Controller\BaseController вместо одного из Symfony Frameworkbundle.

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

<?php

abstract class AbstractManager
{
    /**
     * The Entity Manager
     *
     * @var \Doctrine\ORM\EntityManager  The Doctrine Entity Manager
     */
    protected $em;

    /**
     * The full class path associated with the repository
     *
     * @var string
     */
    protected $class;

    /**
     * The repository for the manager
     *
     * @var \Doctrine\ORM\EntityRepository
     */
    protected $repository;

    /**
     * Creates a new instance of the primary class managed by a given
     * manager
     *
     * @return object       A new instance of the entity being managed
     */
    public function create()
    {
        return new $this->class();
    }

    /**
     * {@inheritDoc}
     */
    public function save($object, $flush = false)
    {
        if( ! $this->supportsClass($object))
        {
            throw new \InvalidArgumentException(sprintf('Invalid entity passed to this manager, expected instance of %s', $this->class));
        }

        $this->em->persist($object);

        if($flush === true)
        {
            $this->flush();
        }

        return $object;
    }

    /**
     * {@inheritDoc}
     */
    public function delete($object, $flush = false)
    {
        if( ! $this->supportsClass($object))
        {
            throw new \InvalidArgumentException(sprintf('Invalid entity passed to this manager, expected instance of %s', $this->class));
        }

        $this->em->remove($object);

        if($flush === true)
        {
            $this->flush();
        }

        return true;
    }

    /**
     * Convenience method providing access to the entity manager flush method
     */
    public function flush()
    {
        $this->em->flush();
    }

    /**
     * {@inheritDoc}
     */
    public function supportsClass($object)
    {
        return $object instanceof $this->class || is_subclass_of($object, $this->class);
    }

    /**
     * Set class. Setter for dependency injection
     *
     * @param object $class  A class related to this manager
     */
    public function setClass($class)
    {
        $this->class = $class;
    }

    /**
     * Set entity manager. Setter for dependency injection
     *
     * @param \Doctrine\ORM\EntityManager $entity_manager
     */
    public function setEntityManager(\Doctrine\ORM\EntityManager $entity_manager)
    {
        $this->em = $entity_manager;
    }

    /**
     * Returns the repository
     *
     * @return \Doctrine\ORM\EntityRepository    A Doctrine Repository for the
     *                                          class related to this Manager
     */
    protected function getRepository()
    {
        if( ! $this->repository)
        {
            $this->repository = $this->em->getRepository($this->class);
        }

        return $this->repository;
    }
}

Менеджеры настроены в контейнере инъекций зависимостей с соответствующим классом для сущности и предоставляют доступ к созданию, сохранению и удалению сущности, за которую они отвечают, а также к доступу к репозиторию.

Можно создать объект в контроллере с менеджером следующим образом:

public function createAction(Request $request)
{
    $entityManager = $this->get('some.entity.manager');

    $entity = $entityManager->create();

    $form = $this->createForm(new EntityForm(), $entity);

    $form->bindRequest($request);

    if($form->isValid())
    {
        $entityManager->save($entity, true);
    }
}

Ответ 3

Я знаю ваше желание. В первый раз выглядит один метод сохранения.

Но если у вас есть 2 метода, вы можете собрать инструкции перед отправкой их в базу данных. Это не фактическая работа доктрины, я думаю, но, возможно, с обновлением вы можете использовать флеш ( "вместе" ). Таким образом вы можете сэкономить много накладных расходов.

Ответ 4

Основываясь на этом посте (написано об этом в самом конце), вы можете написать код сохранения в хранилище:

class DoctrineORMCustomerRepository extends EntityRepository implements CustomerRepository
{
    public function save(Customer $customer)
    {
        $this->_em->persist($customer);
        $this->_em->flush();
    }
}