I have a contact form that works fine. But I want to fill some of this fields when an user click in one link. I receipt the information of some fields in the form controller, but I don't know how can I show this form with this fields with these datas.
Thanks!
You can pass an object, which corresponds to your data fields, when you create your form :
In your controller:
$task = new Task();
$task->setTask('Write a blog post');
$task->setDueDate(new \DateTime('tomorrow'));
$form = $this->createFormBuilder($task)
->add('task', 'text')
->add('dueDate', 'date')
->add('save', 'submit')
->getForm();
Or if you have your own FormType class, bind it to your Entity :
class MyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Build form here
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// Bind entity here
$resolver->setDefaults(array(
'data_class' => 'BlueLinea\Bundle\BlueHomeCareBundle\Entity\MyEntity',
));
}
}
And in your controller :
$myEntity = new MyEntity();
$form = $this->createForm(new MyFormType(), $myEntity);
See Forms (Building the Form) - Symfony
Related
I want to patch some data in my api-platform api using symfony forms. Before that i need to generate a form which should get filled form with actual data.
Is this a good way to do it?
class CruderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class)
->add('amount', IntegerType::class)
->add('save', SubmitType::class)
;
}
}
public function editProduct($id, Request $request) {
$client = new CurlHttpClient();
$data = array($client->request('GET', 'https://api'));
// url return: [{"id":1,"name":"testname","amount":2}]
$form = $this->createForm(CruderType::class, $data);
return $this->render('product/edit_product.html.twig', [
'form' => $form->createView()
]);
}
It returns form but fields not filled by data from endpoint.
(Yes, I know it won't send, it'll be done later)
I have a Business Entity and a BusinessObject Entity, and I would like to link the BusinessObject to the current Business when I create a new BusinessObject.
For example, if my route is business/{id}/object/new, I would like to have the object related with the Business (thanks to the id).
In my BusinessObject Controller, I managed to use #ParamConverter to get the Business id.
In my BusinessObject Form, I put an HiddenType to my business entry because I don't want it to appear, and set data to business_ID.
I struggle in configureOptions to get the business ID, I can't figure out how to get the business id from here.
BusinessObject Controller (route new):
/**
* #Route("/{post_id}/new", name="business_object_new", methods="GET|POST")
* #ParamConverter("business", options={"id" = "post_id"})
*/
public function new(Request $request,Business $business): Response
{
$businessObject = new BusinessObject();
$businessID = $business->getId();
$form = $this->createForm(BusinessObjectType::class, $businessObject,array(
'business_ID'=>$businessID,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($businessObject);
$em->flush();
return $this->redirectToRoute('business_object_index');
}
return $this->render('business_object/new.html.twig', [
'business_object' => $businessObject,
'business'=>$business,
'form' => $form->createView(),
]);
}
BusinessObjectType:
class BusinessObjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('object',TextType::class)
->add('complement')
->add('status')
->add('durationExpected')
->add('durationAchieved')
->add('client')
->add('projectManager')
->add('business',HiddenType::class,array(
'data' => $options['business_ID']
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => BusinessObject::class,
'business_ID'=>Business::class
]);
}
}
With this code, I get an error Expected argument of type "App\Entity\Business or null", "string" given. I think this have something to do with the function configureOptions() in my Form
The approach can be:
public function new(Request $request,Business $business): Response
{
$businessObject = new BusinessObject();
$form = $this->createForm(BusinessObjectType::class, $businessObject);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// I suppose your setter is `setBusiness`, otherwise use more suitable one
$businessObject->setBusiness($business);
$em = $this->getDoctrine()->getManager();
$em->persist($businessObject);
$em->flush();
Form builder is:
builder
->add('object',TextType::class)
->add('complement')
->add('status')
->add('durationExpected')
->add('durationAchieved')
->add('client')
->add('projectManager'); // No business field
Another option is to embed BusinessType form into BusinessObjectType, you can read more about form embedding here.
I'm actually creating a website (with symfony 3) where the login form is on the main page (route /). And I would like to handle this form on the /login route.
Unfortunately I don't know how to do that because my form is built in the indexAction() and my loginAction() has no visibility on the $form built in index...
/**
* #Route("/", name="home")
*/
public function indexAction()
{
$user = new User();
$form = $this->createFormBuilder($user)
->setAction($this->generateUrl('login'))
->setMethod('POST') //btw is this useless ?? Is it POST by default ?
->add('Login', TextType::class)
->add('Password', TextType::class)
->add('save', SubmitType::class, array('label' => 'Sign In'))
->getForm();
return $this->render('ShellCodeHomeBundle:Home:index.html.twig', array (
'login' => '',
'form_signin' => $form->createView(),
));
}
/**
* #Route("/login", name="login")
*/
public function loginAction(Request $request)
{
$user = new User();
//how do I handle the form ????
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$user = $form->getData();
//...
}
return $this->render('ShellCodeHomeBundle:Home:index.html.twig', array (
'login' => $user->getLogin(),
));
}
I guess it's useless to tell that, but I'm using twig and I insert the form like this :
<div class="col-lg-12" style="text-align: center;">
{{ form_start(form_signin) }}
{{ form_widget(form_signin) }}
{{ form_end(form_signin) }}
</div>
Hope you will able to help me ! Thanks !
Do not build your form within the controller, that's a bad practice, because you can't reuse this code.
You should create your form within FormType and define them as a service. That way, you'll be able to reuse this form as often as you need it to.
Taken from the docs linked below, here's an example for the FormType:
namespace AppBundle\Form;
use AppBundle\Entity\Post;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
class PostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('summary', TextareaType::class)
->add('content', TextareaType::class)
->add('authorEmail', EmailType::class)
->add('publishedAt', DateTimeType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Post::class,
));
}
}
Then you could use the FormType as in this example:
use AppBundle\Form\PostType;
// ...
public function newAction(Request $request)
{
$post = new Post();
$form = $this->createForm(PostType::class, $post);
// ...
}
For detailed information, check the docs
Create a custom form type.
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\{
PasswordType, SubmitType, TextType
};
use Symfony\Component\Form\FormBuilderInterface;
class LoginForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Login', TextType::class)
->add('Password', PasswordType::class)
->add('save', SubmitType::class, [
'label' => 'Sign In'
])
;
}
}
Here is the answer :
In your other function just build the same form, handle the request and check if it's valid in this second method.
#[Route('/url', name: 'app_url')]
public function index(Request $request, EntityManagerInterface $em) : Response {
$entity = new Entity();
$data = 'some data';
$form = $this->createForm(EntityFormType::class, $entity, [ 'data' => $data, 'action' => 'other_url' ]);
/** extra code and send the request **/
}
then in the second controller function :
#[Route('/otherUrl', name: 'other_url')]
public function validation(Request $request, EntityManagerInterface $em) : Response {
/** SAME FORM CODE HERE **/
$entity = new Entity();
$form = $this->createForm(EntityFormType::class, $entity, [ 'data' => $data, 'action' => 'other_url' ]);
/** extra code and send the request **/
}
The form will be received and the framework will understand it correctly, it's like it's the same form, each form data will be put in the right place in the new form instance faking it's the same.
I am trying to populate form fields with data from the database in order to edit them. I already searched on google.
Here is my controller which returns empty fields
public function userViewAction($id,Request $request){
$em = $this->getDoctrine()->getManager()->getRepository('BFVMailingBundle:MailingList');
$user = $em->findById($id);
$form = $this->get('form.factory')->createBuilder('form',$user)
->add('unsubscribed','checkbox')
->add('name','text')
->add('givenName','text')
->add('additionalName','text',array('required'=>false))
->add('familyName','text',array('required'=>false))
->add('emailValue','text')
->add('language','choice',array(
'choices' => array('en_GB' => 'en_GB', 'es_ES' => 'es_ES', 'fr_FR' => 'fr_FR'),
'required' => true,
))
->add('commentary','textarea',array('required'=>false))
->add('save','submit')
->getForm();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// perform some action, such as save the object to the database
$em->flush();
return $this->redirect($this->generateUrl('user_view',array('id'=>$id)));
}
}
and this is my template
<div class="cell">
{{ form_start(form, {'attr': {'class': 'form-horizontal'}}) }}
{{ form_end(form) }}
</div>
Did I miss something?
EDIT - READ THIS FOR THE SOLUTION
As John Noel Implied I build an externalised form with the command
php app/console doctrine:generate:form BFVMailingBundle:MailingList
my entity was MailingList instead of User
the MailingListType is a form template which is generated in BFV\MailingBundle\Form. I've added the data types myself.
<?php
namespace BFV\MailingBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MailingListType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$str = date("U");
$codeValue = sha1($str);
$builder
->add('secretCode','hidden',array( 'data' => $codeValue ))
->add('name','text')
->add('givenName','text')
->add('additionalName','text',array('required'=>false))
->add('familyName','text',array('required'=>false))
->add('emailValue','text')
->add('language','choice',array(
'choices' => array('en_GB' => 'en_GB', 'es_ES' => 'es_ES', 'fr_FR' => 'fr_FR'),
'required' => true,
))
->add('unsubscribed','checkbox')
->add('commentary','textarea',array('required'=>false))
->add('save','submit')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BFV\MailingBundle\Entity\MailingList'
));
}
/**
* #return string
*/
public function getName()
{
return 'bfv_mailingbundle_mailinglist';
}
}
In the reformated controller I add to add the the form generator the instance of MailingList $user[0] instead of $user. I read in many websites that usually you put $variable directly in the form builder but that generated the following error:
The form's view data is expected to be an instance of class
BFV\MailingBundle\Entity\MailingList, but is a(n) array. You can avoid
this error by setting the "data_class" option to null or by adding a
view transformer that transforms a(n) array to an instance of
BFV\MailingBundle\Entity\MailingList
Thus in the controller:
public function userViewAction($id,Request $request){
if (!$id) {
throw $this->createNotFoundException('No id !!');
}
$em = $this->getDoctrine()->getManager()->getRepository('BFVMailingBundle:MailingList');
$user = $em->findById($id);
if (!$user){
throw $this->createNotFoundException('No user with the id selected');
}
$form = $this->createForm(new MailingListType(), $user[0]);
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('user_view',array('id'=>$id)));
}
}
return $this->render('BFVMailingBundle:Default:user_view.html.twig',array(
'user'=>$user,
'form'=>$form->createView()
));
}
Conclusion: I got the view form rendering with populated data from the database.
To do this you'll want to look into form classes which will then act as a view (and will also populate) the data you provide. So in your example you'd create a form class UserType:
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('unsubscribed','checkbox')
->add('name','text')
->add('givenName','text')
->add('additionalName','text',array('required'=>false))
->add('familyName','text',array('required'=>false))
->add('emailValue','text')
->add('language','choice',array(
'choices' => array('en_GB' => 'en_GB', 'es_ES' => 'es_ES', 'fr_FR' => 'fr_FR'),
'required' => true,
))
->add('commentary','textarea',array('required'=>false))
->add('save','submit')
;
}
public function getName()
{
return 'user';
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Your\Entity\Class',
));
}
}
Then within your controller you'd do something along the lines of:
$form = $this->createForm(new UserType(), $user);
Then the rest of your controller as you have. Definitely read up on form classes though as that's the starting point for a lot of the advanced functionality of Symfony forms.
I'm not sure if this is what makes the difference, but did you try with:
$form = $this->createFormBuilder($user)
->add(...)
->getForm()
You may also check that the User you get is correctly read from the DB.
For example:
if (!is_object($user)) {
$this->createNotFoundException('The user does not exist');
}
As I know I could create form using form type: $form = $this->createForm(new RegistrationType(), $user);
And here is form type:
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
$builder->add('email', 'email');
$builder->add('terms', 'checkbox', array(
'mapped' => false
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'App\UsersBundle\Entity\User'
));
}
public function getName()
{
return 'user_registration';
}
}
So I could add field term and don't map it to entity. But what is the way to validate this field? Sure I can do something like if ($form->get('terms')->getData()) in my controller but I want to use one function $form->isValid() to validate all fields (mapped and don't mapped)? May be any validate hooks or events exists?
It's covered in the Adding Validation section of the Forms chapter.