I have a createAction for a Symfony request.
How can I add some values in another entity, by creating a new Entity value.
See the following foreach part; whats wrong with it?
public function createAction(Request $request)
{
$entity = new FooType();
$form = $this->createForm(new FooTypeType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
$entities = $em->getRepository('OtherBundle:Lists')->findAll();
foreach($entities as $list){
$manager = $this->getDoctrine()->getManager();
$listValue = new ListValue();
$listValue->setSpecification( new ListsType(), $list );
$manager->persist($listValue);
$manager->flush();
}
return $this->redirect($this->generateUrl('foo_foobar_show', array('id' => $entity->getId())));
}
if you have a proper association mapping between your entities and use Doctrine's persist option for the cascade operation you won't have to persist your related entities explicitly.
You can in this case ommit
$manager->persist($listValue);
Furthermore for performance reasons make sure you flush your entityManager only once - you don't need to flush more than once often except in case you need the auto-generated ID of a newly persisted entity!
create a new method in your repository ( addListsToEntity() ) or in a manager class for adding your lists!
Related
Welcome,
I created a few projects in sf2 (2.4-2.8). The code was different quality...
I read few articles. Now I try to minimize the code in the controller. I use Repository, Services etc. When I use with the services, don't injects doctrine, forwards object. In the controller initializes forms, objects, services, check validation forms and returns values to template. But I have functionalities which I must generate query in the loop or I need many query, which can not be combined into one.
My structure folder: Controller, Services, Repository, Entity, Form, Resources.
How can I reconcile all this? Minimum controller, functionalities in the services and Repository to Entity.
Example ugly code controller:
/**
* #Route("/add", name="controller_admin_page_add")
* #Template()
* #param Request $request
*/
public function addAction(Request $request) {
$page = new Page;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new FormPage, $page);
$form->handleRequest($request);
if ($request->isMethod("POST") && $form->isValid()) {
$links = $em->createQuery("...")->getResult();
foreach($link as links){
if(...){
$checkLink = $em->createQuery("...")->getResult();
...
}
.....
}
$em->persist($page);
$em->flush();
return $this->redirectToRoute('controller_admin_page_index');
}
return array(
'form' => $form->createView()
);
}
Example nicer code:
/** ...
*/
public function addAction(Request $request) {
$page = new Page;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new FormPage, $page);
$form->handleRequest($request);
if ($request->isMethod("POST") && $form->isValid()) {
$generateUrl = $this->container->get('Url');
$generateUrl->checkLink($page);
$generateUrl->getUrl();
$em->persist($page);
$em->flush();
return $this->redirectToRoute('controller_admin_page_index');
}
return array(
'form' => $form->createView()
);
}
Here is problem.
The functionality takes over Services. In the "clean architecture", I should pass an object/objects to the Services. But I must send query in loop.
In my opinion I need 2 types classes helper in project.
1). Gets the object /objects by setters and returns the processed data. Class doesn't have access to the doctrine.
2) Gets arguments, created query and returns the processed data. Class have access to the doctrine.
In the project I have Repository, they only return the objects.
I have a problem with the class name, directory name, and using it.
Can someone please help?
Trying to update my entity, unfortunately didnt use Doctrines generate CRUD feature (have to change stuff I didnt write).
I am finally getting data into my form, but it just won't save the changes (also, it doesn't create a new entity as one might suspect).
When I click 'save', I always return to the page where I have my form to edit the entity.
Checked if method is POST, it is.
if ($form->get('save')->isClicked()) {
doesn't seem to do anything, how can that be?
Here's the rest of my action:
/**
* Updates.
*
* #Route("/offerweekchange/{offerid}", name="offerweekchange")
* #Template("")
*/
public function offerweekchangeAction(Request $request, $offerid)
{
$request = $this->get('request');
if ($offerid) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AlexanderBuerkleShopBundle:Promotion')->findOneBy(array('id' => $offerid));
$form = $this->createForm(new OfferWeekChangeType(), $entity);
# \Doctrine\Common\Util\Debug::dump($request->getMethod());
if ($form->get('save')->isClicked()) {
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('offerweeklist'));
}
}
}
return $this->render('AlexanderBuerkleShopBundle:OfferWeekList:offerweekchange.html.twig',
array('form' => $form->createView(), 'offerid' => $offerid, 'entity' => $entity));
}
}
Any help would be greatly appreciated.
First, here is a working sample of your code:
public function offerweekchangeAction(Request $request, $offerid)
{
if ($offerid) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AlexanderBuerkleShopBundle:Promotion')->findOneBy(array('id' => $offerid));
$form = $this->createForm(new OfferWeekChangeType(), $entity);
$form->handleRequest($request);
# \Doctrine\Common\Util\Debug::dump($request->getMethod());
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('offerweeklist'));
}
return $this->render('AlexanderBuerkleShopBundle:OfferWeekList:offerweekchange.html.twig',
array('form' => $form->createView(), 'offerid' => $offerid, 'entity' => $entity));
}
}
Secondly, you have several mistakes here, so let's analyse them one by one:
1:
if ($offerid) {
your code does nothing on the else branch.
2:
$request = $this->get('request');
you already have the request parameter injected into the action. This line is redundant.
3:
$form->bind($request);
This is deprecated since 2.3. Use $form->handleRequest($request) instead.
4:
$em->flush();
You are flushing the entity manager, but nothing is persisted, so nothing will happen. you have to persist the entity first with $em->persist($entity)
5:
if ($request->getMethod() == 'POST') {
The method $form->isValid() checks for this also, so checking for post is redundant.
That's it. Hope it helped.
The most likely issue here is with the AbstractType which define your form OfferWeekChangeType).
In order to map the form data on the entity you need to set the 'data_class'.
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => ' Acme\StoreBundle\Entity\Product',
)
);
}
then inside your controller you need to invoke :
$form->handleRequest($request);
This will bind the request to your form.
Only when you invoke:
$form->isValid()
The data from the form (if valid) will be mapped on the entity.
$em->persist($entity);
in this case is superflus because Doctrine UnityOfWork already 'knows' the entity from when you got it from the repository. Just invoke
$em->flush($entity);
As a side note remember that flushing only the needed entity is preferable (when possible) the flush the entire UnityOfWork in order to avoid unexpected behaviours.
Regards.
I want update row setting new values from array, now Iset one by one aribute:
$em = $this->getDoctrine()->getManager();
$company = $em->getRepository('CatalogWebBundle:ComCompany')
->findOneBy(
array('cmpCode' => $id)
);
$company->setCmpName($_POST['name']);
$company->setCmpCode($_POST['code']);
$em->flush();
Maybe exist solution to set all atributes from array, some like this ?
$company = $_POST;
Consider using Symfony Form and use like this:
<?php
$request = $this->getRequest(); // or inject Request to the action method like myAction(Request $request)
$em = $this->getDoctrine()->getManager();
$company = $em->getRepository('CatalogWebBundle:ComCompany')
->findOneBy(
array('cmpCode' => $id)
);
$form = $this->createForm('formName', $company);
$form->handleRequest($request);
if($form->isValid()) {
// if you want, you can get entity here,
// but passing an entity in 2nd param of createForm
// provides automatic binding data
$data = $form->getData();
$em->flush();
// do some action after submitting form...
return $this->redirect($this->generateUrl('companies'));
}
Read more about creating forms:
http://symfony.com/doc/current/book/forms.html
And about regitering forms as services for futher use named form in createForm('NAME_HERE', $bindObjectHere):
http://symfony.com/doc/current/book/forms.html#defining-your-forms-as-services
I have some entities with abstract class : EntityDated wich mean that the entity contain 4 commons fields : created, updated, created_by and updated_by.
I want update the 4 data when I create entity and update 'updated' and 'updated_by' when I update the entity.
I made a service calling my listener :
public function preUpdate(PreUpdateEventArgs $eventArgs)
{
$token = $this->container->get('security.context')->getToken();
$entity = $eventArgs->getEntity();
$em = $eventArgs->getEntityManager();
$uow = $em->getUnitOfWork();
if (is_subclass_of($entity, 'Kiwi\Bundle\TrainingBundle\Entity\EntityDated')) {
$entity->setUpdated(new \Datetime());
$entity->setUpdatedBy($token->getUser()->getUsername());
$meta = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($meta, $entity);
}
}
This works perfectly with simple entities with no entities linked BUT as soon as i try to add an entity linked (for instance I add one entity "Response" to the array of $responses of my entity "Question") I have the following error :
Notice: Undefined index: 0000000060e7f05700000000e7f2194b in C:\wamp\www\kiwi\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php line 1359
The problem is that the linked entity is persisted not by a direct call of $em->persist() but by the behaviour : cascade="persist" and as the Doc says about recomputeSingleEntityChangeSet() :
The passed entity must be a managed entity. If the entity already has a change set because this method is invoked during a commit cycle then the change sets are added. whereby changes detected in this method prevail.
So obviously the problem here is that my entity linked is not managed. How could I add it to the UnitOfWork or something in order to manage it ?
In order to perform both Inserts and Updates I had to change two points :
Use onFlush(), not preFlush()
Add recomputeSingleEntityChangeSet() after each change
The new code :
public function onFlush(OnFlushEventArgs $eventArgs)
{
$token = $this->container->get('security.context')->getToken();
$em = $eventArgs->getEntityManager();
$uow = $em->getUnitOfWork();
// Inserts
foreach ($uow->getScheduledEntityInsertions() as $entity) {
if (is_subclass_of($entity, 'Kiwi\Bundle\TrainingBundle\Entity\EntityDated')) {
$entity->setCreated(new \Datetime());
$entity->setCreatedBy($token->getUser()->getUsername());
$entity->setUpdated(new \Datetime());
$entity->setUpdatedBy($token->getUser()->getUsername());
$meta = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($meta, $entity);
}
}
// Updates
foreach ($uow->getScheduledEntityUpdates() as $entity) {
if (is_subclass_of($entity, 'Kiwi\Bundle\TrainingBundle\Entity\EntityDated')) {
$entity->setUpdated(new \Datetime());
$entity->setUpdatedBy($token->getUser()->getUsername());
$meta = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($meta, $entity);
}
}
}
I'm following Symfony2's form processing:
public function createAction()
{
$entity = new Node();
$request = $this->getRequest();
$form = $this->createForm(new NodeType(), $entity);
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($entity);
$em->flush();
The problem is the the "Node" entity has some other fields that aren't populated by the user, but rather by processes in the controller script. These "system generated" values should also be persisted along with the the "user generated" values from the form.
I'm not sure how to add the system values to the entity.
It is a shortcoming in my OOP knowledge, but I can't find any examples in the docs or online. Thanks!
I think you need to add some getXXX/setXXX methods to Node class (or look inside class'es code for them), so your code will look like
$em = $this->getDoctrine()->getEntityManager();
$entity->setPropertyOne('some value of mine');
$entity->setCurrentUserId($this->get('security.context')
->getToken()->getUser()->getId());
// another entity setters
$em->persist($entity);
Don't know if it would help you in your case, but i suggest reading about Doctrine 2 events here.
I also strongly recommend you reading this (unofficial) Symfony2 book :)
If you want to manage it in entity rather in controller. And if you are ising YML then just add this on YML file
lifecycleCallbacks:
prePersist: [ doPrePersist ]
and in the entity just add this method
function doPrePersist()
{
$this->publish = true;
$this->isDeleted = false;
}
If you are using annotation then in the entity just add the annotation tag
/**
* #ORM\prePersist
*/
function doPrePersist()
{
$this->publish = true;
$this->isDeleted = false;
}