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();
}
}