Rendering a template with form inside from a service - symfony

my DataTable service code is given below
public function dataTableTest(string $class, Request $request, $FormBuilder): Response
{
$FormFactory = Forms::createFormFactory();
$form = $FormFactory
//->createBuilder()
->create('App\Form\NewsType', null, array(
'method' => 'POST',
))
->add('task', TextType::class, [
'label' => 'Some task',
'required' => true,
])
->add('dueDate', DateType::class)
->add('save', SubmitType::class, [
'label' => 'Create',
])
//->getForm()
;
$response = $this->twig->render('forms/FormFactory.html.twig', [
'controller_name' => 'FormsController',
'form' => $form->createView(),
]);
return new Response($response);
}
FormFactory.html.twig code is
{{ form(form) }}
and i have an error
SyntaxError HTTP 500 Internal Server Error
Unknown "form" function.
1 so how can render a template with twig function 'form' ? or its not possible?
2 When i render some template from service than
a)twig knows entity functions or properties like 'array.id'
b)twig does not know all twig functions like form(), form_start
and so on.
c) I think i need some extra twig dependency injections

Related

Dynamically populate project drop down data based on client drop down choice data. But edit form show exception/error in symfony 5

I want to "Dynamically populate project drop down data based on client drop down choice data" in symfony 5. New page work properly, but when change client drop down value from edit page then ajax called and show this exception/error: "Expected argument of type "string", "null" given at property path "buildingPosition"."
Form Code:
class EnquiryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('client', EntityType::class, [
// looks for choices from this entity
'class' => Client::class,
// uses the User.username property as the visible option string
'choice_label' => 'name',
'placeholder' => 'Select a Client...',
// 'label' => 'Contact Person Designation',
// used to render a select box, check boxes or radios
// 'multiple' => true,
// 'expanded' => true,
])
->add('buildingPosition', TextType::class, [
'attr' => ['class' => 'form-control'],
])
->add('offerSubmissionDate', DateType::class, [
'attr' => ['class' => 'form-control'],
'widget' => 'single_text',
'empty_data' => null,
])
->add('probability', ChoiceType::class, [
'choices' => [
'P1' => 'P1',
'P2' => 'P2',
'P3' => 'P3',
],
'placeholder' => 'Select a Probability...',
])
->add('notes', TextType::class, [
'attr' => ['class' => 'form-control'],
])
;
// Start Project data populate dynamically based on the value in the "client" field
$formModifier = function (FormInterface $form, Client $client = null) {
$projects = null === $client ? [] : $client->getProjects();
$form->add('project', EntityType::class, [
'class' => 'App\Entity\Project',
'placeholder' => '',
'choices' => $projects,
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. Enquiry
$data = $event->getData();
$formModifier($event->getForm(), $data->getClient());
}
);
$builder->get('client')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$client = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $client);
}
);
// End Project data populate dynamically based on the value in the "client" field
}
Controller Code:
public function edit(Request $request, $id): Response
{
$enquiry = new Enquiry();
$entityManager = $this->getDoctrine()->getManager();
$enquiry = $entityManager->getRepository(Enquiry::class)->find($id);
$form = $this->createForm(EnquiryType::class, $enquiry);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
$this->addFlash('notice', 'Enquiry updated successfully!');
return $this->redirectToRoute('enquiry_index');
}
return $this->render('enquiry/edit.html.twig', [
'enquiry' => $enquiry,
'form' => $form->createView(),
]);
}
Twig/View Code:
{{ form_start(form) }}
{{ form_row(form.client, {'attr': {'class': 'form-control'}}) }}
{{ form_row(form.project, {'attr': {'class': 'form-control'}}) }}
{{ form_row(form.buildingPosition) }}
{{ form_row(form.offerSubmissionDate) }}
{{ form_row(form.probability, {'attr': {'class': 'form-control'}}) }}
{{ form_row(form.notes) }}
{{form_row(row)}}
JavaScript Code:
var $client = $('#enquiry_client');
// When sport gets selected ...
$client.change(function() {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected sport value.
var data = {};
data[$client.attr('name')] = $client.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url : $form.attr('action'),
type: "POST",
data : data,
success: function(html) {
// Replace current position field ...
$('#enquiry_project').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#enquiry_project')
);
// Position field now displays the appropriate positions.
}
});
});
Please help me.....

How can I change error message in Symfony

