Symfony2 make field entity dynamically - symfony

I have a number of fields of an entity that I see on a page, I would like for each of these fields you can edit them via ajax, one at a time.
To do this I came up with the idea of ​​building a unique controller for all fields, but I can not make it work and I do not know if it is the right solution for what I try to do.
my page show field:
<div>
<form class="ajax" action="{{ path('ajax_setSocial', { 'id': entity.id }) }}" method="post" {{ form_enctype(form) }}>
<div class="editor">
{{ form_errors(form) }}
<div class="editLabel pls lti">{{ form_label(form.ragSocial) }}</div>
<div class="editField">
<div class="ptm">
{{ form_widget(form.ragSocial) }} {{ form_errors(form.ragSocial) }}
</div>
{{ form_widget(form._token) }}
<div class="mtm">
<button class="btn btn-primary disabled save" type="submit" disabled>Save</button>
<button class="btn ann">Cancel</button>
</div>
</div>
</div>
</form>
</div>
<div>
<form class="ajax" action="{{ path('ajax_setSocial', { 'id': entity.id }) }}" method="post" {{ form_enctype(form) }}>
<div class="editor">
{{ form_errors(form) }}
<div class="editLabel pls lti">{{ form_label(form.pIva) }}</div>
<div class="editField">
<div class="ptm">
{{ form_widget(form.pIva) }} {{ form_errors(form.pIva) }}
</div>
{{ form_widget(form._token) }}
<div class="mtm">
<button class="btn btn-primary disabled save" type="submit" disabled>Save</button>
<button class="btn ann">Cancel</button>
</div>
</div>
</div>
</form>
</div>
in my controller:
public function setSocialAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MyBusinessBundle:Anagrafica')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Anagrafic entity.');
}
$field = $request->get('field');
$class = $field.'Type()';
$form = $this->createForm(new $class, $entity);
$form->bind($request);
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
$response = new Response();
$output = array('success' => true);
$response->headers->set('Content-Type', 'application/json');
$response->setContent(json_encode($output));
return $response;
}
$class = $field.'Type()';
$form = $this->createForm(new $class, $entity);
with these lines of code I try to make dynamic class that generates the form field, but does not work because it is being transformed as a string and the error I get is:
Fatal error: Class 'ragSocialType()' not found
but the class is! and is also called to the top file ..
I hope I explained, I accept any advice to follow a better way!

$class = $field.'Type'; //remove the ()
$form = this->createForm(new $class, $entity);

Related

Call to a member function getId() on null in symfony 3

