I've got a standard FOS user that's got a ManyToOne entity relationship with a blog entity.
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="blog")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
private $user;
I've used the app/console generate:doctrine:crud command to generate a basic crud system.
When I create a new blog entity I want to insert the logged in user that performed the action. By default Symfony generates CRUD code that allows the user to select which user is connected to the entity.
$builder
->add('name')
->add('address')
->add('facebook')
->add('twitter')
->add('user')
;
In the controller I can access the logged in user using security.context:
$user = $this->get('security.context')->getToken()->getUser();
Whats the best course of action to change this?
Okay! solved my own question (if I'm doing it wrong please feel free to correct me, and I'll accept a better answer). This one does appear to work well however!
The user can be added in the controller after the $form->isValid() check is performed. Here's my controller function for example.
public function createAction(Request $request)
{
$entity = new Blog();
$form = $this->createForm(new BlogType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$entity->setUser($this->get('security.context')->getToken()->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('blog_show', array('id' => $entity->getId())));
}
return $this->render('ExampleBundle:Blog:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
The user needs to be removed from the form builder for this to work.
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?
I am trying to implement Embedded Forms (Symfony2, 2.7), with Task and Tag entities, One2Many.
To save reference to the Task object into a Tag record, I am able to define Task's createAction() only by:
/**
* Creates a new Task entity.
*
* #Route("/", name="MyName_Task_create")
* #Method("POST")
* #Template("MyNameBundleBlogBundle:Task:new.html.twig")
*/
public function createAction(Request $request)
{
$task = new Task();
$form = $this->createCreateForm($task);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$tags = $task->getTags();
foreach($tags as $tg){$tg->setTask($task); $em->persist($tg);} // <-- do I really need to loop?
$em->persist($task);
$em->flush();
return $this->redirect($this->generateUrl('MyName_Task_show', array('id' => $task->getId())));
}
return array(
'entity' => $task,
'form' => $form->createView(),
);
}
EDIT: I know it should work without the loop straightforwardly, but it does not. Question is: What should I look for which I might have written wrong? See related question
Note, I have:
class Task{
....
/**
*
* #ORM\OneToMany(targetEntity="Tag", mappedBy="Task", cascade={"persist"} )
*/
private $Tags;
....
/**
* Add tag
*
* #param \MyName\Bundle\BlogBundle\Entity\Tag $tag
*
* #return Task
*/
public function addTag(\MyName\Bundle\BlogBundle\Entity\Tag $tag)
{
$this->tags[] = $tag;
$tag->setTask($this);
return $this;
}
}
No, you don't need to loop through all tags and explicitly set task, Symfony will do that for you if you configure it correctly.
The only thing you need to add is set by_reference to false inside your form builder. In this case, symfony will explicitly will call setTask on every tag.
For more info 'by_reference'
According to #Cerad comment, the only thing you have to do is persist the Task.
All related tags will be automatically persisted, thanks to cascade={"persist"} in your association mapping.
Your code should be :
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($task);
$em->flush();
return $this->redirect($this->generateUrl('MyName_Task_show', array('id' => $task->getId())));
}
See the Etablishing associations and Cascade operations chapters of Doctrine documentation.
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.
In my controller there is a rather classic action "create" based on Doctrine CRUD generation.
But when I execute this action by clicking the "create" form button several times the same object is created as many times as I clicked.
This is a major problem because my class "Operation" is quite large and takes a long time to record. The user is very tempted to click several times.
/**
* Creates a new Operation entity.
*
* #Route("/", name="operation_create")
* #Method("POST")
* #Template("MyApplicationBundle:Operation:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Operation();
$form = $this->createForm(new OperationType(), $entity, array(
'em' => $this->getDoctrine()->getManager(),
));
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity->setdateCreation(new \DateTime())
->setUser($this->get('security.context')->getToken()->getUser());
$em->persist($entity);
$em->flush();
$this->get('session')->getFlashBag()->add('success', 'OK');
return $this->redirect($this->generateUrl('operation_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
If anyone can help me it would be really nice.
After click on create button you must disabled or remove them with JavaScript, and user can't click second time at it.
If you use jQuery:
<input type="submit" onclick="jQuery(this).attr('disabled', 'disabled')">
I have a CRUD for one of my entities in Symfony2. In order to create a new entry, I have two controller functions:
public function newAction($id) {
$entity = new Clientes();
// Get the reference to the Login entity using its ID
$em = $this->getDoctrine()->getManager();
$ref_login = $em->getReference('LoginBundle:Login', $id);
// Put the retrieved reference to the entity
$entity->setLogin($ref_login);
$form = $this->createForm(new ClientesType(), $entity);
return $this
->render('MovinivelBundle:Persona/Clientes:new.html.twig',
array('entity' => $entity,
'form' => $form->createView(),));
}
public function createAction(Request $request) {
$entity = new Clientes();
$form = $this->createForm(new ClientesType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('clientes'));
}
return $this
->render('MovinivelBundle:Persona/Clientes:new.html.twig',
array('entity' => $entity,
'form' => $form->createView(),));
}
In the previous code I added the $id input parameter to the newAction() function because I want it to be established from outside, because each of this Clientes is additional info of Login and has to be linked.
In the ClientesType form I have the following:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('login')
->add('direccion')
->add('localidad')
->add('provincia')
->add('telefono')
;
}
So far it works. In my form, the login parameter is chosen depending on the $id value. But the thing is that I want the login parameter to be fixed once the form is created, so the user cannot modify it from the form, but only calling the newAction($id) function with the appropiate value.
The thing is that if I delete the ->add('login') line in the FormType, it doesn't work anymore. It comes to my mind two options:
Hide somehow the 'login' in the form, but keeping it working, although I don't know how, or
pass to the createAction the $id parameter along with the $request one as input parameters, but I cannot figure out how do it either.
Any thoughts on this?
I think you are looking for a hidden field type:
public function buildForm(...)
{
$builder
->add('login', 'hidden')
// ...
;
}
Ok, I came out with the solution. All I was looking for is actually the following:
<div style="display:none">
{{ form_rest(form) }}
</div>
Typing this at the end of the template after having shown explicitly any other form field avoids any user to modify the fields I don't want to, while it still sends the info using the $POST method.