I am trying to remove() the Book that contains multiple pages. When I delete the book, it is not present in database anymore while its pages aren't removed. What I would like to do is to remove a book together with pages that are bound with it.
What I tried already is the following, but the framework shows me no error.
/**
* #Route("/site/delete/{idSite}", name="delete")
*/
public function delete(Request $request, $idSite){
$liste_books=$this->getDoctrine()->getRepository(Book::class)->findOneBy(['idSite'=>$idSite]);
$liste_pages=$this->getDoctrine()->getRepository(Page::class)->findBy(['idSite'=>$idSite]);
$em = $this->getDoctrine()->getManager();
$em->remove($liste_books, $liste_pages);
$em->flush();
return $this->redirectToRoute('site');
Related
Within my database I have two related tables.
AppBooking
AppBookingService
AppBookingService has a foreign key to AppBooking
I use this method to make an insertion in both the first and second table.
public function bookingExecute($data){
try{
$this->em->beginTransaction();
$appBooking = $this->_fillAppBooking($data);
$this->em->persist($appBooking);
if(array_key_exists("appService",$data) && is_array($data['appService']) && count($data['appService']) > 0){
foreach($data['appService'] as $bookingService){
$appBookingService = $this->_fillAppBookingService($bookingService,$appBooking);
$this->em->persist($appBookingService);
$this->em->flush();
}
}
$this->em->flush();
$this->em->commit();
return $appBooking;
}catch (\Exception $ex){
$this->em->rollback();
throw new BookingException("",BookingError::BOOKING_QUERY_ERROR);
}
}
The data is written correctly
After that, in the same http request, I invoke the method below in order to have AppBooking Service data within my entity
$appBooking = $this->bookingService->findOne($id);
The problem that the AppBooking entity I get does not contain AppBookingService
The method
$appBooking->getServices()->count()
returns 0
If I make the same call in another http request I get the desired result.
It is as if doctrine did not update the entity in that same request
This is a part of AppBooking
/**
* #var Collection
* #ORM\OneToMany(targetEntity="AppBookingService", mappedBy="idBooking")
*/
private $services;
public function __construct() {
$this->services = new ArrayCollection();
}
This is part of AppBookingService
/**
* #var \Entity\Entity\AppBooking
*
* #ORM\ManyToOne(targetEntity="Entity\Entity\AppBooking", inversedBy="services")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="ID_BOOKING", referencedColumnName="ID_BOOKING", nullable=true)
* })
*/
private $idBooking;
This is because when running
$appBooking = $this->bookingService->findOne($id);
The entity is fetched from his internal proxy cache. No database query is executed to get the entity `s data. The same is true for its already loaded associations. The Proxy cache is valid during the execution of a http request.
To solve this, you either have to update the $services Collection manually or refresh the entity.
$this->em->refresh($appBooking);
Refreshes the persistent state of an entity from the database, overriding any local changes that have not yet been persisted.
You can also clear the entire entity manager cache before calling the findOne() method.
$this->em->clear();
Clears the EntityManager. All entities that are currently managed by this EntityManager become detached.
References
How do I force doctrine to reload the data from the database?
I want validate an entity doctrine differently when the entity is created, updated or deleted.
There is an entity constraint validator in my entity class.
// src/AppBundle/Entity/AcmeEntity.php
use AppBundle\Validator\Constraints as AcmeAssert;
/**
* #AcmeAssert\CustomConstraint
*/
class AcmeEntity
{
// ...
protected $name;
// ...
}
In my CustomConstraint I want determine if the Entity will be updated, created or delete for execute a specific validator.
Using unit of work is a solution ?
What is the best way to make this?
I think this problematic is common in lot of application ?
Thank's all ;)
You could either use validation groups based on the submitted data or handle itwhen you create the form by passing the validation group.
For example, in your controller when you create the form;
$form = $this->createForm(new AcmeType(), $acme, ['validation_groups' => ['create']]);
Then you entity would be something like;
/**
* Get name
*
* #Assert\Length(min=2, max=11, groups={"create", "update"})
* #AcmeAssert\ContainsAlphanumeric(groups={"create"}) // only applied when create group is passed
* #return string
*/
public function getName()
{
return $this->name;
}
This is what validation groups are made for.
Since Symfony Forms read validations from entity annotations and use internally the Validator component you'd have a look at these articles in the documentation:
http://symfony.com/doc/current/form/validation_groups.html
http://symfony.com/doc/current/validation/groups.html
http://symfony.com/doc/current/validation/sequence_provider.html
I have been wondering why my mappings and the controller actions are not working. For this I need to refer to my previous post, where I have described my entities and database schema, which can be found here. I need to start a new post since there were no further updates and I thought this the only way to get attention of the Doctrine + Zend Pros.
As described in my previous post, I have a Zend Form, the user can enter teamId and teamName, further he has the choice to select multiple players from the drop down list on the form and can allocate players to the team. So basically that is my goal to achieve with Doctrine and Zend. For that I wrote my entities described in the previous post and right now I want to add the code from my controller to persist the entities.
Controller:
public function addAction()
{
$form = new TeamForm($this->getEntityManager());
$form->get('submit')->setAttribute('value', 'Add');
$request = $this->getRequest();
if ($request->isPost())
{
$team = new Team();
$player = new Player();
$teamPlayers = new TeamPlayer();
$form->setInputFilter($typeset->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid())
{
$team->populate($form->getData());
$teamPlayers->setPlayer($player);
$teamPlayers->setTeam($team);
$this->getEntityManager()->persist($teamPlayers);
$this->getEntityManager()->flush();
//Reroute to the index page once the data is successfully added
}
}
//return form array
return array(
'form' => $form
);
}
So that is basically what Im doing in my controller to save the entities into two tables (team Table and teamPlayer Table), as already the player Table is populated with data. So I want to add players to the team and assign that values in these two tables.
Right now I can see my form and when I enter the data and press submit nothing is happening, i can see the form with no action. When the data is successfully saved into the database then I reroute it to the index page which is not happening.
Any help would be appreciated, to point out the error Im making either in mapping section or in the controller side.
The official documentation especially from Doctrine 2 is too global and is particulary not that clear for my requirement.
let's try to solve it by updating this answer by steps :
step 1 :
your words implied to me that , you might have some issues in from validation , so lets check if you are passing this $form->isValid()
if ($form->isValid())
{
$team->populate($form->getData());
$teamPlayers->setPlayer($player);
$teamPlayers->setTeam($team);
$this->getEntityManager()->persist($teamPlayers);
$this->getEntityManager()->flush();
//Reroute to the index page once the data is successfully added
}else{
var_dump($form->getMessages());
}
I can also suggest you to use doctrine commandline : doctrine orm:validate-schema , this command will help you to check if your entity mapping is ok plus your database mapping is also okay , i see it as handy to to debug your doctrine2 entity
ps : I havn't read your entities in depth yet
I have an Entity called Game with a related Repository called GameRepository:
/**
* #ORM\Entity(repositoryClass="...\GameRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Game {
/**
* #ORM\prePersist
*/
public function setSlugValue() {
$this->slug = $repo->createUniqueSlugForGame();
}
}
In the prePersist method, I need to ensure that the Game's slug field is unique, which requires a database query. To do the query, I need access to the EntityManager. I can get the EntityManager from inside GameRepository. So: how do I get the GameRespository from a Game?
You actually can get the repository in your entity and only during a lifecycle callback. You are very close to it, all you have to do is to receive the LifecycleEventArgs parameter.
Also see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
use Doctrine\ORM\Event\LifecycleEventArgs;
/**
* #ORM\Entity(repositoryClass="...\GameRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Game {
/**
* #ORM\prePersist
*/
public function setSlugValue( LifecycleEventArgs $event ) {
$entityManager = $event->getEntityManager();
$repository = $entityManager->getRepository( get_class($this) );
$this->slug = $repository->createUniqueSlugForGame();
}
}
PS. I know this is an old question, but I answered it to help any future googlers.
You don't. Entities in Doctrine 2 are supposed to not know of the entity manager or the repository.
A typical solution to the case you present would be to add a method to the repository (or a service class) which is used to create (or called to store) new instances, and also produces a unique slug value.
you can inject the doctrine entity manager in your entity
(using JMSDiExtraBundle)
and have the repository like this:
/**
* #InjectParams({
* "em" = #Inject("doctrine.orm.entity_manager")
* })
*/
public function setInitialStatus(\Doctrine\ORM\EntityManager $em) {
$obj = $em->getRepository('AcmeSampleBundle:User')->functionInRepository();
//...
}
see this : http://jmsyst.com/bundles/JMSDiExtraBundle/1.1/annotations
In order to keep the logic encapsulated without having to change the way you save the entity, instead of the simple prePersist lifecycle event you will need to look at using the more powerful Doctrine events which can get access to more than just the entity itself.
You should probably look at the DoctrineSluggableBundle or StofDoctrineExtensionsBundle bundles which might do just what you need.
I've set up a self-referencing entity per the manual here:
http://www.google.com/url?sa=D&q=http://www.doctrine-project.org/docs/orm/2.0/en/reference/association-mapping.html%23one-to-many-self-referencing
My class is Page (instead of Category, like in the docs). In my entity
class I have a toArray() method that I've implemented that will give
me back the values of my member variables. For those fields that are
associations, I've made sure to grab the associated class object then
grab the id. I'm doing this to populate a form. Here is the code from
my toArray() method in my Page entity as well as my PageService
function to grab a Page object and my Page Controller code that calls
toArray() to populate my form.
http://pastie.org/1686419
As I say in the code comments, when the toArray() method is called in
the Page Controller, all values get populated except for parent id.
page_type is also a ManyToOne association and it gets populated no
problem. Explicitly grabbing the parent id from the Page object
outside of the toArray() method (in the Page Controller) does return
the parent id value. (See code.)
As a side note, I'm using __get() and __set() in my Page entity instead of full blown getters/setters.
I think it is because you are getting caught out by proxies. When you have an association in Doctrine 2, the related objects are not returned directly as objects, but as subclasses which do not fill their properties until a method is called (because of lazy loading to save database queries).
Since you are calling the property directly (with $this->parent->id) without invoking any method the object properties are all empty.
This page http://www.doctrine-project.org/docs/orm/2.0/en/tutorials/getting-started-xml-edition.html#a-first-prototype has a warning about this type of thing in the warning box. Although yours isn't a public property, you are accessing as though it were because that object is of the same class and the same problem is occuring.
Not sure of exactly what is causing your described behavior, but you're probably better anyway to have your toArray() method call getters/setters rather than having toArray() operate directly on the class properties. This will give you consistency so that if you implement custom getters for certain properties, you'll always get back the same result from toArray() and the getter.
A rough example:
<?php
/** #Entity */
class MyEntity {
// ....
/** #Column */
protected $foo;
public function setFoo($val)
{
$this->foo = $val;
}
public function getFoo()
{
return 'hello ' . $this->foo;
}
public function toArray()
{
$fields = array('foo');
$values = array();
foreach($fields as $field) {
$method = 'get' . ucfirst($field);
if (is_callable(array($this, $method)) {
$fields[$field] = $this->$method();
} else {
$fields[$field] = $this->$field;
}
}
return $fields;
}
}
Now you get the same result:
<?php
$e = new MyEntity;
$e->setFoo('world');
$e->getFoo(); // returns 'hello world'
$e->toArray(); // returns array('foo' => 'hello world')