I'm trying to retrieve the values ​​of an attribute passed in request, I have tried, I can not, and it returns a NULL, when I make a var_dump on the attribute.
First of all I created a form to enter a comment, and when we click on validate, this page will have to take you back to a page where I have the comment list for each doctor, but I only receive this error which tells me "Call to a member function getId () on null" because I can not recover the value of doctor
Controller of create comments
public function commentCreateAction(Request $request, Booking $bookings)
{
$em = $this->getDoctrine()->getEntityManager();
// $medecin = $booking->getMedecin();
$patient = $bookings->getPatient();
$repoMedecin = $em->getRepository('DoctixMedecinBundle:Medecin');
$medecin = $repoMedecin->findOneBy(array(
'id' => $request->query->get("medecin")
));
$bookings = $em->getRepository("DoctixFrontBundle:Booking")->findBy(array(
"patient" => $patient
));
$comments = new Comment();
$comments->setMedecin($medecin);
$comments->setPatient($patient);
$form = $this->createForm('Doctix\PatientBundle\Form\CommentType', $comments);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($comments);
$em->flush();
return $this->render('DoctixPatientBundle:Patient:comments.html.twig', array(
'id' => $comments->getMedecin()->getId(),
'comments' => $comments,
'bookings' => $bookings
));
}
return $this->render('DoctixPatientBundle:Patient:create.html.twig', array(
'comment' => $comment,
'form' => $form->createView()
));
}
Controller from the list of comments
public function commentsAction(Request $request){
$em = $this->getDoctrine()->getManager();
$repoMedecin = $em->getRepository('DoctixMedecinBundle:Medecin');
$medecin = $repoMedecin->findOneBy(array(
'id' => $request->query->get("medecin")
));
$patient = $em->getRepository("DoctixPatientBundle:Patient")->findOneBy(array(
'user' => $this->getUser(),
));
$bookings = $em->getRepository("DoctixFrontBundle:Booking")->findBy(array(
"patient" => $patient
));
***
$comments = $em->getRepository("DoctixPatientBundle:Comment")
->getCommentsForDoc($medecin->getId());
***
return $this->render('DoctixPatientBundle:Patient:comments.html.twig', array(
'comments' => $comments,
'bookings' => $bookings
));
}
My mistake is in this controller.
to have the comments of a doctor, I have a function in my repository
Repository
public function getCommentsForDoc($docId, $approved = true)
{
$qb = $this->createQueryBuilder('c')
->select('c')
->where('c.medecin = :medecin_id')
->addOrderBy('c.created')
->setParameter('medecin_id', $docId);
if (false === is_null($approved))
$qb->andWhere('c.approved = :approved')->setParameter('approved', $approved);
return $qb->getQuery()->getResult();
}
Routing of commentsAction and createcomment
patient_comments:
path: /patient/medecin/comments
defaults: { _controller: DoctixPatientBundle:Patient:comments}
patient_comments_create:
path: /patient/medecin/{id}/create
defaults: { _controller: DoctixPatientBundle:Patient:commentCreate}
View of commentsAction
{% for booking in bookings %}
<div class="list_general" id="liste">
<ul>
<li>
<figure>
<img src="{{ vich_uploader_asset(booking.medecin.media, 'imageFile') }}"
alt="{{ booking.medecin.media.imagename }}">
</figure>
<h4>
Dr. {{ booking.medecin.user.prenom|capitalize }} {{ booking.medecin.user.nom|upper }}
<i class="pending">Pending</i>
</h4>
<a href="{{ path('patient_comments_create', {'id': booking.id}) }}?medecin={{ booking.medecin.id }}">
Ajouter un Commentaire
</a>
<header>
{% for comment in comments %}
{% if comment is defined %}
<label>Nom</label>
<input type="text" class="form-control" readonly
value=" {{ comment.patient.user.nom }} ">
<label>Nom</label>
<input type="text" class="form-control" readonly
value=" {{ comment.patient.user.prenom }} ">
<p> a commenté </p>
<p>
<time datetime="{{ comment.created|date('c') }}">
{{ comment.created|date('l, F j, Y') }}
</time>
</p>
</header>
<label>My Comments</label>
<input type="text" class="form-control" readonly
value=" {{ comment.comment }} ">
{% else %}
<p> Il n'y a pas encore de commentaires à propos de ce médecin. Soyez le premier à commenter....</p>
{% endif %}
{% endfor %}
{% endfor %}
my layout where there is the Feedback tab and where I call my route
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="Mon profil">
<a class="nav-link link-white" href="{{ path('patient_comments')}}">
<i class="fa fa-fw fa-comments"></i>
<span class="nav-link-text">FeedBack</span>
</a>
</li>
Although the question is still lacking the information how exactly you are accessing this route - i.e. why you have made the assumption that the medicin id would be passed in the request params - to me it just looks like your route definition is missing the id:
patient_comments:
path: /patient/medecin/{id}/comments
defaults: { _controller: DoctixPatientBundle:Patient:comments}
and
public function commentsAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$repoMedecin = $em->getRepository('DoctixMedecinBundle:Medecin');
$medecin = $repoMedecin->find($id);
...

Symfony forward with #Template

