I want to save the form data in session in case of an error occured then I can display valid form data in my form view.
I've got a file field for an image but I've got this error when I submit my form with an image : Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
My Form Type :
class ContenuType extends AbstractType
{
private $session;
public function __construct($session)
{
$this->session = $session;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$session = $this->session;
$formSession = $session->get('dataCreateContenu');
if (!$formSession) {
$formSession = new Contenu();
}
$builder
->add('description', 'textarea', array(
'label' => 'Description',
'data' => $formSession->getDescription(),
'attr' => array('maxlength' => 560),
)
)
->add('file', 'file', array(
'label' => 'Image',
'data' => $formSession->getImage(),
'required' => false,
)
)
;
}
}
My Form Controller :
/**
* New Contenu
*
* #Route("/", name="contenu_create")
* #Method("POST")
* #Template("MyOwnBundle:Contenu:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Contenu();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
$session = $this->get('session');
$session->set('dataCreateContenu', $form->getData());
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$formAll = $form->all();
foreach ($formAll as $formField) {
if(empty($formField->getData())) {
$this->get('session')->getFlashBag()->add('error', 'Field « '.$formField->getConfig()->getOption("label").' » is empty.');
return $this->redirect($this->generateUrl('contenu_new'));
}
}
$image = $form->get('file')->getData();
if ($image) {
$entity->upload();// Upload
}
$em->persist($entity);
$em->flush();
$session->clear();
return $this->redirect($this->generateUrl('contenu_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
What can I do ?
Related
I use Propel in a project & I try to set default value my form which uses a ModelType input and I need to set a default value stored in session in this form and where this session is not null for the stored value used in this functionnality.
This is my form :
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
'name' => 'profile_variety_search',
'locales' => ['fr'],
'session' => null
));
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', ModelType::class, array(
'class' => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
'query' => ProfileVarietyQuery::create()->orderById(),
'property' => 'name',
'label' => 'Profil recherché',
'expanded' => false,
'multiple' => false,
'required' => false,
'placeholder' => '- Filtrer par profil -',
'attr' => array(
'onchange' => 'submit()',
'class' => 'col s3'
)
))
;
}
This is my treatment :
public function listAction(Request $request = null)
{
$pModelManager = $this->get('fcl_vitrinellis.p_model_manager');
$profileVarietyManager = $this->get('fcl_vitrinellis.profile_variety_manager');
$session = $request->getSession();
$profileVariety = new ProfileVariety();
$models = null;
$form = $this->createForm(ProfileVarietySearchType::class, $profileVariety);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (null != $form['name']->getData()) {
$models = $pModelManager->getWebsiteByModel($form['name']->getData()->getName());
$session->set('profileVarietySearch', $form['name']->getData()->getName());
} else {
$models = $pModelManager->getList();
}
} else {
if ($session->has('profileVarietySearch') && null != $session->get('profileVarietySearch')) {
$models = $pModelManager->getWebsiteByModel($session->get('profileVarietySearch'));
} else {
$models = $pModelManager->getList();
}
}
return $this->render('console\p_model_list.html.twig', array(
'objArray' => $models,
'form' => $form->createView()
));
}
I have try to set default data with 'data' option and with PRE_SET_DATA event in the form but I had satisfactory result.
In an EntityType the incoming default 'data' must be an object of the right type. I would first try to see if we have incoming form data.
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Check form data
$formDataEntity = $builder->getData();
// Check if it has the field filled in
if ($formDataEntity && $formDataEntity->getName()) {
$objToSet = $formDataEntity->getName();
} else {
$objToSet = $options['incomingDefaultObject'];
)
$builder
->add('name', ModelType::class, array(
class => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
data => $objToSet,
...
And then for the resolver
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'incomingDefaultObject' => null,
));
}
And you call the form with the default opion in the controller
$form = $this->createForm(YourType::class, $yourObject, array('incomingDefaultObject' => $nameObject));
Warning: if a user decides to leave the field empty this code will always set the default.
I have an other solution.
Create new Model which his name is ProfileVarietySearch, like this :
class ProfileVarietySearch
{
/** #var null|ProfileVariety $profileVariety */
private $profileVariety;
/**
* #return bool
*/
public function is_empty()
{
return is_null($this->profileVariety);
}
/**
* #return null|ProfileVariety
*/
public function getProfileVariety()
{
return $this->profileVariety;
}
/**
* #param $profileVariety
*
* #return ProfileVarietySearch
*/
public function setProfileVariety($profileVariety): self
{
$this->profileVariety = $profileVariety;
return $this;
}
}
In the controller, write this :
public function listAction(Request $request = null)
{
$pModelManager = $this->get('fcl_vitrinellis.p_model_manager');
$profileVarietyManager = $this->get('fcl_vitrinellis.profile_variety_manager');
$session = $request->getSession();
$profileVarietySearch = new ProfileVarietySearch();
$models = null;
if ($session->has('profileVarietySearch') && null != $session->get('profileVarietySearch')) {
$profileVarietySearch->setProfileVariety(
$profileVarietyManager->getByName($session->get('profileVarietySearch'))->getData()[0]
);
}
$form = $this->createForm(ProfileVarietySearchType::class, $profileVarietySearch);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (null != $form->getData()->getProfileVariety()) {
$models = $pModelManager->getWebsiteByModel($form->getData()->getProfileVariety()->getName());
$session->set('profileVarietySearch', $form->getData()->getProfileVariety()->getName());
} else {
$session->set('profileVarietySearch', null);
$models = $pModelManager->getList();
}
} else {
if ($session->has('profileVarietySearch') && null != $session->get('profileVarietySearch')) {
$models = $pModelManager->getWebsiteByModel($session->get('profileVarietySearch'));
} else {
$models = $pModelManager->getList();
}
}
return $this->render($this->view_list, array(
'objArray' => $models,
'form' => $form->createView()
));
}
In the ProfileVarietySearchType, write this :
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Fcl\VitrinellisBundle\Form\Model\ProfileVarietySearch',
'name' => 'profile_variety_search'
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('profileVariety', ModelType::class, array(
'class' => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
'query' => ProfileVarietyQuery::create()->orderById(),
'property' => 'name',
'label' => 'Profil recherché',
'expanded' => false,
'multiple' => false,
'required' => false,
'placeholder' => '- Filtrer par profil -',
'attr' => array(
'onchange' => 'submit()',
'class' => 'col s3'
)
));
}
my builder is
private $username;
public function __construct( $username = null) {
$this->username = $username;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('titre')
->add('description')
->add('contenu')
->add('categorie')
->add('site', 'choice', array(
'choices' => array('ALM' => 'Aujourdhui le Maroc', 'LVE' => 'Lavieéco', 'FDM' => 'Femmes du Maroc', 'Nissaa' => 'Nissa min almaghrib'),
'required' => false,
))
->add('Journaliste', 'text', array(
'label' => 'Journaliste',
'data' => $this->username))
->add('Webmaster', 'entity', array('class' => 'Work\frontBundle\Entity\Utilisateurs', 'property' => 'id', 'multiple' => false))
->add('image')
->add('Valider')
->add('Envoyer', 'submit')
;
}
and the controller $a = new Article();
$username=$this->container->get('security.context')->getToken()->getUser()->getUsername();
$form = $this->createForm(new \Work\frontBundle\Form\ArticleType($username), $a);
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
$a->setsTitre($form['titre']->getData());
$a->setDescription($form['description']->getData());
$a->setContenu($form['contenu']->getData());
$a->setCategorie($form['categorie']->getData());
$a->setSite($form['site']->getData());
$a->setImage($form['image']->getData());
$a->setWebmaster($form['Webmaster']->getData());
$a->setValider($form['Valider']->getData());
$a->setJournaliste($form['Journaliste']->getData());
$em = $this->getDoctrine()->getEntityManager();
$em->persist($a);
$em->flush();
}
}
return $this->render('WorkfrontBundle:Default:article.html.twig', array('form' => $form->createView()));
}
the setter
and the setter
/**
* Set journaliste
*
* #param \Work\frontBundle\Entity\Utilisateurs $journaliste
* #return Article
*/
public function setJournaliste(\Work\frontBundle\Entity\Utilisateurs $journaliste = null)
{
$this->journaliste = $journaliste;
return $this;
}
but i got this probleme
Catchable Fatal Error: Argument 1 passed to Work\frontBundle\Entity\Article::setJournaliste() must be an instance of Work\frontBundle\Entity\Utilisateurs, string given, called in C:\wamp\www\stage\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php on line 442 and defined in C:\wamp\www\stage\src\Work\frontBundle\Entity\Article.php line 297
One route on click on button is for this controller:
public function addAction(Request $request){
$em = $this->getDoctrine()->getManager();
$spotEntity = $this->getCurrentSpot();
$permitsidrand = rand(0, 1000000000000);
$currentDate = new DateTime();
$permitsrepo = new Permits();
$permitsrepo->setCreatedat($currentDate);
$permitsrepo->setPermitid($permitsidrand);
$permitsrepo->setPermitsSpot($spotEntity);
$em->persist($permitsrepo);
$em->flush();
return $this->redirect($this->generateUrl('permits_add', array('id' => $permitsrepo->getId())));
}
So I want to make new Object and fill it with couple variables and after it I want to redirect to screen with form that will be updating my record from database which I just added.
Here is second function (this one that I am redirecting to after click in button)
public function addfullAction(Request $request, $id){
$permitsidrand = rand(0, 1000000000000);
$currentDate = new DateTime();
$permitsrepo = $this->getDoctrine()->getRepository('MainCoreBundle:Permits');
$perm= $permitsrepo->find($id);
$form = $this->createForm(new PermitsType(), $permitsrepo);
$permitsrepo->setCreatedat($currentDate);
$permitsrepo->setPermitid($permitsidrand);
$permitsrepo->setPermitsSpot($spotEntity);
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($permitsrepo);
$em->flush();
return $this->redirect($this->generateUrl('permits_show'));
}
}
return $this->render('MainAdminBundle:Permits:add.html.twig', $this->getViewConstants(array(
'form' => $form->createView(),
'rand' =>$permitsidrand
)));
}
And when I click that Button that I mantion I have this error message:
Neither property "PermitsContractor" nor method "getPermitsContractor()" nor method "isPermitsContractor()" exists in class "Main\CoreBundle\Entity\PermitsRepository"
Here is my form
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('PermitsContractor', 'entity', array(
'class' => 'MainCoreBundle:Generalcontractor',
'multiple' => false,
'expanded' => false,
'property'=>'name',
'label'=> 'Generalny wykonawca',
));
$builder->add('PermitsCompany', 'entity', array(
'class' => 'MainCoreBundle:Company',
'multiple' => false,
'expanded' => false,
'property'=>'name',
'label'=> 'Firma',
));
$builder->add('Permitname', 'text',array('label'=> "Imię", 'required'=>false));
$builder->add('Permitsurname', 'text',array('label'=> "Nazwisko", 'required'=>false));
$builder->add('expirationdate', 'date', array(
'widget' => 'single_text',
'label'=> 'Data ważności',
));
$builder->add('file', 'file', array('required'=>false, 'label'=>'Przeglądaj'));
}
public function getName() {
return 'main_admin_permits_type';
}
I checkout and I got getters and setters in Entities
The error is here
$perm = $permitsrepo->find($id);
$permitsrepo->setCreatedat($currentDate);
$permitsrepo->setPermitid($permitsidrand);
$permitsrepo->setPermitsSpot($spotEntity);
Use
$perm = $permitsrepo->find($id);
$perm->setCreatedat($currentDate);
$perm->setPermitid($permitsidrand);
$perm->setPermitsSpot($spotEntity);
I'd like to move my email code from my controller into a service.
I've done the following thus far:
created the entry in services.yml
created a EmailManager.php file inside acme/demobundle/services/EmailManager.php
Could use some help on what needs to go into the EmailManager.php and how to call it in the controller?
services.yml
services:
email_manager:
class: Acme\DemoBundle\Services\EmailManager
arguments: [#request_stack, #mailer]
scope: request
EmailManager.php
<?php
// src/Acme/DemoBundle/Services/EmailManager.php
namespace Acme\DemoBundle\Services;
class EmailManager
{
private $mailer;
private $request;
public function __construct(RequestStack $requestStack, $mailer)
{
$this->request = $requestStack->getCurrentRequest();
$this->mailer = $mailer;
}
What needs to go here? Do I just copy/paste the code from the contactAction below into here?
}
Controller code with contactAction that I would like to move out of the controller into EmailManager service:
/**
* #Route("/", name="contact")
* #Template("AcmeDemoBundle:Default:index.html.twig")
*/
public function contactAction(Request $request)
{
$form = $this->createForm(new ContactType());
if ($request->isMethod('POST')) {
$form->submit($request);
if ($form->isValid()) {
$message = \Swift_Message::newInstance()
->setSubject($form->get('subject')->getData())
->setFrom($form->get('email')->getData())
->setTo('example#gmail.com')
->setBody(
$this->renderView(
'AcmeDemoBundle:Default:index.html.twig',
array(
'ip' => $request->getClientIp(),
'name' => $form->get('name')->getData(),
'message' => $form->get('message')->getData()
)
)
);
$this->get('mailer')->send($message);
$request->getSession()->getFlashBag()->add('success', 'Your email has been sent! Thanks!');
return $this->redirect($this->generateUrl('contact'));
}
}
return array(
'form' => $form->createView()
);
}
ContactType Form
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text', array(
'attr' => array(
'placeholder' => 'What\'s your name?',
'pattern' => '.{2,}' //minlength
)
))
->add('email', 'email', array(
'attr' => array(
'placeholder' => 'So I can get back to you.'
)
))
->add('subject', 'text', array(
'attr' => array(
'placeholder' => 'The subject of your message.',
'pattern' => '.{3,}' //minlength
)
))
->add('message', 'textarea', array(
'attr' => array(
'cols' => 90,
'rows' => 10,
'placeholder' => 'And your message to me...'
)
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$collectionConstraint = new Collection(array(
'name' => array(
new NotBlank(array('message' => 'Name should not be blank.')),
new Length(array('min' => 2))
),
'email' => array(
new NotBlank(array('message' => 'Email should not be blank.')),
new Email(array('message' => 'Invalid email address.'))
),
'subject' => array(
new NotBlank(array('message' => 'Subject should not be blank.')),
new Length(array('min' => 3))
),
'message' => array(
new NotBlank(array('message' => 'Message should not be blank.')),
new Length(array('min' => 5))
)
));
$resolver->setDefaults(array(
'constraints' => $collectionConstraint
));
}
public function getName()
{
return 'contact';
}
}
You can customize this as you see fit, but that's a general idea and a very quick draft to guide you:
public function send($subject, $recipientName, $recipientEmail, $bodyHtml, $bodyText)
{
/* #var $mailer \Swift_Mailer */
if(!$this->mailer->getTransport()->isStarted()){
$this->mailer->getTransport()->start();
}
/* #var $message \Swift_Message */
$message = $this->mailer->createMessage();
$message->setSubject($subject);
$message->setBody($bodyHtml, 'text/html');
$message->addPart($bodyText, 'text/plain', 'UTF8');
$message->addTo($recipientEmail, $recipientName);
$message->setFrom( array('example#gmail.com' => 'Chance') );
$this->mailer->send($message);
$this->mailer->getTransport()->stop();
}
Room for Improvement
You could have:
An email data model that would contain the fields necessary for an email (like $subject, $recipientEmail, ...)
A composer that would compose your email from your request
A sender that would send your email
EMAIL MODEL would look something like this:
/**
* Email Data Model
*/
class Email implements EmailInterface
{
/**
* The text part of the message.
*
* #var string
*/
protected $bodyText;
// etc...etc..
}
You'd have an EmailInterface too:
/**
* Email interface
*/
interface EmailInterface
{
/**
* #return string
*/
public function getBodyText();
// etc...etc..
}
THE SENDER would look like this (if kept inside EmailManager):
public function send(EmailInterface $email)
{
//...
}
THE COMPOSER would look like this (if kept inside EmailManager):
public function composeEmail(Request $request)
{
//...
return $email;
}
Note: Composer and Sender could also be a separate service for better reuse, that's up to you I guess. Here is what they would look like if there were just functions in your EmailManager
I have two entities "meeting" and "Slot" with a one2many relation.
I have a form to update a meeting (just to change the time slot), i want to display only free slot so i've made a query_ builder. It works for the creation, but for the update, there is always a validation error (this value is not valid).
This is my code :
controller
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('NfidBusinessMeetingBundle:Meeting')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Meeting entity.');
}
$editForm = $this->createForm(new UpdateMeetingType($entity->getUserA(),$entity->getUserB()), $entity);
if ($this->getRequest()->isMethod('POST')) {
$editForm->bind($this->getRequest());
// var_dump($editForm->getData() );
if ($editForm->isValid()) {
$entity->setDeleted(0);
$entity->setPending(1);
$entity->setValidated(0);
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('meeting_front'));
}
}
return $this->render('NfidBusinessMeetingBundle:MeetingFront:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
));
}
form builder
public function __construct($userA = null, $userB = null)
{
$this->userA = $userA;
$this->userB = $userB;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// die(var_dump($options));
$users[] = $this->userA;
$users[] = $this->userB;
$builder
->add('slot', 'entity',
array(
'class' => 'NfidBusinessMeetingBundle:Slot',
'query_builder' => function(SlotRepository $cr) use ($users) {
return $cr->findAllFreeSlotByUsers($users);
}
)
);
}
Repository
public function findAllFreeSlotByUsers(array $users){
$subquery = $this->createQueryBuilder('query1');
$subquery->select('s')
->from('NfidBusinessMeetingBundle:Meeting', 'm')
->leftJoin('m.slot', 's')
->leftJoin('m.userA', 'uA')
->leftJoin('m.userB', 'uB')
->where('m.userA = :userA')
->orWhere('m.userA = :userB')
->orWhere('m.userB = :userA')
->orWhere('m.userB = :userB')
->andWhere('m.validated = 1');
$query = $this->createQueryBuilder('query');
$query->select('s2')
->from('NfidBusinessMeetingBundle:Slot', 's2')
->where($query->expr()->notIn('s2.id', $subquery->getDQL()))
->setParameters(array('userA' => $users[0]->getId(), 'userB' => $users[1]->getId()));
return $query;
}
Someone can help me ?
EDIT : If made this it works
public function buildForm(FormBuilderInterface $builder, array $options)
{
// die(var_dump($options));
$users[] = $this->userA;
$users[] = $this->userB;
$builder
->add('slot');
}
=========================== EDIT ====================================
I've try this
public function findAllFreeSlotByUsers(array $users){
$subquery = $this->createQueryBuilder('query1');
$subquery->select('s')
->from('NfidBusinessMeetingBundle:Meeting', 'm')
->leftJoin('m.slot', 's')
->leftJoin('m.userA', 'uA')
->leftJoin('m.userB', 'uB')
->where('m.userA = :userA')
->orWhere('m.userA = :userB')
->orWhere('m.userB = :userA')
->orWhere('m.userB = :userB')
->andWhere('m.validated = 1');
$query = $this->createQueryBuilder('query');
$query->select('s2')
->from('NfidBusinessMeetingBundle:Slot', 's2')
->where(
$query->expr()->orx(
$query->expr()->notIn('s2.id', $subquery->getDQL()),
$query->expr()->eq('s2.id', $users[2]->getId())
)
)
->setParameters(array('userA' => $users[0]->getId(), 'userB' => $users[1]->getId()));
return $query;
}
and
public function buildForm(FormBuilderInterface $builder, array $options)
{
// die(var_dump($options));
$users[] = $this->userA;
$users[] = $this->userB;
$users[] = $builder->getData();
if ($this->userConnected == User::TYPE_RESSOURCE ) {
$builder
->add('slot', 'entity',
array(
'class' => 'NfidBusinessMeetingBundle:Slot',
'query_builder' => function(SlotRepository $cr) use ($users) {
return $cr->findAllFreeSlotByUsers($users);
}
)
)
And it's always the same error
string 'slot:
ERROR: Cette valeur n'est pas valide.
UPDATED:
Insert this code and output the result:
editAction:
var_dump($entity->getSlot()->getId());
$editForm = $this->createForm(new UpdateMeetingType($entity->getUserA(),$entity->getUserB()), $entity);
buildForm:
'query_builder' => function(SlotRepository $cr) use ($users) {
$query = $cr->findAllFreeSlotByUsers($users);
$results = $query->getQuery()->getResult();
foreach ($results as $result) {
var_dump($result->getId());
}
die;
}
Try this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$data = $builder->getData();
$users[] = $this->userA;
$users[] = $this->userB;
$builder
->add('slot', 'entity',
array(
'class' => 'NfidBusinessMeetingBundle:Slot',
'query_builder' => function(SlotRepository $cr) use ($users) {
return $cr->findAllFreeSlotByUsers($users, $data->getSlot());
}
)
);
}
SlotRepository: slot_id is the second parameters you pass from the entity type
$query = $this->createQueryBuilder('query');
$query->select('s2')
->from('NfidBusinessMeetingBundle:Slot', 's2')
->where(
$query->expr()->orx(
$query->expr()->notIn('s2.id', $subquery->getDQL()),
$query->expr()->eq('s2.id', $slot_id)
)
)
->setParameters(array('userA' => $users[0]->getId(), 'userB' => users[1]->getId()));
Of course, you may need to make some tests if the slot is null, etc.
What may be your issue:
Let's assume NEW meeting. This a the list of free slots:
Slot 1,
Slot 2,
Slot 3,
You select Slot 2. At edit, because it is used this is the list of free slots:
Slot 1,
Slot 3
Since Slot 2 is not on the list you get invalid choice.