for a few days I am blocked, if someone can help me with the good practice, I explain:
I want to retrieve data from the database: entity (expression_besoin) contains the information of a purchase with ref , requester ... and the entity besoin_article contains the items products in the previous entity, there is a OneToMany relationship between the two entities.
the objective is to retrieve the several expression needs of articles in a form in order to modify whether the quantities are necessary or to delete them, then to be able to generate a PDF file which contains all the needs and the articles which correspond to them.
Controller :
/**
* #Route("/extraire_commandes", name="export_commandes", methods={"GET","POST"})
*/
public function exportCommandes(ExBesoinRepository $exBesoinRepository, Request $request): Response
{
$datas = new FiltreBesoin();
$form = $this->createForm(FiltreBesoinType::class, $datas);
$form->handleRequest($request);
$exBesoin = $exBesoinRepository->exportCommande($datas);
$valueFournisseur = $form['fournisseur']->getData();
$formExport = $this->createFormBuilder(array('besoin' => $exBesoin));
$formExport->add('besoin', CollectionType::class, array(
'entry_type' => ExBesoinToCommandeType::class,
));
$formExport = $formExport->getForm();
$formExport->handleRequest($request);
$formValue = $formExport->getData();
if ($formExport->isSubmitted() && $formExport->isValid()) {
$html = $this->renderView('admin/besoins/epicerie/exportPdf.html.twig', [
'besoins' => $formValue,
]);
$html .= '<link rel="stylesheet" href="/build/css/app.css"> ';
$html .= '<script src="/build/vendors~js/app.js"></script><script src="/build/runtime.js"></script><script src="/build/vendors-node_modules_popperjs_core_lib_index_js-node_modules_symfony_stimulus-bridge_dist_ind-f4bfca.js"></script>';
$name = 'test';
$options = new Options();
$options->set('isHtml5ParserEnabled', true);
$options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);
$dompdf->loadHtml($html);
// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'portrait');
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to Browser
$dompdf->stream($name, array('Attachment' => 0));
return new Response('', 200, [
'Content-Type' => 'application/pdf',
]);
}
return $this->render('admin/besoins/epicerie/export.html.twig', [
'besoins' => $exBesoin,
'form' => $form->createView(),
'valueFournisseur' => $valueFournisseur,
//'idBesoin' => $idBesoin,
'formExport' => $formExport->createView(),
'valu'=> $formValue
]);
}
FormType
class ExBesoinToCommandeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('besoinArs', CollectionType::class, [
'entry_type' => BesoinArToCommandeType::class,
'allow_delete' => true,
//'allow_add' => false,
'prototype' => true,
'by_reference' => false,
'delete_empty' => true,
'entry_options' => [
'label' => true,
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ExBesoin::class,
]);
}
public function getBlockPrefix()
{
return 'ExBesoinToCommandeType';
}
}
class BesoinArToCommandeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('article', EntityType::class, [
'class' => Article::class,
'label' => false,
'attr' =>[
'class' => 'arSelect form-control-sm',
'data-live-search' => 'true',
],
'placeholder' => 'Selectionner un article ',
'query_builder' => function (EntityRepository $er) {
$qb = $er->createQueryBuilder('a')
->innerJoin('a.category', 'c')
->where('c.is_legume = 0')
;
return $qb;
},
'group_by' => function (Article $article) {
return $article->getCategory()->getLibele();
}
])
->add('quantity', TextType::class, [
'label' => ' ',
'attr' =>[
'class' => 'quantity form-control-sm'
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => BesoinAr::class,
]);
}
public function getBlockPrefix()
{
return 'BesoinArToCommandeType';
}
}
Until I get my data back without problem, the getData() of the form contains all my data before the submit, but when I validate to generate my pdf file, it does not contain all the data. I use a filter system that allows me to select the expressions of need between two dates, by requester or by supplier, and the problem is linked to this filter because when I generate the pdf of the data without filter it works but when I filter my data this is where my data changes and I don't recover the filtered data, I will be grateful if someone unblocks me or tell me where the problem comes from.
Related
I am using symfony 6 with everything updated to date.
I created a form type with which I intend to receive a url or an image and internally transform the image into a url that will indicate where it is stored on the server, or keep the given url. The idea is to be able to receive one or the other (url or file) and only return as data the new url.
Here is my code:
parent form
class EditProfileForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('imgProfile', ImageType::class, [
'required' => false,
'label' => "Profile Image",
'bucket' => 'tw-user-files',
'key' => $options["key"],
'constraints' => [
new File([
'maxSize' => '7M',
'mimeTypes' => [
'image/*'
],
'mimeTypesMessage' => 'That is not a valid image format',
])
],
'setter' => function (User &$user, string $data, FormInterface $form): void {
$user->setImgProfile($data);
}
])
;
}
}
ImageType
class ImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$bucketName = $options["bucket"];
$bucket = $this->flySystemS3->getBucket($bucketName);
$constraints = $options["constraints"];
$builder->add('url', UrlType::class, [
'error_bubbling' => false,
'required' => false,
])
->add('file', FileType::class, [
"error_bubbling" => false,
"multiple" => false,
'required' => false,
'attr' => [
'accept' => 'image/*'
],
'constraints' => $constraints
])
->addViewTransformer(new UrlOrFileToImage($bucket, $options["key"]));
}
}
Data tranformer
class UrlOrFileToImage implements DataTransformerInterface
{
public function transform($value)
{
return [
"url" => "",
"file" => null
];
}
public function reverseTransform($value)
{
if (!empty($value["url"])) {
return $value;
}
if (!empty($value["file"])) {
return $this->fileToImage($value["file"]);
}
return "#";
}
private function fileToImage(UploadedFile $file): string
{
$fileName = $this->uploadToServer();
return $fileName;
}
}
the situation is that when validating the parent form I get the error "The file could not be found.", this only happens when validating the parent form, the child form "ImageType" passes all validations and does not generate error.
I debugged it step by step and when I debug it, it passes correctly, the validation is correct and returns everything ok. So I think it is some validation that takes too long, and at the time of debugging gives it a chance to validate it, and when I let it run the code, the validation fails.
Can I specify how the form field shold be mapped on data class?
Let's say I have form with check box and on my data entity the field is stored as string.
class FormType extends AbstractType {
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => DataEntity::class,
]);
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('issueType', CheckboxType::class, [
'label' => 'issueType',
]);
}
}
class DataEntity {
/** #var string Either PLASTIC or PAPER */
private $issueType;
public function getIssueType() {
return $this->issueType;
}
public function setIssueType($issueType) {
$this->issueType = $issueType;
}
}
Can I made the checkbox to be mapped as 'PLASTIC' if ture and 'PAPER' if false?
You can use data transformer to cast bolean to the string. See this tutorial: https://symfony.com/doc/current/form/data_transformers.html.
$builder->get('issueType')
->addModelTransformer(new CallbackTransformer(
function ($type) {
// your logic here
return $type;
},
function ($type) {
// your logic here
return $type;
}
));
try :
$builder->add('newsletter', 'choice', array(
'label' => 'Newsletter erhalten',
'attr' => array(
'class' => 'form-control',
),
'choices' => array(array('yes' => 'plastic'), array('no' => 'paper')),
'expanded' => true,
'multiple' => true,
'required' => false,
));
also check the answer here Symfony2 Change checkbox values from 0/1 to 'no'/'yes'
I am using React on the frontend to send data to the controller which uses Symfony Form for validation. The information sent from React is what I expect but I am getting an error that says "This form should not contain extra fields".
I want to create a new Booking using this form, which has a Reservation. A Reservation has many (or none) reservationTripAddOns (TripAddOns). I have figured out that the problem is caused when I select trip add on((TripAddOn::class) reservationTripAddOn) that I want linked to reservation. When I do not select any add on, it works.
Data passed from React when no add ons are selected and works:
{
"reservations”:
[
{
"trip":277,
"date":"10/27/2017”,
"guests":2,
"reservationTripAddOns":[]
}
]
}
Data passed from React when add ons are selected and does not work:
{
"reservations”:
[
{
"trip":277,
"date":"10/26/2017”,
"guests":2,
"reservationTripAddOns”:
[
{
"id":34,
"name":"Additional one guest”,
"price":100,
"trip”:null
}
]
}
]
}
BookingController:
public function newAction(Request $request, GuideProfile $guideProfile)
{
$reservation = new Reservation();
$booking = new Booking();
$booking->addReservation($reservation);
$form = $this->createForm(BookingType::class, $booking, ['guide_profile' => $guideProfile]);
$form->submit(json_decode($request->getContent(), true));
if ($form->isValid()) {
$context = new SerializationContext();
$context->setSerializeNull(true);
$context->setGroups(['Session']);
$this->get('session')->set(
'booking', $this->get('serializer')->serialize($booking, 'json', $context)
);
return $this->createApiResponse($booking, ['Default'], 201);
}
return $this->createApiErrorResponse($form->getErrors(true));
}
BookingType:
class BookingType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reservations', CollectionType::class, [
'entry_type' => ReservationType::class,
'entry_options' => [
'data_class' => Reservation::class,
'guide_profile' => $options['guide_profile'],
],
'allow_add' => true,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Booking::class,
'guide_profile' => null,
]);
}
}
ReservationType:
class ReservationType extends AbstractType
{
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$guideProfileId = $options['guide_profile'] instanceof GuideProfile ? $options['guide_profile']->getId() : 0;
$builder
->add('trip', EntityType::class, [
'class' => Trip::class,
'query_builder' => function (EntityRepository $er) use ($guideProfileId) {
return $er->createQueryBuilder('t')
->where('t.guideProfile = :guide_profile_id')
->orderBy('t.title', 'ASC')
->setParameter('guide_profile_id', $guideProfileId);
},
'choice_label' => 'title',
'placeholder' => 'Select a Trip',
])
->add('date', DateType::class, [
'format' => 'MM/dd/yyyy',
'html5' => false,
'widget' => 'single_text',
])
->add('reservationTripAddOns', 'collection', [
'entry_type' => TripAddOnType::class,
'entry_options' => [
'data_class' => TripAddOn::class,
'mapped' => false,
]
])
->addEventListener(FormEvents::PRE_SET_DATA, [$this, 'addGuests'])
;
}
public function addGuests(FormEvent $event)
{
//assume everything works here
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Reservation::class,
'guide_profile' => null,
]);
}
TripAddOnType:
class TripAddOnType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('price', TextType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\TripAddOn'
]);
}
I can not get value from EntityType. I have last version 3.3.6.
class BuildType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array
$options)
{
$builder
->add('title', TextType::class)
->add('save', SubmitType::class, array('label' => 'Create Post'))
->add('team', CollectionType::class, array(
// each entry in the array will be an "email" field
'entry_type' => TeamType::class,
// these options are passed to each "email" type
'entry_options' => array(
'attr' => array('class' => 'form-control'),
),
'label' => false,
'allow_add' => true,
'prototype' => true,
'mapped' => false
));
}
}
class TeamType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array
$options)
{
$builder
->add('name', EntityType::class, array(
'placeholder' => 'Choice a champ',
'required' => true,
'class' => 'AppBundle:Champions',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
},
'choice_label' => 'name',
'choice_value' => 'id',
'attr' => array('class' => 'dropdown'),
));
}
I tried all but i cannot take value of 'name' of TeamType. After submission form, i do
foreach ($form["team"]->getData() as $value) {
'name' => $value['name']
but the value is empty. If i try dump request and the value is there. The other values i can get it and save in Database. Only EntityType i can not.
Someone know how do?
EntityType returns as the object. You should use model getter functions.
$form->get('name')->getData()->getId(); // getName() vs..
Here is a similar example.
symfony how get selected data from select
I suppose that you are using ManyToOne relationship.
With AJAX
if you are trying get data after submitted, You can do this first in your view:
$('#elementWhereYouAreTEAMType').find('input').each(function (i,v) {
var valTeam = $(this).val(); //take value
// adding data, create an associative array.
formData.append("team["+ i +"]", valTeam);
});
You must put formData like data argument to ajax JQuery
Now, server side:
public function createTeamNow(Request $request) {// ajax
$teams = $request->request->get('team'); // getting array
if(!is_null($teams)) {// if user added team
foreach ($teams as $team) {
// dump($team);
//create an instance for each element, it does not replace a data with the above
$teamType = new TeamType();
$teamName->setName($team);
$this->em->persist($teamType);
}
}
}
Without AJAX
/**
* #Route("/slim/1" , name="data_x")
*/
public function slimExampleAction(Request $request)
{
$form = $this->createForm(TeamType::class);
$form->handleRequest($request);
if ($form->isSubmitted() /*&& $form->isValid()*/) {
// When you've ManyToOne relationship, that field returns ArrayCollection class, it has several method to get data on differents ways, iterate with it, for example toArray is one
$data = $form->getData();
dump($data->getDescription()->toArray());die;
}
return $this->render('AppBundle:view.html.twig', array(
'form' => $form->createView(),
));
}
I have a form that collects data from two related entities 'Jobs' and 'Scope'. Jobs data adds successfully to the database, but i can't get the scope entity to add which also requires the unique ID that was created from the jobs entry. I'm using doctrine by the way.
Here is jobsType:
class jobsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('jobNumber', null, array('label' => 'Job Number','attr' => array('placeholder'=>'Code used for job')))
->add('description', null, array('label' => 'Job Description',))
;
$builder->add('scopes', new scopeType())
;
}
public function getName()
{
return 'jobs';
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Baker\TimeSlipBundle\Entity\Jobs',
));
}
}
Here is scopeType
class scopeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description', 'entity', array('label' => 'Scope', 'required' => false,
'class' => 'BakerTimeSlipBundle:Scope',
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('s')
->orderBy('s.description', 'asc');
},
'property' => 'description',
'multiple' => false,
'expanded' => false,
'empty_value' => false,
'attr' => array('class' => 'form-inline'),
'label_attr' => array('class' => 'required')
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Baker\TimeSlipBundle\Entity\Scope',
));
}
public function getName()
{
return 'scope';
}
}
Here is my controller, i think the problem here is that i'm not passing the scope() instance to the form builder. Which i'm not sure how to do. The entity is mapped correctly.
class JobsController extends Controller
{
public function indexAction($limit, Request $request)
{
$jobs= new Jobs();
$scope = new Scope();
$fname=$limit;
$form = $this->createForm(new JobsType(),$jobs, array(
'method' => 'POST',
));
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($jobs);
$em->persist($scope);
$em->flush();
return $this->redirectToRoute('company',array ('limit' =>'Job Submitted Successfully'));
}
return $this->render(
'BakerTimeSlipBundle:Jobs:index.html.twig',
array('fname' => $fname,
'form' => $form->createView()
)
);
}
}
}
Any help here would be greatly appreciated. Below is listed the error message when I try to enter the scope:
An exception occurred while executing 'INSERT INTO Scope (description, jobsId, jobsid) VALUES (?, ?, ?)' with params [null, null, null]:
SQLSTATE[42000]: Syntax error or access violation: 1110 Column 'jobsId' specified twice
The problem here is the $jobs object you link to your form has no relation with the $scope object. So when you try to persist $jobs, Doctrine has no idea $scope it had to persist.
Just try this :
$jobs= new Jobs();
$scope = new Scope();
$jobs->setScope($scope);
Then, in your Jobs entity, on the annotation above $scopes, make sure you have cascade={"persist"} (but you must already have it because Doctrine tries to persist, and that's where the error is thrown), and you should be good to go.
Hope this helps