I have an entry point controller (editAction) which depending on a route variable ({property}) will display different templates. I am using annotation "#Template".
I tried a lots of differtings settings but none is working. The closing that I got is with the following :
Error is " The merge filter only works with arrays or hashes "
public function editAction(Request $request, $property, $id)
{
// controller logic
$form = $this->createForm('ObjectEdit'.ucfirst($property), $object);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirect($this->generateUrl('acme-demo-dashboard-show'));
}
$response = $this->forward('AcmeDemoBundle:Dashboard:edit'. ucfirst($property),
array('form' => $form)
);
return $response;
}
/**
* Edit Title property for Object
* #Template
*/
public function editTitleAction($form)
{
return array('form' => $form->createView());
}
Yaml Routing:
acme-demo-dashboard-edit:
path: /dashboard/edit/{property}/{id}
defaults: { _controller: AcmeDemoBundle:Dashboard:edit }
requirements:
acme-demo-dashboard-edit-title:
path: /dashboard/forward/edit/title/{form}
defaults: { _controller: AcmeDemoBundle:Dashboard:editTitle }
Edit: More info about the error :
at twig_array_merge (null, array('_locale' => 'en'))
Edit2: Twig Template for editTitle
{% extends "AcmeDemoBundle::layout.html.twig" %}
{% trans_default_domain "AcmeDemoBundle" %}
{% block AcmeBundleContent %}
<div class="col-sm-12">
<div class="alert alert-info">
{{ (ycRoute~'.intro') | trans }}
</div>
{{ form_start(form, { 'attr': {'class': 'form-horizontal', 'role': 'form'}}) }}
{% if form_errors(form) %}
<div class="alert alert-danger">
{{ form_errors(form) }}
</div>
{% endif %}
<div class="form-group {% if form_errors(form.title) %}has-error{% endif %}">
{{ form_label(form.title, '', {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
<div class="col-sm-9">
{{ form_widget(form.title, { 'attr': {'class': 'form-control', 'placeholder': (ycRoute~'.titre') } }) }}
<p class="help-block">{{ form_errors(form.title) }}</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
{{ form_widget(form.save, { 'attr': {'class': 'btn btn-primary'} }) }}
</div>
</div>
<div class="row">
<div class="col-sm-9 col-sm-offset-3">
(<i class="fa fa-asterisk yc-fa-sm"></i>) {{ (ycRoute~'.champRequis')|trans }}
</div>
</div>
{{ form_end(form)}}
</div>
{% endblock AcmeBundleContent %}
Did you try such syntax to render template? You will need remove #Template annotation.
return $this->render(
'AcmeDemoBundle:Dashboard:edit'. ucfirst($property),
array('form' => $form)
);
"forward" used for forwards the request to another controller.

Label collection rendered incorrectly

I have the following form where questionaire.Questions is a collection of QuestionType which is just a yes/no <select>.
Here's what the twig looks like:
Expected:
{{ form_start(questionaire) }}
{% for question in questionaire.Questions %}
<div class="question">
{{ form_label(question) }}
</div>
<div>
{{ form_widget(question) }}
</div>
{% endfor %}
{{ form_end(questionaire) }}
However it gets rendered like this:
<div class="question">
//This is where I want the label. But instead I get this:
<label></label>//Unsure why it's empty. Maybe it's questionaire.Question's label?
</div>
<div>
<label>lorem ipsum...</label> //Wrong place. Label gets rendered here instead.
<select>...</select> //Selection widget is correctly rendered.
</div>
I think the label is getting rendered along with the widget. Here's my QuestionType just in case.
class QuestionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
$question = $event->getData();
$form = $event->getForm();
$form->add('Answer', 'choice', array(
'label' => $question->getQuestion(),
'choices' => array(
'' => 'Select One',
'Yes',
'No'
)
)
);
}
);
}
...
}
How can I get the label to where I want it?
You have to call the form_widget and form_label for the answer type
{{ form_label(question.Answer) }}
{{ form_widget(question.Answer) }}
You need to define the block question_row in a form theme, and use {{ form(questionaire_form) }} to render the entire form.
Acme/DemoBundle/Form/Type/QuestionType.php
// ...
public function getName(){
return 'question';
}
// ...
Acme/DemoBundle/Controller/DefaultController.php
// ...
public function questionaireAction(){
$form = $this->createForm(new BriefQuestionaireType());
return $this->render('AcmeDemoBundle:Default:brief_questionaire.html.twig', array(
'questionaire_form' => $form->createView()
));
}
// ...
Acme/DemoBundle/Resources/views/Default/brief_questionaire.html.twig
<html>
<head>
<title>Questionaire</title>
</head>
<body>
{% form_theme questionaire_form 'AcmeDemoBundle:Form:form.html.twig' %}
{{ form(questionaire_form) }}
</body>
</html>
Acme/DemoBundle/Resources/views/Form/form.html.twig
We create a block named [block_prefix]_row, where block_prefix is derived from getName() in QuestionType above. When this form theme is used, all QuestionType rows are rendered this way.
{% block question_row %}
<div class="question">
{{ form_label(form) }}
</div>
<div>
{{ form_widget(form) }}
{{ form_error(form) }}
</div>
{% endblock %}