I create a form and then when I click on submit button, show this error message:
Please select an item in the list.
How can I change this message and style it ( with CSS )?
Entity:
...
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank(message="Hi user, Please select an item")
*/
private $name;
...
Controller:
...
public function index(Request $request)
{
$form = $this->createForm(MagListType::class);
$form->handleRequest($request);
return $this->render('index.html.twig', [
'form' => $form->createView()
]);
}
...
Form:
...
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', EntityType::class,[
'class' => InsCompareList::class,
'label' => false,
'query_builder' => function(EntityRepository $rp){
return $rp->createQueryBuilder('u')
->orderBy('u.id', 'ASC');
},
'choice_label' => 'name',
'choice_value' => 'id',
'required' => true,
])
->add('submit', SubmitType::class, [
'label' => 'OK'
])
;
...
}
In order to use custom messages, you have to put 'novalidate' on your HTML form. For example:
With Twig:
{{ form_start(form, {attr: {novalidate: 'novalidate'}}) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Or in your controller:
$form = $this->createForm(MagListType::class, $task, array( //where task is your entity instance
'attr' => array(
'novalidate' => 'novalidate'
)
));
This Stackoverflow answer has more info on how to use novalidate with Symfony. You can also check the docs for more info.
As for the styling, you can use JavaScript to trigger classes, which you can then style in your CSS, like in this example taken from Happier HTML5 Form Validation . You can also take a look at the documentation on MDN and play with the :valid and :invalid selectors.
const inputs = document.querySelectorAll("input, select, textarea");
inputs.forEach(input => {
input.addEventListener(
"invalid",
event => {
input.classList.add("error");
},
false
);
});
EDIT:
You are probably not seeing your custom message because it comes from server side, the message that you're currently seeing when submitting your form is client-side validation. So you can either place novalidate on your field, or you can override the validation messages on the client side by using setCustomValidity(), as described in this SO post which also contains many useful links. An example using your Form Builder:
$builder
->add('name', EntityType::class,[
'class' => InsCompareList::class,
'label' => false,
[
'attr' => [
'oninvalid' => "setCustomValidity('Hi user, Please select an item')"
]
],
'query_builder' => function(EntityRepository $rp){
return $rp->createQueryBuilder('u')
->orderBy('u.id', 'ASC');
},
'choice_label' => 'name',
'choice_value' => 'id',
'required' => true,
])
->add('submit', SubmitType::class, [
'label' => 'OK'
]);

Symfony4 - change single parameter in url after submitting form

I have a route that looks like this - route/{parameter} and I need to change the parameter after submitting a form.
I tried to use redirectToRoute but it created new URL together with some other parameters that the form passed which I don't want.
So I would love to ask you if there is some way to redirect to a new URL with the only parameter that I choose through select in the form.
Thank you very much for your responses.
EDIT:
I am going to share more actual information. This is how my controller for the form looks like:
$form = $this->createFormBuilder()
->setMethod("get")
->add('category', ChoiceType::class, [
'choices' => [
'Všechny kategorie' => 'vsechny-kategorie',
'Automobilový průmysl' => 'automobilovy-prumysl',
'Stavebnictví' => 'stavebnictvi',
'Elektronika a elektrotechnika' => 'elektronika-a-elektrotechnika',
'Gastronomie' => 'gastronomie',
'Lesnictví' => 'lesnictvi',
'Potravinářský průmysl' => 'potravinarsky-prumysl',
'IT technologie' => 'it-technologie',
'Logistika' => 'logistika',
'Strojírenství' => 'strojirenstvi',
'Zdravotnictví' => 'zdravotnictvi'
],
'label' => 'Kategorie:'
])
->add('send', SubmitType::class, ['label' => 'Test'])
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$category = $data['category'];
return $this->redirectToRoute('jobs', [
'jobs' => $pagination,
'categoryForm' => $form->createView(),
'category' => $category,
]);
}
You should be able to use the redirectToRoute, but be sure to pass the parameter you're trying to dynamically set as an array:
// in your controller action:
return $this->redirectToRoute('post_form_route', ['parameter' => $parameter]);
If that's not working for you, I would double check your route definitions and make sure your route's name & expected URL parameters are passed correctly.
Documentation on redirecting in the controller
you can try that :
if($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$category = $data['category'];
return $this->redirectToRoute('route', [
'parameter' => $form->getData()->getCategory()
]);
}
return $this->redirectToRoute('jobs', [
'jobs' => $pagination,
'categoryForm' => $form->createView(),
]);

How to get rid of the Invalide CSRF token error

I have a symfony form. Submitting it, I have an error message :
The CSRF token is invalid. Please try to resubmit the form.
I dont know why I have this. I bind request to form after checking the request method is post :
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
}
Here is the type of the form.
class PasswordActionType extends AbstractType {
protected $forgotten_password;
public function __construct($forgotten_password) {
$this->forgotten_password = $forgotten_password;
}
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) {
$builder->add('identifiant', 'text', array('attr' => array('style' => 'width:250px')));
if(!$this->forgotten_password) {
$builder->add('ancienMDP', 'password', array(
'label' => 'Ancien MDP',
'attr' => array(
'class' => 'ligne',
'style' => 'width:252px'
)));
$builder->add('nouveauMDP', 'repeated', array(
'type' => 'password',
'invalid_message' => 'Confirmation différente du nouveau mot de passe',
'first_options' => array('label' => 'Nouveau MDP'),
'second_options' => array('label' => 'Confirmer'),
'options' => array(
'attr' => array(
'class' => 'ligne',
'style' => 'width:252px'
))
));
} else {
$builder->add('ancienMDP', 'hidden', array('error_bubbling' => false, 'data' => 'NULL'));
$builder->add('nouveauMDP', 'hidden', array('error_bubbling' => false, 'data' => 'NULL'));
}
}
public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'My\Bundle\Security\PasswordAction',
'csrf_protection' => true,
'csrf_field_name' => 'token'
));
}
public function getName() {
return 'cramif_password_action';
}
}
So 2 forms use the same builder. The difference is the value of "forgotten_password".
form1 : forgotten_password = true
the 2 fields 'ancienMDP' and 'NouveauMDP' are hidden html fields
form2: forgotten_password = false
the 2 fields are what u can see.
There is not problem with form1, no CSRF error.
The problem occurs with form2.
Note : the 2 forms are displayed with Twig with the same commands.
Note2 : in the twig template I have a form_rest
Just to help people :
If u think u did it right :
bind the request after checking that the form is posted
used form_rest.
Check that you did not invalidate your session. Of course, for the CSRF to work, you need a valid session.

