I'm working with Symfony 2 and I want to pass from my controller to my twig template a simple string and then use it on my template to descriminate the user role.
The controller code has something like :
public function modify_user_asAction(Request $request, $username)
{
$stringtopass="admin";
$um = $this->get('fos_user.user_manager');
$user = $um->findUserByUsername($username);
if($user == null){
//error page here..
}
$form = $this->createForm(new UserForm(), $user);
$form->handleRequest($request);
if ($form->isValid()) {
$um->updateUser($user);
return $this->redirect($this->generateUrl('acme_query_success'));
}
return $this->render('AcmeUserBundle:Default:modifyuserform.html.twig', array(
'form' => $form->createView(),
));
}
I want to pass $stringtopass in the generateUrl (if it's possible).
I can't find anything online.
Thanks
You are almost there!
API: generateUrl
Basically, just pass an array as second param to generateUrl.
return $this->redirect($this->generateUrl('acme_query_success', array('stringToPass' => $stringtopass)));
And also, #Brewal has a very valid point there. Be careful not to pass some sensitive data or leave unrestricted access to that controller's action. You could do more harm than good...
UPDATE:
public function acmeQuerySuccessAction(){
// ... action's logic
$stringToPass = $this->getRequest()->query->get('stringToPass');
// .....
return array(
'stringToPass' => $stringToPass,
// all other elements that you would normally return
);
}
Related
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'm developing a RESTFul API in Symfony 2.3.* with FOSUserBundle and FOSRestBundle, and I'm having trouble understanding how to create a registration method.
My controller look like this :
class UserRestController extends FOSRestController
{
//Other Methods ...
public function postUserAction()
{
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
$param = $paramFetcher->all();
$form = $this->createForm(new UserType(), $user);
$form->bind($param);
if ($form->isValid() == false)
return $this->view($form, 400);
$userManager->updateUser($user);
return $this->view('User Created', 201);
}
//...
}
And my UserType class :
class UserType extends BaseType
{
public function __construct($class = "User")
{
parent::__construct($class);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('username', 'username')
->add('email', 'email')
->add('plainPassword', 'repeated', array(
'first_name' => 'password',
'second_name' => 'confirm',
'type' => 'password'
))
->add('lastname')
->add('firstname')
->add('job_position')
->add('phone')
->add('company_name')
->add('website')
->add('sector')
->add('address')
->add('city')
->add('zip_code')
->add('country')
->add('billing_infos_same_as_company')
->add('billing_address')
->add('billing_city')
->add('billing_zip')
->add('billing_country')
->add('putf')
->add('das');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Wipsea\UserBundle\Entity\User',
'csrf_protection' => false
));
}
public function getName()
{
return 'wipsea_user_registration';
}
}
When I test it, no matter what the form isn't valid and shows no error.
And when I try to get the request :
"Validation Failed" "This form should not contain extra fields."
Is there a way to properly validate the form ?
EDIT : Updating my problem.
I would recommend you this tutorial in 3 parts - there is everything you need:
http://welcometothebundle.com/symfony2-rest-api-the-best-2013-way/
http://welcometothebundle.com/web-api-rest-with-symfony2-the-best-way-the-post-method/
http://welcometothebundle.com/symfony2-rest-api-the-best-way-part-3/
If you want to provide complex user validation you should create UserType form and pass data to this form instead of directly setting all properties:
public function postAction()
{
$user = new User();
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
// propel version
$user->save();
$response = new Response();
$response->setStatusCode(201);
// set the `Location` header only when creating new resources
$response->headers->set('Location',
$this->generateUrl(
'acme_demo_user_get', array('id' => $user->getId()),
true // absolute
)
);
return $response;
}
// return form validation errors
return View::create($form, 400);
}
In part 2 of this tutorial you have all information about creating form, passing data and validating it with RestBundle.
There is also a lot information about best practices using REST with Symfony2.
Take a look at this code:
https://github.com/piotrjura/fitness-api/blob/master/src/Fitness/FitnessBundle/Service/UsersService.php#L40
https://github.com/piotrjura/fitness-api/blob/master/src/Fitness/FitnessBundle/Controller/UsersController.php#L30
Also check validation.yml and entity serializer yml files.
You don't need forms to do the validation. And you definitly should not put the user creation and validation logic inside a controller. In case you'd like to make use of that form anyway later, eg. render it on the backend side, you'll have to write the same code twice.
I had to have the getName() method return '' in order for it to work for me.
https://github.com/FriendsOfSymfony/FOSRestBundle/issues/585
How can I clear form values after successful form submission?
These didn't help:
How to clear field value with Symfony2 forms
Clear form values after successful submit
CONTROLLER:
namespace Car\BrandBundle\Controller;
use Car\BrandBundle\Entity\BrandEntity;
use Car\BrandBundle\Form\Type\BrandType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class BrandController extends Controller
{
public function indexAction()
{
$form = $this->getFrom();
return $this->render('CarBrandBundle:Default:brand.html.twig',
array('page' => 'Brand', 'form' => $form->createView(), 'brands' => $this->getBrands()));
}
public function createAction(Request $request)
{
if ($request->getMethod() != 'POST')
{
return new Response('Only POST method is allowed');
}
$form = $this->getFrom();
$form->handleRequest($request);
if ($form->isValid())
{
$submission = $form->getData();
$em = $this->getDoctrine()->getManager();
$brand = new BrandEntity();
$brand->setName($submission->getName());
$em->persist($brand);
$em->flush();
$this->redirect($this->generateUrl('brand'));
}
return $this->render('CarBrandBundle:Default:brand.html.twig',
array('page' => 'Brand', 'form' => $form->createView(), 'brands' => $this->getBrands()));
}
private function getFrom()
{
return $this->createForm(new BrandType(), new BrandEntity(),
array('action' => $this->generateUrl('brandCreate')));
}
private function getBrands()
{
$repo = $this->getDoctrine()->getRepository('CarBrandBundle:BrandEntity');
$brands = $repo->findAll();
return $brands;
}
}
You simply need to unset both form and entity objects. Then, create new, clean instances so they are available in your template.
Personally I prefer to do it only when the form is properly validated.
if($form->isValid()){
// persisting and flushing the entity
unset($entity);
unset($form);
$entity = new Entity();
$form = $this->createForm(new EntityType(), $entity);
}
Works for me.
Cheers.
Resetting symfony form when same page handles the submission
In Bazyl's method creating another form after unsetting current form may be unnecessary task. I suggest to redirect to same page because symfony documentation (handling-form-submissions) also shows an example which redirects to another controller.
if ($form->isSubmitted() && $form->isValid()) {
// ... perform some action, such as saving the task to the database
return $this->redirect($request->getUri());
}
I have added sample sources to GitHub
Not sure if it is related but when your form is valid, you do $this->redirect($this->generateUrl('brand'));. The issue is $this->redirect() simply creates a redirect response that your controller must return in order to be taking into account. In other words, just do $this->redirect() in the middle of a controller does nothing (except intantiating a RedirectResponse which be garbage collected by PHP).
If using twig templates, you can just clear it there.
Example:
{{ form_start(form) }}
{{ form_widget(form.yourFieldNameHere, { 'value': '' }) }}
{{ form_end(form) }}
I want to separate form validation logic:
public function contactAction()
{
$form = $this->createForm(new ContactType());
$request = $this->get('request');
if ($request->isMethod('POST')) {
$form->submit($request);
if ($form->isValid()) {
$mailer = $this->get('mailer');
// .. setup a message and send it
return $this->redirect($this->generateUrl('_demo'));
}
}
return array('form' => $form->createView());
}
I want to translate into 2 separate actions:
public function contactAction()
{
$form = $this->createForm(new ContactType());
return array('form' => $form->createView());
}
public function contactSendAction()
{
$form = $this->createForm(new ContactType());
$request = $this->get('request');
if ($request->isMethod('POST')) {
$form->submit($request);
if ($form->isValid()) {
$mailer = $this->get('mailer');
// .. setup a message and send it using
return $this->redirect($this->generateUrl('_demo'));
}
}
// errors found - go back
return $this->redirect($this->generateUrl('contact'));
}
The problem is that when errors exist in the form - after form validation and redirect the do NOT showed in the contactAction. (probably they already will be forgotten after redirection - errors context will be lost)
If you check out how the code generated by the CRUD generator handles this you will see that a failed form validation does not return a redirect but instead uses the same view as the GET method. So in your example you would just:
return $this->render("YourBundle:Contact:contact.html.twig", array('form' => $form->createView()))
rather than return the redirect. This means you do not lose the form errors as you do in a redirect. Something else the CRUD generator adds is the Method requirement which means you could specify that the ContactSendAction requires the POST method and thus not need the extra if($request->isMethod('POST')){ statement.
You can also just return an array if you specify the template elsewhere, for example you could use the #Template annotation and then just
return array('form' => $form->createView())
This seems to work for me in Symfony 2.8:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller {
public function templateAction()
{
$form = $this->createForm(new MyFormType(), $myBoundInstance);
if ($session->has('previousRequest')) {
$form = $this->createForm(new MyFormType());
$form->handleRequest($session->get('previousRequest'));
$session->remove('previousRequest');
}
return array(
'form' => $form->createView(),
);
}
public function processingAction(Request $request)
{
$form = $this->createForm(new MyFormType(), $myBoundInstance);
$form->handleRequest($request);
if ($form->isValid()) {
// do some stuff
// ...
return redirectToNextPage();
}
$session->set('previousRequest', $request);
// handle errors
// ...
return redirectToPreviousPage();
}
}
Please note that redirectToNextPage and redirectToPreviousPage, as well as MyFormType, are pseudo code. You would have to replace these bits with your own logic.
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.