Pre-populating form values in Symfony2 / Twig

Im new to Symfony2 / twig and I need to render a form with pre-saved values.
I can get the form to load / save data but I cant get it to show the pre-saved values. What am I missing?
Here is my controller code:
/**
* #Route("/build/{id}")
* #Template()
*/
public function buildAction($id)
{
$request = $this->getRequest();
$em = $this->getDoctrine()->getEntityManager();
$repo = $em->getRepository('ImagineNewsletterBundle:Section');
$section = $repo->find($id);
$newsletter = $section->getNewsletter();
$globalMag = $newsletter->getMagazine();
//$globalMag = unserialize($globalMag[0]);
$builder = $this->get('newsletter.builders')->getBuilder($section->getBuilder());
$builder->setSearchUrl($this->generateUrl('imagine_newsletter_section_search', array('builder' => $section->getBuilder())));
$form = $this->createForm($builder->getSearchFormBuilder());
$prevArticles = $section->getArticles();
// $form->bind($prevArticles);
return $this->render('ImagineNewsletterBundle:Section:'.$builder->getTemplate() , array('prevArticles' => $prevArticles,'builder' => $builder, 'form' => $form->createView(), 'section' => $section, 'newsletter' => $newsletter, 'globalmag' => $globalMag));
}
Here my twig/form code:
<form id="advert" action="{{ addAticle }}" method="post" {{ form_enctype(form) }} class="form-stacked">
<div class="form_element">
{{ form_label(form.topLogoAdvert) }}
{{ form_errors(form.topLogoAdvert) }}
{{ form_widget(form.topLogoAdvert) }}
</div>
<div class="form_element">
{{ form_label(form.topLogoAlt) }}
{{ form_errors(form.topLogoAlt) }}
{{ form_widget(form.topLogoAlt) }}
</div>
<div class="form_element">
{{ form_label(form.topLogoLink) }}
{{ form_errors(form.topLogoLink) }}
{{ form_widget(form.topLogoLink) }}
</div>
<input type="hidden" name="section" value="{{ section.id }}" />
{{ form_widget(form) }}
<div class="well">
<button type="submit" class="btn primary">Save</button>
<button id="reset" type="reset" class="btn">Reset</button>
</div>
{{ form_rest(form) }}
</form>
You need to bind the form to the request, that will then populate the form with the data the user entered. I have updated your code.
$request = $this->getRequest();
$em = $this->getDoctrine()->getEntityManager();
$repo = $em->getRepository('ImagineNewsletterBundle:Section');
$section = $repo->find($id);
$builder = $this->get('newsletter.builders')->getBuilder($section->getBuilder());
$builder->setSearchUrl($this->generateUrl('imagine_newsletter_section_search', array('builder' => $section->getBuilder())));
$form = $this->createForm($builder->getSearchFormBuilder(), $section);
if ($request->isMethod('post')) {
$form->bind($request);
}
return $this->render('ImagineNewsletterBundle:Section:'.$builder->getTemplate() , array('builder' => $builder, 'form' => $form->createView(), 'section' => $section));
You also need to ensure that when the form is submitted by the user that it goes to the action that output the form. I suspect now that you have a separate action to process the form.
Create a custom FormType http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html
Fill your entity with the data you want and pass it to the form. (From database/staticly/api/etc.)
Then follow this existing answer on how to get data from the entity to the form so that when you display the form you can create existing values: How to pass entity atribute value to form Symfony2? Of course instead of the attribute type you make it a default choice.