Symfony 2: Set field as read only after first save

I have a Symfony 2 entity. When I create a new record, I must fill all the values using a form, but after saving it, one of the values, $amount shouldn't be updatable when I update the others members.
How can I accomplish this? It's possible to mark a form member as a read-only, in runtime?
By using the validation_groups and name options when creating your form, you can change the form.
The name attribute sets the form creation, and the validation_groups takes care of the validation.
For example, in the create/new method of your controller;
public function createAction(Request $request)
{
// Instantiate new Foo object
$client = new Foo();
// create the form (setting validation group)
$form = $this->formFactory->create('foo', $foo, array(
'name' => 'create',
'validation_groups' => array('create')
)
);
// form has been submitted...
if ('POST' === $request->getMethod()) {
// submits the form
$form->handleRequest($request);
// do validation
if ($form->isValid()) {
// do whatever
}
}
// either GET or validation failed, so show the form
return $this->template->renderResponse('FooBundle:foo:add.html.twig', array(
'form' => $form->createView(),
'foo' => $foo
));
}
And in the edit/update function of your controller;
public function updateAction($id, Request $request)
{
// Instantiate Client object
$client = new Foo($id);
// create the form (setting validation group)
$form = $this->formFactory->create('foo', $foo, array(
'name' => 'update',
'validation_groups' => array('update')
));
// form has been submitted...
if ('POST' === $request->getMethod()) {
// submits the form
$form->handleRequest($request);
// do validation
if ($form->isValid()) {
// do whatever
}
}
// either GET or validation failed, so show the form
return $this->template->renderResponse('FooBundle:foo/edit:index.html.twig', array(
'form' => $form->createView(),
'foo' => $foo
));
}
And your Form Type will look something like;
class FooType extends BaseAbstractType
{
protected $options = array(
'data_class' => 'FooBundle\Model\Foo',
'name' => 'foo',
);
private $roleManager;
public function __construct($mergeOptions = null)
{
parent::__construct($mergeOptions);
}
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->$options['name']($builder, $options);
}
private function create(FormBuilderInterface $builder, array $options)
{
// ID
$builder->add('Id', 'text', array(
'required' => true,
'label' => 'ID',
'attr' => array(
'placeholder' => 'Format: 2 alphanumeric (e.g. A1)'
)
));
// Name - only show on create
$builder->add('Name', 'text', array(
'required' => true,
'label' => 'Name',
'attr' => array(
'placeholder' => 'Your name'
)
));
// add the submit form button
$builder->add('save', 'submit', array(
'label' => 'Save'
));
}
private function update(FormBuilderInterface $builder, array $options)
{
// ID
$builder->add('Id', 'text', array(
'required' => true,
'label' => 'ID',
'attr' => array(
'placeholder' => 'Format: 2 alphanumeric (e.g. A1)',
)
));
// Name - just for show
$builder->add('Name', 'text', array(
'required' => true,
'label' => 'Name',
'attr' => array(
'readonly' => 'true' // stops it being editable
)
));
// add the submit form button
$builder->add('save', 'submit', array(
'label' => 'Save'
));
}
}
P.S. All my classes are declared as services, so how you call create forms/views/etc may be different.

Resources