I'm using the bundle Omines to create DataTables in Symfony 5 and I've written a custom query. However, when I do so, the search in the view doesn't work.
How I can fix it?
This is my code:
Controller
$table = $dataTableFactory->create()
->add('fullName', TextColumn::class, [
'label' => 'Full Name',
'propertyPath' => '[fullName]',
'searchable' => true,
])
->createAdapter(ORMAdapter::class, [
'entity' => Person::class,
'hydrate' => AbstractQuery::HYDRATE_ARRAY,
'query' => function (QueryBuilder $builder) {
$builder
->select('p.id, CONCAT(p.firstName, \' \', p. middleName, \' \', p.lastName) AS fullName')
->from(Person::class, 'p');
},
])
->handleRequest($request);
if ($table->isCallback()) {
return $table->getResponse();
}
return $this->render('person/index.html.twig', [
'datatable' => $table,
]);
datatables.html.twig
{% extends 'base.html.twig' %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs5/jq-3.6.0/dt-1.11.2/b-2.0.0/fh-3.1.9/r-2.2.9/datatables.min.css"/>
{% endblock %}
{% block javascripts %}
<script type="text/javascript" src="https://cdn.datatables.net/v/bs5/jq-3.6.0/dt-1.11.2/b-2.0.0/fh-3.1.9/r-2.2.9/datatables.min.js"></script>
<script src="{{ asset('bundles/datatables/js/datatables.js') }}"></script>
<script>
$(function () {
$('#table').initDataTables({{ datatable_settings(datatable) }}, {
searching: true,
fixedHeader: true,
responsive: true,
});
});
</script>
{% endblock %}
index.html.twig
{% extends 'datatables.html.twig' %}
{% block title %}List{% endblock %}
{% block body %}
<div id="table">Loading...</div
{% endblock %}
EDIT
The search term is the fullName alias. I've tried with custom criteria_query like this:
->createAdapter(ORMAdapter::class, [
'entity' => Person::class,
'hydrate' => AbstractQuery::HYDRATE_ARRAY,
'query' => function (QueryBuilder $builder) {
$builder
->select('p.id, CONCAT(p.firstName, \' \', p. middleName, \' \', p.lastName) AS fullName')
->from(Person::class, 'p');
},
'criteria' => [
function (QueryBuilder $builder) {
$builder->andWhere($builder->expr()->like('CONCAT(p.firstName, \' \', p.middleName, \' \', p.lastName)', ':fullName'))->setParameter('fullName', '%%');
},
new SearchCriteriaProvider(),
],
])
but I'm not sure how to retrieve the value of the datatable search field to be used as a parameter in '%%'
Solution:
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter;
use Omines\DataTablesBundle\DataTableState;
....
->createAdapter(ORMAdapter::class, [
'entity' => Person::class,
'hydrate' => AbstractQuery::HYDRATE_ARRAY,
'query' => function (QueryBuilder $builder) {
$builder
->select('p.id, CONCAT(p.firstName, \' \', p. middleName, \' \', p.lastName) AS fullName')
->from(Person::class, 'p');
},
'criteria' => [
function (QueryBuilder $builder, DataTableState $state) {
$term = strtolower($state->getGlobalSearch());
$builder->andWhere($builder->expr()->like('LOWER(CONCAT(p.firstName, \' \', p.middleName, \' \', p.lastName))', ':fullName'))->setParameter('fullName', '%' . $term . '%');
},
new SearchCriteriaProvider(),
],
])
Related
I need to create a form adding faculty to the database. First, the user selects a region from the list ( / ChoiceType), then the city of this region from the following list, the university, and finally enters the name of the faculty. The default values are the first region from the database, its first city and first university.
Sending the page with default data works, the choice of the region works, but the the choice of the city return to 500 status
Form:
Twig and ajax:
{% extends 'admin/insert/insert.html.twig' %}
{% block title %}Add Faculty{% endblock %}
{% block body %}
<div class="insert">
<h1 class="insert__title">Add Faculty</h1>
{{ form_start(insert_faculty, { 'attr' : {'class' : 'insert__form'} }) }}
{% for message in app.flashes('success') %}
<div class="insert__success">
{{ message }}
</div>
{% endfor %}
<div class="insert__errors">
{{ form_errors(insert_faculty) }}
</div>
{{ form_label(insert_faculty.region, 'Region:', { 'label_attr' : {'class' : 'insert__label'} }) }}
{{ form_widget(insert_faculty.region, { 'attr' : {'class' : 'insert__input'} }) }}
{{ form_label(insert_faculty.city, 'City:', { 'label_attr' : {'class' : 'insert__label'} }) }}
{{ form_widget(insert_faculty.city, { 'attr' : {'class' : 'insert__input'} }) }}
{{ form_label(insert_faculty.university, 'University:', { 'label_attr' : {'class' : 'insert__label'} }) }}
{{ form_widget(insert_faculty.university, { 'attr' : {'class' : 'insert__input'} }) }}
{{ form_label(insert_faculty.name, 'Name:', { 'label_attr' : {'class' : 'insert__label'} }) }}
{{ form_widget(insert_faculty.name, { 'attr' : {'class' : 'insert__input insert__input_name'} }) }}
<button type="submit" class="insert__button">Save</button>
{{ form_end(insert_faculty) }}
<div class="insert__buttons">
Back
</div>
</div>
{% block javascripts_footer %}
{{ parent() }}
<script>
let $region = $('#insert_faculty_region');
$region.change(function() {
let $form = $(this).closest('form');
let data = {};
data[$region.attr('name')] = $region.val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(get) {
$('#insert_faculty_city').html(
$(get).find('#insert_faculty_city').html()
);
$('#insert_faculty_university').html(
$(get).find('#insert_faculty_university').html()
);
}
});
});
let $city = $('#insert_faculty_city');
$city.change(function() {
let $form = $(this).closest('form');
let data = {};
data[$city.attr('name')] = $city.val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(get) {
$('#insert_faculty_university').html(
$(get).find('#insert_faculty_university').html()
);
}
});
});
</script>
{% endblock %}
{% endblock %}
Form class:
class InsertFacultyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('region', ChoiceType::class, [
'choices' => $options['regions_array'],
'mapped' => false,
])
->add('city', ChoiceType::class, [
'choices' => null,
'mapped' => false,
])
->add('university', ChoiceType::class, [
'choices' => null,
])
->add('name')
;
$formModifier = function (FormInterface $form, $entity_parent) {
if (get_class($entity_parent) === 'App\Entity\Region') {
if (!$entity_parent->getCities()->count()) {
$form->add('city', ChoiceType::class, [
'choices' => null,
'mapped' => false,
]);
}
else {
$cities_in_database = $entity_parent->getCities();
foreach ($cities_in_database as $city) {
$cities[$city->getName()] = $city;
}
$form->add('city', ChoiceType::class, [
'choices' => $cities,
'mapped' => false,
]);
}
}
else if (get_class($entity_parent) === 'App\Entity\City') {
if (!$entity_parent->getUniversities()->count()) {
$form->add('university', ChoiceType::class, [
'choices' => null,
]);
}
else {
$university_in_database = $entity_parent->getUniversities();
foreach ($university_in_database as $university) {
$universities[$university->getName()] = $university;
}
$form->add('university', ChoiceType::class, [
'choices' => $universities,
]);
}
}
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($options, $formModifier, $builder) {
$region = $options['regions_array'][array_key_first($options['regions_array'])];
$city = $region->getCities()[0];
$formModifier($event->getForm(), $region);
$formModifier($event->getForm(), $city);
}
);
$builder->get('region')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$region = $event->getForm()->getData();
$city = $region->getCities()[0];
$formModifier($event->getForm()->getParent(), $region);
$formModifier($event->getForm()->getParent(), $city);
}
);
$builder->get('city')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$city = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $city);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Faculty::class,
'regions_array' => null,
]);
$resolver->setAllowedTypes('regions_array', 'array');
}
}
Controller:
/**
* #Route("/admin/insert/faculty", name="faculty")
*/
public function faculty(Request $request)
{
$regions_in_database = $this->getDoctrine()->getRepository(Region::class)->findAll();
$regions = [];
foreach ($regions_in_database as $region) {
$regions[(string)$region->getName()] = $region;
}
$faculty = new Faculty();
$insert_faculty = $this->createForm(InsertFacultyType::class, $faculty, [
'regions_array' => $regions,
]);
if (!$regions_in_database) {
$insert_faculty->addError(new FormError("There are no regions!"));
}
$insert_faculty->handleRequest($request);
if ($insert_faculty->isSubmitted() && $insert_faculty->isValid()) {
$repository = $this->getDoctrine()->getRepository(University::class);
$faculty_in_database = $repository->findOneBy(
[
'name' => $faculty->getName(),
'university' => $faculty->getUniversity(),
]
);
if ($faculty_in_database) {
$insert_faculty->addError(new FormError('Such a faculty is already in the database!'));
}
else {
$faculty->setRating(0);
if(!$faculty->getUniversity()) {
$insert_faculty->addError(new FormError("Select the university!"));
}
else {
$entity_manager = $this->getDoctrine()->getManager();
$entity_manager->persist($faculty);
$entity_manager->flush();
$this->addFlash(
'success',
'Faculty "' . $faculty->getName() . '" successfully saved!'
);
}
}
}
return $this->render('admin/insert/faculty/faculty.html.twig', [
'insert_faculty' => $insert_faculty->createView(),
]);
}
I invite you to use the Symfony debug toolbar. It will allow you to see the different problems associated with your code and give much more information about the problems that appear.
Profiler Symfony
About your problem, I think it is necessary to debug at the level of what your form sends to your application. But if you want more help, you must provide the error message that come with your 500 error.
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.....
I've worked through a few of the Forms-Tutorials on the Symfony-Page (especially How to Embed a Collection of Forms, How To use a Form without a Dataclass & CollectionType Field ).
I'm trying to show a form with multiple lead partners which can be edited and submitted back to the system.
But i get a Twig_Runtime_Error saying: ''Variable "lead_partners" does not exist''.
My Twig:
{% block content %}
<div>
{{ form_start(form) }}
{% for partner in lead_partners %}
{{ form_row(partner.name) }}
{% endfor %}
{{ form_end(form) }}
</div>
{% endblock content %}
My Controller Code:
public function overview(Request $request, \App\Utility\LeadPartnerLoader $LeadPartnerLoader)
{
$leadPartnerList = $LeadPartnerLoader->loadAll();
$form = $this->createFormBuilder($leadPartnerList)
->add('lead_partners', CollectionType::class, [
'entry_type' => LeadPartnerFormType::class,
])->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
$data = $form->getData();
}
return $this->render(
'lead_partner_overview2.html.twig',
[
'form' => $form->createView()
]);
}
And the Form Type (LeadPartnerFormType):
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => LeadPartner::class,
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', HiddenType::class)
->add('name', TextType::class);
}
$leadPartnerList is of type array.
What am i doing wrong/missing here?
Kind Regards
It seems your action overview soesn't return the lead_partners variable you use in your template.
You can try to do this
return $this->render(
'lead_partner_overview2.html.twig',
[
'form' => $form->createView(),
'lead_partners' => $leadPartnerList, // I gess that's the list you want to loop ?
]);
i have a problem when i insert date from calender using jquery !there is a problem of conversion i think .
II try to use
{{ form_widget(form.dateArrivage|date("m/d/Y") , {'attr': {'class': 'from'}}) }}<br>
but :
An exception has been thrown during the rendering of a template
Catchable Fatal Error: Object of class Symfony\Component\Form\FormView could not be converted to string
in GestionHotelBundle:Default:index.html.twig at line 147.
this is ReservationType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('dateArrivage',DateTimeType::class, array(
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'attr' => array('class' => 'date')
))
->add('dateSortie',DateTimeType::class, array(
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'attr' => array('class' => 'date')
))
->add('nbjour')
->add('dateReser',DateType::class)
->add('chambres', CollectionType::class, array(
'entry_type' => ChambreType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
->add('save',SubmitType::class)
;
;
}
and this is the vue :
<script>
$( function() {
var dateFormat = "mm/dd/yy",
from = $( ".from" )
.datepicker({
defaultDate: "+1w",
changeMonth: true,
numberOfMonths: 2
})
.on( "change", function() {
to.datepicker( "option", "minDate", getDate( this ) );
}),
to = $( ".to" ).datepicker({
defaultDate: "+1w",
changeMonth: true,
numberOfMonths: 2
})
.on( "change", function() {
from.datepicker( "option", "maxDate", getDate( this ) );
});
function getDate( element ) {
var date;
try {
date = $.datepicker.parseDate( dateFormat, element.value );
} catch( error ) {
date = null;
}
return date;
}
} );
{{ form_start(form) }}
{{ form_label(form.dateArrivage) }}
{{ form_errors(form.dateArrivage) }}
{{ form_widget(form.dateArrivage , {'attr': {'class': 'from'}}) }}<br>
<br><br>
{{ form_label(form.dateSortie) }}
{{ form_errors(form.dateSortie) }}
{{ form_widget(form.dateSortie, {'attr': {'class': 'to'}}) }}<br><br>
<br><br>
{{ form_row(form.nbjour) }}
{{ form_row(form.dateReser) }}
Doc says :
If you want your field to be rendered as an HTML5 "date" field, you
have to use a single_text widget with the yyyy-MM-dd format (the RFC
3339 format) which is the default value if you use the single_text
widget.
So you have to change date format into your form builder:
$builder
->add('dateArrivage',DateTimeType::class, array(
'date_widget' => 'single_text',
'date_format' => 'yyyy-MM-dd', //here
))
->add('dateSortie',DateTimeType::class, array(
'date_widget' => 'single_text',
'date_format' => 'yyyy-MM-dd', //and here
))
Set the dateformat option in the jQuery-UI datepicker :
$(".from").datepicker({ dateFormat:'mm/dd/yy'})
Nothing else. You don't need to parse the date yourself.
Other mistake you have :
DateTimeType must not use format and widget options but date_format, date_widget, time_format and time_widget options ...
Because the jQuery plugin doesn't care about time. It can only be applied on the date part.
http://symfony.com/doc/current/reference/forms/types/datetime.html#date-format
i need your help please , I want to display my created form in Symfony2. I want to display my created form 92 times becouse i have 92 numbers in my database(every number is a form) , i didn't know how to do it here is my code:
controller:
class DefaultController extends Controller
{
public function QuestionsAction(Request $request)
{
$questions = $this->getDoctrine()->getEntityManager()
->getRepository('Tests\TestsPhpBundle\Entity\Question')
->findAll();
$task = new Question();
$forms = $this->createForm(new QuestionType(), $task);
if ($request->getMethod() == 'POST') {
$forms->bindRequest($request);
if ($forms->isValid())
{
$em = $this->getDoctrine()->getEntityManager();
$em->persist($task);
$em->flush();
}
}
{
return $this->render('TestsTestsPhpBundle:Default:index.html.twig', array(
'questions' => $questions,
'forms' => $forms->createView()
));
}
}
}
my form file:
class QuestionType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('categories', null, array('required' => false,
))
->add('text', 'entity', array(
'class' => 'TestsTestsPhpBundle:Question',
'query_builder' => function($repository) {
return $repository->createQueryBuilder('p')->orderBy('p.id', 'ASC'); },
'property' => 'text'))
;
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Tests\TestsPhpBundle\Entity\Question',);
}
public function getName()
{
return 'question';
}
}
my twig file:
{% block content %}
<h2>Questions</h2>
{% for question in questions %}
<dl>
<dt>Number</dt>
<dd>{{ question.number }}<dd>
{% for form in forms %}
{{ form_row(forms.categories) }}
{{ form_row(forms.text) }}
</dl>
{% endfor %}
<hr />
{% endfor %}
{% endblock %}
I recommend to read capter: Embedding Controller
http://symfony.com/doc/2.0/book/templating.html
<div id="sidebar">
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>
You can make a for loop within Twig Template and call an action (with parameter if needed) where you render the form. -> QuestionsAction in your case.