Symfony/Silex: Form submission does nothing (no errors, nothing returned)

I'm using the most recent version of Silex (without the .phar) with Doctrine DBAL installed, on this signup form page.
If I enter invalid details, it returns to that form as excepted. But if the details are valid, instead of redirecting to the /success/ page, it returns the same form again like nothing happened. The database has no entry received and Apache error log doesn't report any problems.
<?php
// ...
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Yaml\Parser;
use Silex\Provider\FormServiceProvider;
use Symfony\Component\Validator\Constraints as Assert;
// ...
$app->match('/signup/', function(Request $request) use($app, $page) {
$data = array('name' => 'John','surname' => 'Smith','telephone' => '00011112222');
$form = $app['form.factory']->createBuilder('form', $data)
->add('name', 'text', array(
'constraints' => array(
new Assert\NotBlank(),
new Assert\MinLength(2),
),
'invalid_message' => 'First name is too short, It should have 2 characters or more',
))
->add('surname', 'text', array(
'constraints' => array(
new Assert\NotBlank(),
new Assert\MinLength(2),
),
'invalid_message' => 'Surname is too short, It should have 2 characters or more',
))
->add('telephone', 'text', array(
'constraints' => array(
new Assert\NotBlank(),
new Assert\Regex("/[\d\-\ ]+/"),
new Assert\MinLength(11),
),
'invalid_message' => 'Please enter a valid phone number. Must have 11 digits and may contain dashes (-) or spaces.',
))
->getForm();
if ('POST' == $request->getMethod()) {
$form->bindRequest($request);
if ($form->isValid()) {
$data = $form->getData();
$app['db']->insert('signups', array(
'forename' => $data['name'],
'surname' => $data['surname'],
'telephone' => $data['telephone']
));
return $app->redirect('/success/');
}
}
$page['form'] = $form->createView();
return $app['twig']->render('signup.html.twig', $page);
}, 'POST|GET');
$app->match('/success/', function() use($app, $page) {
return $app['twig']->render('success.html.twig', $page);
}, 'POST|GET');
And the twig form
<form class="well" action="/signup/" method="post">
<fieldset>
<div class="control-group">
{% if (form_errors(form.name)) or (form_errors(form.surname)) or (form_errors(form.telephone)) %}
<div class="error-in-form">
<h5 style="color:#c00;">Please review the following errors:</h5>
<br />
<div>
<p class="help-msg"><span>First Name: </span></p>
<div class="error-msg">{{ form_errors(form.name) }}</div>
<div class="clearfix"></div>
</div>
<div>
<p class="help-msg"><span>Surname: </span></p>
<div class="error-msg">{{ form_errors(form.surname) }}</div>
<div class="clearfix"></div>
</div>
<div>
<p class="help-msg"><span>Telephone: </span></p>
<div class="error-msg">{{ form_errors(form.telephone) }}</div>
<div class="clearfix"></div>
</div>
</div>
{% endif %}
{{ form_label(form.name) }}
<div class="controls">
{{ form_widget(form.name, { 'attr': { 'class': 'input-medium' } } ) }}
{{ form_widget(form.surname, { 'attr': { 'class': 'input-medium' } } ) }}
</div>
</div>
<div class="control-group">
{{ form_label(form.telephone) }}
<div class="controls">
{{ form_widget(form.telephone, { 'attr': { 'class': 'input-fullwidth' } } ) }}
</div>
</div>
<p class="tnc">If you accepts the terms and conditions below, please proceed.</p>
<button id="big-red-button" type="submit" class="btn btn-danger btn-fullwidth">Submit ></button>
</fieldset>
</form>
Well, looks like I forgot to add {{ form_rest }} to the Twig form template.
Since I hadn't also included {{ form_errors(form) }} either, I couldn't see the error regarding the missing CSFP token, a hidden field that gets added to the form.

Resources