What's the purpose of persisting entities? - symfony

I have read the documentation many times at http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html but I still don't get it.
What's the purpose of persiting entities?
I have the following code
$em = $this->getDoctrine()->getManager();
$user = $this->container->get('security.context')->getToken()->getUser();
if ($user) {
$user->enabled(1);
$em->flush();
}
It works very well.
Why should I add the
$em->persist($user);
before the flush ?

persisting an entity just means that the entity manager can manage the entity. otherwise it doesn't know about it.
EDIT: if you are working with an entity that has been pulled from the entity manager to begin with (in your case, $user), then persisting is not required because the entity manager already "knows" about it. So persisting is only required when creating a NEW instance.
An entity can be made persistent by passing it to the EntityManager#persist($entity) method. By applying the persist operation on some entity, that entity becomes MANAGED, which means that its persistence is from now on managed by an EntityManager. As a result the persistent state of such an entity will subsequently be properly synchronized with the database when EntityManager#flush() is invoked.
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#persisting-entities

Related

Test symfony doctrine UnitOfWork error only during tests

I have a problem during testing a symfony App with phpunit.
I created a service and it works well but when I execute the service in my tests doctrine throw me an exception
A new entity was found through the relationship 'PointOfSale#country' that was not configured to cascade persist operations for entity
In my service I do this:
$pointOfSale->setCountry($this->getCountry($name));
private function getCountry(string $name): Country
{
$country = $this->entityManager->getRepository(Country::class)->findOneBy(['alpha3Code' => $name]);
return $country;
}
I don't understand why this entity is not managed by UnitOfWorks. Indeed when I do the following code I have an exception only during test
$country = $this->entityManager->getRepository(Country::class)->findOneBy(['alpha3Code' => $name]);
$this->entityManager->refresh($country);
[ERROR] Entity Namespace\Country#000000001bfea0ed00000000602457d6 is not managed. An entity is
managed if its fetched from the database or registered as new through EntityManager#persist
How can I fix this ?
Solution was discuss here:
https://github.com/doctrine/DoctrineBundle/issues/1112#event-3005473120
[doctrine changelog note] (https://github.com/doctrine/DoctrineBundle/blob/1.12.x/UPGRADE-1.12.md#unitofwork-cleared-between-each-request)
While troubleshooting the same problem with PhpUnit Testing producing "A new entity was found through the relationship" errors I realized I was actually getting different Entity Manager instances thanks to this question. What I did was move the self::bootKernel() from my __construct function to a new "startUp" function that I run at beginning of each test function and then I started getting the correct Entity Manager each time instead of a different one each test.
I may be missing something, but now my tests pass and produce the same results as my actual program.

Symfony - Database connection with a Repository

I'm refactoring the code in one of my Controller to put it in a service.
In the Controller the entity manager is targeting a db connection called legacy.
The problem is, I did not injected the Entity Manager in my service but just the OrderRepository.
How can I target the good db connection with the repository in my service without the Entity Manager?
OrderController
// In my Controller
$em = $this->getDoctrine()->getManager('legacy');
$em->persist($order);
$em->flush();
OrderService
// In my Service
public function __construct(OrderRepository $orderRepository)
{
$this->orderRepository = $orderRepository;
}
public function updateOrderStatus(Order $order)
{
// some code ...
$this->orderRepository->save($order);
}
Based on some comments it would appear that the basic issue is having multiple entity managers. Nowadays there is a great deal of automated functionality which works well for one entity manager but no so much for multiple managers.
You basically need to define your services manually.
# services.yaml
# assume we have
# doctrine.orm.default_entity_manager and
# doctrine.orm.legacy_entity_manager
# already defined through configuration
# define legacy repository
order_repository.legacy:
class: Whatever\Repository\OrderRepository
factory: ['doctrine.orm.legacy_entity_manager', 'getRepository']
arguments:
- 'Whatever\Entity\Order'
# define default repository
order_repository.default:
class: Whatever\Repository\OrderRepository
factory: ['doctrine.orm.default_entity_manager', 'getRepository']
arguments:
- 'Whatever\Entity\Order'
# then your service
Whatever\Service\MyService:
'#order_repository.legacy'
And you should be good to go. Note that your repository needs to extend EntityRepository and not the doctrine bundle's ServiceEntityRepository.
And if you feel this is too much work then just inject the doctrine bundle's entity manager registry and do what the ControllerTrait::getDoctrine($name) does.
You must forgot that you can always get the entity manager inside your repository just like this:
$em = $this->getEntityManager();
then you can use it normally calling persist, flush etc.
Note that the Repository class itself is agnostic to functionalities of the database access layer like insert or update so it should call entity manager to execute them.

Symfony2 allow a FOS user to only update entities they have a relation to

I want to limit my user account to only view and modify entities it has a relationship with.
I've got a basic FOS User setup, and I have a entity with a one to many relationship with my user entity.
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="blog")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user_id;
The schema validates properly, and doctrine seems happy with my relationship.
I've used the app/console generate:doctrine:crud command to generate a basic crud system.
How should I limit doctrine from returning entities that don't have a relationship with the logged in user?
This is the code I'm currently using to get all entities.
$entities = $em->getRepository('ExampleBundle:Blog')->findAll();
Is there a pre-built command for fetching by user id, or do I need to write some DQL?
You can use the findBy method with the current logged in user.
$user = $this->get('security.context')->getToken()->getUser();
$entities = $em->getRepository('ExampleBundle:Blog')->findBy(array('user' => $user));
And in your Blog entity, it's not a user_id but a user, you want to get the user not the id. $blog->getUser();
Hope it's helpful.
Best regard.

How to get entity manager for Doctrine entity with Symfony 2.1 from inside controller

How can I get an entity manager from inside a controller with latest Symfony and Doctrine?
The way described in "The Book" flagged as deprecated now. What is a modern (proper) way to do this?
public function someAction()
{
// getEntityManager() from Doctrine\Bundle\DoctrineBundle\Registry is deprecated
$entityManager = $this->getDoctrine()->getEntityManager();
...
}
Use $this->getDoctrine()->getManager() instead.
Actually, it's best not to make controllers aware of the persistence layer you're using. That stuff should be moved to the Service Layer to abstract the way the data is persisted.

How to persist/flush doctrine2 entities with OneToMany // ManyToOne relations?

I am trying to persist/flush my doctrine2 entities, but I am gettig an error every time:
Entity of type Test\Main\MainBundle\Entity\ProductVariantAssociation has identity
through a foreign entity Test\Main\MainBundle\Entity\Product, however this entity has
no ientity itself. You have to call EntityManager#persist() on the related entity and make
sure it an identifier was generated before trying to persist
'Test\Main\MainBundle\Entity\ProductVariantAssociation'. In case of Post Insert ID
Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call
EntityManager#flush() between both persist operations.
I posted my ArticleController at pastebin:
http://pastebin.com/iN0BpGFc
Does anybody know, how to solve that problem?

Resources