Related
I've been trying for a while to create custom messages for regexes. So far, I have been able to get this as a message.
But I would like for each regex to be able to put messages, example: for the regex[A-Z] I would like them to have their own custom messages and not have the same and unique message for all of them.
$req->validate([
'login'=> 'required|unique:user',
'email' => 'required|unique:user|email|regex:/(.+)#(.+)\.(.+)/i',
'password' => [
'required',
'min:8', // must be at least 10 characters in length
'confirmed',
'regex:/[a-z]/', // must contain at least one lowercase letter
'regex:/[A-Z]/', // must contain at least one uppercase letter
'regex:/[0-9]/',
'regex:/[#$!%*#?&]/' // must contain a special character
],
'password_confirmation' => 'required'
], [
'login.unique' => "Le nom d'utilisateur est déjà pris",
'email.unique' => "L'adresse mail est déjà utilisé",
'required' => 'Le champ est obligatoire',
'email.regex' => 'Le champ doit respecter le format comme indiqué',
'email.email'=> 'Le champ doit respecter le format comme indiqué',
'password.min'=> 'Le mot de passe doit contenir au moins 8 caractères',
'password.regex' => 'Le mot de passe doit contenir au moins 1 majuscule, 1 minuscule et un caractère spéciale',
'password.digits_between' => 'Le mot de passe doit contenir au moins 1 chiffres et maximum 10',
'password.confirmed' => 'Les deux mots de passes doivent être similaire',
]);
I would like something like this 'regex:/[a-z]/'=> 'One letter between a to z'
Thank a lot
Try this:
$req->validate([
'login'=> 'required|unique:user',
'email' => 'required|unique:user|email|regex:/(.+)#(.+)\.(.+)/i',
'password' => [
'required',
'min:8', // must be at least 10 characters in length
'confirmed',
'regex:/[a-z]/', // must contain at least one lowercase letter
'regex:/[A-Z]/', // must contain at least one uppercase letter
'regex:/[0-9]/',
'regex:/[#$!%*#?&]/' // must contain a special character
],
'password_confirmation' => 'required'
], [
'login.unique' => "Le nom d'utilisateur est déjà pris",
'email.unique' => "L'adresse mail est déjà utilisé",
'required' => 'Le champ est obligatoire',
'email.regex' => 'Le champ doit respecter le format comme indiqué',
'email.email'=> 'Le champ doit respecter le format comme indiqué',
'password.min'=> 'Le mot de passe doit contenir au moins 8 caractères',
'password.regex.0' => 'Le mot de passe doit contenir au moins 1 majuscule',
'password.regex.1' => 'Le mot de passe doit contenir au moins 1 minuscule',
'password.regex.3' => 'Le mot de passe doit contenir au moins un caractère spéciale',
'password.digits_between' => 'Le mot de passe doit contenir au moins 1 chiffres et maximum 10',
'password.confirmed' => 'Les deux mots de passes doivent être similaire',
]);
I would like to display the field form.childNumber and form.childFoyerFiscal according to the answer of form.child
If the person chosen TRUE :
-- Display"enfantNombre" and "enfantFoyerFiscal"
If the person chosen is FALSE:
- Do not display anything
All this must change without refreshing the page (with AJAX for example)
Something like that :
class SimulationType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
/* Partie 1 - Situation */
->add('situationFamilliale', ChoiceType::class,$this->getConfigurationChoice("Votre situation familliale ?", "input"))
->add('anneeDeNaissance', IntegerType::class,$this->getConfigurationInteger("Quelle est votre année de naissance ?", "input"))
->add('enfant', ChoiceType::class,$this->getConfigurationBoolean("Avez vous des enfants ?", "radioButton"))
->add('enfantNombre', IntegerType::class,$this->getConfigurationInteger("Combien avez-vous d'enfants ?", "input"))
->add('enfantFoyerFiscal', IntegerType::class,$this->getConfigurationInteger("Combien sont encore dans votre foyer fiscal ?", "input"))
->add('pension', ChoiceType::class, $this->getConfigurationBoolean("Payez vous une pension ?", "radioButton"))
->add('pensionPrix', IntegerType::class, $this->getConfigurationInteger("Combien vous coûte cette pension mensuellement?", "input"))
/* Partie 2 - Patrimoine */
->add('residencePrincipale', ChoiceType::class, $this->getConfigurationResidence("Concernant votre résidence principale vous êtes :", "radioButton", "Proprietaire", "Locataire", "Heberge gratuitement"))
// Propriétaire
->add('creditResidencePrincipale', ChoiceType::class, $this->getConfigurationBoolean("Avez-vous un crédit sur la résidence principale ?", "radioButton"))
// Propriétaire -> Oui
->add('proprietaireCreditPrix', IntegerType::class, $this->getConfigurationInteger("Combien vous coûte ce crédit par mois ?", "input"))
->add('proprietaireCreditTemps', IntegerType::class, $this->getConfigurationInteger("Quelle est la durée restante (en année) ?", "input"))
//Locataire
->add('locataireCreditLoyer', IntegerType::class, $this->getConfigurationInteger("Quel est la montant de votre loyer /mois ?", "input"))
//Investissement Locatif
->add('investissement_bis', ChoiceType::class, $this->getConfigurationBoolean("Avez-vous déjà un investissement locatif en cours ?", "radioButton"))
//Investissement Locatif -> Oui
->add('investissement', CollectionType::class, ['entry_type' => InvestissementType::class, 'allow_add' => true]) // Créer les différents investissements
// Credit (Autres qu'immobilier)
->add('credit', ChoiceType::class, $this->getConfigurationBoolean("Avez-vous des crédits? (Autres qu'immobilier)", "radioButton"))
//Credit (Autres qu'immobilier) --> Oui
->add('creditAdd', CollectionType::class, ['entry_type' => CreditType::class, 'allow_add' => true])
->add('revenuMensuel', IntegerType::class, $this->getConfigurationInteger("Quel est le revenu net MENSUEL de votre foyer ?", "input"))
/* Partie 3 - Epargne */
->add('epargne', ChoiceType::class, $this->getConfigurationEpargne("A combien estimez-vous votre épargne?", "radioButton", "Moins de 10.000€", "Entre 10.000€ et 20.000€", "Entre 20.000€ et 50.000€", "Entre 50.000€ et 100.000€", "Plus de 100.000€"))
->add('apportInvestissement', ChoiceType::class, $this->getConfigurationBoolean("Envisagez vous de mettre un apport dans votre investissement?", "radioButton"))
// qpportInvestissement -> Oui
->add('apportPrix', IntegerType::class, $this->getConfigurationInteger("Combien apporteriez-vous ?", "input"))
->add('reductionImpot', ChoiceType::class, $this->getConfigurationBoolean("Avez-vous déjà des réductions d'impôts ?", "radioButton"))
// reductionImpot -> Oui
->add('reductionImpotPrix', IntegerType::class, $this->getConfigurationInteger("De combien réduisez vous votre impôt par an ?", "input"))
/* Partie 4 - Objectifs */
->add('objectifsPrincipaux', ChoiceType::class, $this->getConfigurationObjectifsPrincipaux("Choisissez vos 3 objectifs principaux", "radioButton", "input", "input1", "input2", "input3", "input4", "input5", "input6"))
->getForm();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Client::class,
]);
}
/**
* Permet d'avoir la configuration de base d'un IntegerType
*
* #param string $label
* #param string $class
* #return array
*/
private function getConfigurationInteger($label, $class){
return [
'label' => $label,
'attr' =>[
'class' => $class
],
'required' => true
];
}
/**
* Permet d'avoir la configuration de base d'un button de type RADIO
*
* #param string $label
* #param string $class
* #return array
*/
private function getConfigurationBoolean($label, $class): array
{
return [
'label' => $label,
'attr' =>[
'class' => $class
],
'choices' => [
'Oui' => true,
'Non' => false,
],
'expanded' => false,
'multiple' => false,
];
}
/*
* Permet d'avoir le choix en plusieurs proprositions (Max 5)
* L'utilisation de cette function peut servir quand il y a plusieurs choix à faire.
*
*/
public function getConfigurationObjectifsPrincipaux($label, $class, $choix1, $choix2, $choix3, $choix4, $choix5, $choix6, $choix7): array
{
return [
'label' => $label,
'attr' =>[
'class' => $class
],
'choices' => [
$choix1 => "patrimoineImmobilier",
$choix2 => "antipationRetraite",
$choix3 => "reductionFiscalite",
$choix4 => "augmentationRendementEpargne",
$choix5 => "constitutionCapital",
$choix6 => "transmissionEnfant",
$choix7 => "revenuComplementaire",
],
'expanded' => true,
'multiple' => true,
];
}
/*
* Configuration de base d'un ChoiceType
* Permet d'avoir le choix en plusieurs proprositions (Max 5)
* L'utilisation de cette function peut servir quand il y a plusieurs choix à faire.
*
*/
public function getConfigurationResidence($label, $class, $choix1, $choix2, $choix3): array
{
return [
'label' => $label,
'attr' =>[
'class' => $class
],
'choices' => [
$choix1 => strtolower(str_replace(' ','',$choix1)),
$choix2 => strtolower(str_replace(' ','',$choix2)),
$choix3 => strtolower(str_replace(' ','',$choix3)),
],
'expanded' => false,
'multiple' => false,
];
}
/*
* Configuration de base d'un ChoiceType
* Permet d'avoir le choix en plusieurs proprositions (Max 5)
* L'utilisation de cette function sert quand il y a plusieurs choix à faire.
*
*/
public function getConfigurationEpargne($label, $class, $choix1, $choix2, $choix3, $choix4, $choix5): array
{
return [
'label' => $label,
'attr' =>[
'class' => $class
],
'choices' => [
$choix1 => "10k",
$choix2 => "20k",
$choix3 => "50k",
$choix4 => "100k",
$choix5 => "1000k",
],
'expanded' => false,
'multiple' => false,
];
}
/**
* L'utilisation de cette fonction est unique (Partie 1)
*
* #param $label
* #param $class
* #return array
*/
private function getConfigurationChoice($label, $class): array
{
return
[
'label' => $label,
'attr' =>[
'class' => $class
],
'choices' => [
'Célibataire' => 'celibataire',
'Marié(e)' => 'marie',
'Pacsé(e)' => 'pacse',
'En concubinage' => 'concubinage',
'Divorcé(e)' => 'divorce',
'Veuf/Veuve' => 'veuf'
]
];
}
SimulationController
class SimulationController extends AbstractController
/**
* #Route("/simulation", name="simulation")
* #param Request $request
* #param ObjectManager $manager
* #return Response
*/
public function formulaire(Request $request, ObjectManager $manager)
{
$Client = new Client();
$form = $this->createForm(SimulationType::class, $Client); //SimulationType = Formulaire avec les champs
/**
* Permet d'agir en fonction des résultats des formulaires
*/
$form->handleRequest($request);
dump($Client);
/* Est ce que le formulaire est bien valide ? */
if ($form->isSubmitted() && $form->isValid()) {
// Si la formulaire est correct --> Direction la page Patrimoine
return $this->render('content/verification.html.twig', [
'form' => $form->createView()]);
} elseif ($form->isSubmitted() && $form->isValid() == false) {
// Si la page n'est pas correct, il affiche la page de vérification
return $this->render(
'/content/verification.html.twig', [
'form' => $form->createView()]);
} else {
return $this->render(
'/content/simulation.html.twig', [
'form' => $form->createView()]);
}
}
You've to use Form Events to make your form element update if another form element is updated. That is quite complicated. On the symfony doc you can find an example.
I will try to explain as best as possible. I created 2 linked entities for a #manytoone bidirectional relationship (I believe ^^ '). Here is what I want to do, I create a first form that allows me to fill the first entity (the daughter entity) and then I am redirected according to criteria to another page that allows me to fill the parent entity but I Can not find a way to retrieve the id of the entity girl, I tried to pass it through the URL but I can not retrieve it and insert it in the field id_daughterentities.
I enclose the code, I hope that this explanation will allow you to see more clearly.
public function newclientAction(Request $request)
{
// On crée un objet Advert
$client = new Clients();
// J'ai raccourci cette partie, car c'est plus rapide à écrire !
$form = $this->get('form.factory')->createBuilder(FormType::class, $client)
->add('FirstName', TextType::class)
->add('Surname', TextType::class)
->add('Address', TextType::class)
->add('Mail', EmailType::class, array(
'required' => false))
->add('Mail2', EmailType::class, array(
'label' => 'Mail N°2',
'required' => false
))
->add('Phone', TextType::class, array(
'required' => false))
->add('Phone2', TextType::class, array('label' => 'Phone N°2',
'required' => false))
->add('BirthDate', BirthdayType::class, array('label' => 'Date of Birth'))
->add('Status', ChoiceType::class, array(
'choices' => array(
'Client' => 'Client',
'Ex-Client' => 'Ex-Client',
'Prospect' => 'Prospect'),
))
->add('Comments', TextareaType::class, array(
'required' => false))
->add('TypeofBuisness', ChoiceType::class, array(
'choices' => array(
'Blank'=> Null,
'SE' => 'SE',
'SA' => 'SE',
'LLP' => 'LTD',
'LTD' => 'LTD',
'Payroll' => 'Payroll'),
'label' => 'Type of buisness'
))
->add('save', SubmitType::class)
->getForm()
;
// Si la requête est en POST
if ($request->isMethod('POST')) {
// On fait le lien Requête <-> Formulaire
// À partir de maintenant, la variable $advert contient les valeurs entrées dans le formulaire par le visiteur
$form->handleRequest($request);
// On vérifie que les valeurs entrées sont correctes
// (Nous verrons la validation des objets en détail dans le prochain chapitre)
if ($form->isValid()) {
// On enregistre notre objet $advert dans la base de données, par exemple
$em = $this->getDoctrine()->getManager();
$em->persist($client);
$em->flush();
$request->getSession()->getFlashBag()->add('notice', 'Well regitered.');
if ($client->getTypeOfBuisness()== 'Payroll')
{
return $this->redirectToRoute('pegasus_payroll', array('id' => $client->getId()));
}
elseif ($client->getTypeOfBuisness()== 'LTD')
{
return $this->redirectToRoute('pegasus_ltd', array('id' => $client->getId()));
}
elseif ($client->getTypeOfBuisness()== 'LTD')
{
return $this->redirectToRoute('pegasus_se', array('id' => $client->getId()));
}
else {
return $this->redirectToRoute('pegasus_web_homepage', array('id' => $client->getId()));
}
}
}
// À ce stade, le formulaire n'est pas valide car :
// - Soit la requête est de type GET, donc le visiteur vient d'arriver sur la page et veut voir le formulaire
// - Soit la requête est de type POST, mais le formulaire contient des valeurs invalides, donc on l'affiche de nouveau
return $this->render('PegasusWebBundle:Default:newclient.html.twig', array(
'form' => $form->createView(),
));
}
public function payrollAction(Request $request)
{
// On crée un objet Advert
$payroll = new Payroll();
// J'ai raccourci cette partie, car c'est plus rapide à écrire !
$form = $this->get('form.factory')->createBuilder(FormType::class, $payroll)
->add('EmployerName', TextType::class, array('label' => 'Employer name'))
->add('EmployerSurname', TextType::class)
->add('Address', TextType::class, array('required' => false))
->add('Phone', TextType::class, array('required' => false))
->add('Phone2', TextType::class, array('label' => 'Phone N°2','required'=> false))
->add('Mail', EmailType::class, array('required' => false))
->add('Mail2', EmailType::class, array('label' => 'Mail N°2','required'=> false ))
->add('ContactName', TextType::class, array('required' => false))
->add('Payedisctrict', TextType::class, array('label' => 'PAYE district','required'=> false))
->add('Payeaddress', TextType::class, array('label' => 'PAYE address','required'=> false))
->add('Payephone', TextType::class, array('label' => 'PAYE phone','required'=> false))
->add('Payereference', TextType::class, array('label' => 'PAYE reference','required'=> false))
->add('Accref', TextType::class, array('label' => 'Account reference','required'=> false))
->add('Taxereff', TextType::class, array('label' => 'Tax reference','required'=> false))
->add('Comments', TextareaType::class, array('label' => 'Any comment ?','required'=> false))
->add('save', SubmitType::class)
->getForm()
;
I tried there to take the id from the url but it's not working, i tried tones of solutions but nothing works .... I really sorry for this stupid question but i'm trying to learn it by my own
$payroll.clients=$request->query->get('id');
// Si la requête est en POST
if ($request->isMethod('POST')) {
// On fait le lien Requête <-> Formulaire
// À partir de maintenant, la variable $advert contient les valeurs entrées dans le formulaire par le visiteur
$form->handleRequest($request);
$payroll->is
// On vérifie que les valeurs entrées sont correctes
// (Nous verrons la validation des objets en détail dans le prochain chapitre)
if ($form->isValid()) {
// On enregistre notre objet $advert dans la base de données, par exemple
$em = $this->getDoctrine()->getManager();
$em->persist($payroll);
$em->flush();
$request->getSession()->getFlashBag()->add('notice', 'Well regitered.');
return $this->redirectToRoute('pegasus_web_homepage');
}
}
// À ce stade, le formulaire n'est pas valide car :
// - Soit la requête est de type GET, donc le visiteur vient d'arriver sur la page et veut voir le formulaire
// - Soit la requête est de type POST, mais le formulaire contient des valeurs invalides, donc on l'affiche de nouveau
return $this->render('PegasusWebBundle:Default:newclient.html.twig', array(
'form' => $form->createView(),
));
}
/**
* Payroll
*
* #ORM\Table(name="payroll")
* #ORM\Entity(repositoryClass="Pegasus\WebBundle\Repository\PayrollRepository")
*/
class Payroll
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Clients", inversedBy="payroll")
* #ORM\JoinColumn(nullable=false, name="clients_id", referencedColumnName="id")
*/
private $clients;
/**
* Set clients
*
* #param \Pegasus\WebBundle\Entity\Clients $clients
*
* #return Payroll
*/
public function setClients(\Pegasus\WebBundle\Entity\Clients $clients )
{
$this->clients = $clients;
return $this;
}
/**
* Get clients
*
* #return \Pegasus\WebBundle\Entity\Clients
*/
public function getClients()
{
return $this->clients;
}
Cause of that i can't validate my form because my foreign key is empty ... :/
Someone can help me ? pls
First you need the Clients Entity object to persist the doctrine entity, not the integer ID. If you are passing the id in your request, you'll need to either use automatic Dependency Injection, or get the entity from doctrine manually, like so:
$clients = $this->getDoctrine()->getManager()
->find('PegasusWebBundle:Clients', $request->query->get('id'));
The next issue is your Payroll form. It needs to be made aware of the Payroll entity (data_class option) and the Clients EntityType association, even if clients is a hidden field. Though it is unclear in your example how you are passing the form data to the new Payroll entity object.
For example using separate GET and POST actions.
/**
* #Route("/pegasus_payroll/{id}", name="pegasus_payroll", requirements={"id":"\d+"})
* #Method("GET")
*/
public function payrollAction(Request $request, \Pegasus\WebBundle\Entity\Clients $clients)
{
$payroll = new Payroll();
//set the new payroll clients based on the automatic param conversion
$payroll->setClients($clients);
$form = $this->createPayrollForm($payroll, ['action' => $this->generateUrl('save_pegasus_payroll')]);
$form->handleRequest($request);
return $this->render('PegasusWebBundle:Default:newpayroll.html.twig', [
'form' => $form->createView(),
]);
}
/**
* #Route("/pegasus_payroll", name="save_pegasus_payroll")
* #Method("POST")
*/
public function savePayrollAction(Request $request)
{
//retrieve the entity from the request form data, to validate with the previous form choice(s).
$em = $this->getDoctrine()->getManager();
$clients = $em->find('PegasusWebBundle:Clients', $request->request->get('form')['clients']);
$payroll = new Payroll;
$payroll->setClients($clients);
$form = $this->createPayrollForm($payroll);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$formPayroll = $form->getData();
echo $formPayroll->getClients()->getId();
//the form data is propagated to the $payroll object passed to it
echo $payroll->getClients()->getId();
exit;
//$em->persist($payroll);
//$em->flush();
//$this->addFlash('notice', 'Well regitered.');
//return $this->redirectToRoute('pegasus_web_homepage');
}
return $this->render('PegasusWebBundle:Default:newpayroll.html.twig', [
'form' => $form->createView(),
]);
}
/**
* use a method to store the form so you can use it elsewhere
* Alternatively create a new FormType class that extends AbstractFormType
*/
private function createPayrollForm(Payroll $payroll, array $options = [])
{
$options['data_class'] = Payroll::class;
return $this->get('form.factory')
->createBuilder(FormType::class, $payroll, $options)
//.. you will need to update to match the Payroll entity property name getter/setters names.
->add('clients', EntityType::class, [
'class' => \Pegasus\WebBundle\Entity\Clients::class,
'multiple' => false, //only a single selection
'label' => false, //don't display the form field label
'choice_label' => false, //don't display select options
'choices' => [$payroll->getClients()], //only available choice
'attr' => [
'style' => 'display:none;' //hide the select box
]
])
->getForm();
}
As a final note, you should take advantage of the automatic Dependency Injection using ParamConverter
It will make your life a lot easier when your controllers have type-hinted what they are requiring, rather than having to manually define evertything.
I am using symfony 2 and I have a form on which I put #Assert\NotBlank() annotations.
I am volontarily filling the fields, my form does not pass the isValid and isSubmitted test and after those lines I get a non-null value for exit(var_dump($recipeForm->getErrors()));
private 'errors' =>
array (size=4)
0 =>
object(Symfony\Component\Form\FormError)[4119]
private 'message' => string 'Cette valeur doit être vide.' (length=29)
protected 'messageTemplate' => string 'This value should be blank.' (length=27)
protected 'messageParameters' =>
array (size=1)
...
protected 'messagePluralization' => null
private 'cause' =>
object(Symfony\Component\Validator\ConstraintViolation)[4062]
...
private 'origin' => null
In my twig template I render the form with a simple form(form). form_errors(form) or form_errors(form.field) won't render the errors. Why? Why could I do to further understand where the issue comes from?
I have a pretty complicated type. for some other forms of my website, the errors are correctly displayed.
My type:
<?php
//src/AppBundle/Form/FoodAnalytics/RecipeType.php
namespace AppBundle\Form\FoodAnalytics;
use AppBundle\Form\Core\MediaType;
use AppBundle\Repository\FoodAnalytics\UnitRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RecipeType extends AbstractType
{
protected $recipeIngredientQueryBuilder;
protected $recipeSubrecipeQueryBuilder;
protected $unitRepository;
protected $action;
/**
* #return string
*/
public function getName()
{
return 'appbundle_foodanalytics_recipe' . $this->action;
}
public function __construct(UnitRepository $unitRepository, $recipeIngredientQueryBuilder=null, $recipeSubrecipeQueryBuilder=null, $action = null)
{
$this->recipeIngredientQueryBuilder = $recipeIngredientQueryBuilder;
$this->recipeSubrecipeQueryBuilder = $recipeSubrecipeQueryBuilder;
$this->unitRepository = $unitRepository;
$this->action = $action == null ? null : '_' . $action;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('recipeCategories', 'genemu_jqueryselect2_entity',array(
'multiple' => true,
'class' => 'AppBundle:FoodAnalytics\RecipeCategory',
'label' => 'Catégories',
'required' => false,
'by_reference' => false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez les catégories dans lesquelles enregistrer la recette pour un recherche future plus facile",
)))
->add('isProduct', null, array(
'label'=>'Correspond à un produit fini',
'required'=>false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"La recette correspond-elle à un produit fini qui peut être mis en vente ?",
)))
->add('name', null, array(
'label'=>'Nom détaillé',
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez le nom détaillé de la recette. Par exemple : 'millefeuilles praliné ganache vanille sur feuilletage inversé'",
)))
->add('nickName', null, array(
'label'=>'Nom raccourci',
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez un nom raccourci pour la recette. Par exemple : 'millefeuilles'",
)))
->add('recipeIngredients', 'collection', array(
'type' => new RecipeIngredientType($this->unitRepository, $this->recipeIngredientQueryBuilder),
'by_reference' => false,
'label'=>'Ingrédient',
'allow_add' => true,
'allow_delete' => true,
'cascade_validation' => true,
))
->add('subrecipes', 'collection', array(
'type' => new RecipeSubrecipeType($this->unitRepository, $this->recipeSubrecipeQueryBuilder),
'by_reference' => false,
'label'=>'Sous-recette',
'allow_add' => true,
'allow_delete' => true
))
->add('recipeSteps', 'collection', array(
'type' => new RecipeStepType(),
'by_reference' => false,
'label'=>'Etape de production',
'allow_add' => true,
'allow_delete' => true
))
->add('portions', null, array(
'label'=>'Nombre de parts / de pièces',
'required' => false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez le nombre d'éléments disponibles dans la recette. Cela peut permettre d'utiliser l'unité 'U' dans les recettes parentes qui l'utiliseront",
)))
->add('shortDescription', null, array(
'label'=>'Description courte',
'required'=>false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Décrivez succinctement la recette",
)))
->add('medias', 'collection', array(
'type' => new MediaType(),
'by_reference' => false,
'label'=>'Medias',
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Ajoutez des images ou vidéos pour décrire la recette",
)))
->add('content', 'textarea', array(
'label'=>'Instructions générales',
'required'=>false,
'attr' => array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'class' => 'summernote',
'title'=>"Ajoutez du contenu supplémentaire pour détailler la recette",
)))
->add('workingDuration', 'timepicker', array(
'label'=>'Temps total de travail',
'required' => false,
'attr'=>array
(
'class' => 'timepicker',
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez le temps total de travail consacré à la recette si il diffère du temps de travail cumulé des étapes de production",
)))
->add('sleepDuration', 'timepicker', array(
'label'=>'Temps total de repos',
'required' => false,
'attr'=>array
(
'data-toggle'=>"tooltip",
'class'=>'timepicker',
'data-placement'=>"top",
'title'=>"Indiquez le temps total de repos consacré à la recette si il diffère du temps de repos cumulé des étapes de production",
)))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\FoodAnalytics\Recipe',
// 'cascade_validation' => true,
));
}
}
EDIT: keeping only one simple field of this form does not change anything, the error won't get shown
Take a look at how errors are rendered here: http://symfony.com/doc/current/cookbook/form/form_customization.html#customizing-error-output
The problem with using {{ form_errors(form) }} is that it displays global form errors, not individual fields, whereas getErrorsAsString() will drill-down through all of the fields. If you want all of the individual field errors to be accessible via {{ form_errors(form) }}, then you need to edit every single field in your form and add the option error_bubbling => true.
If you don't set the error bubbling to true on all of our fields, then you will need to render each field's error individually - for example: {{ form_errors(form.name) }}, or just using {{ form_row(form.name) }} which renders the label, form element, and errors all in one shot.
Ah my god!
I'm sorry i made people lose time with this! The issue was I was passing as a response an array $response = array(form->createView()) but this array response was generated before I handle the request. Hence why I could see it in the vardump and not in twig.
Seems that the error is caused by a validation rule on a property that is part of your Recipe entity but not added to RecipeType so the error is unable to be linked to any sub-forms.
Try to check your entity and find which property has validation rule and not added to the RecipeType either add a default value for that property or use Validation Groups
I am trying to use a query_builder with a notIn clause. But it doesn't work et I have this error message :
Call to a member function expr() on a non-object in C:\wamp\www\projet\src\Intranet\UserBundle\Entity\UserRepository.php line 301
This is the method :
public function employesSansCongesAllouesEn($annee) {
$nots = $this->createQueryBuilder('u') // récupérer les employés qui ont déjà des congés définis
->select('u.id')
->Join('\Intranet\CalendrierBundle\Entity\UserCongeByYear', 'uc', "WITH", "uc.user = u.id ") // jointure UserCongeByYear
->andWhere('u.enabled = 1 ')
->andWhere('uc.annee = :annee ') // condition d'année
->getDQL()
;
$qb = $this->createQueryBuilder('user') // récupérer les employés qui n'ont pas encore de congé pour l'année choisie
->andWhere('user.enabled = 1')
->distinct('user')
->andWhere($qb->expr()->notIn('user.id', $nots)) // condition NOT IN
->setParameter(':annee', $annee)
->orderBy('user.nom', 'ASC')
;
return $qb;
}
And the form using this query :
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('users', 'entity', array(
'label' => "Employés : ",
'class' => 'IntranetUserBundle:User',
'multiple' => false,
'required' => true,
'attr' => array('class' => 'form-control'),
'query_builder' => function(UserRepository $er) use($options) {
return $er->employesSansCongesAllouesEn($options['annee']);
}
))
->add('heures', 'integer', array(
'label' => "Nombre d'heures attribuées : ",
'attr' => array('class' => 'form-control', 'min' => 1, 'max' => '250')
))
;
}
You are using the $qb before it has been declared.
You should declare it and then use it in the query building process after that, like..
$qb = $this->createQueryBuilder();
// récupérer les employés qui ont déjà des congés définis
$nots = $qb
->select('u.id')
->Join(
'\Intranet\CalendrierBundle\Entity\UserCongeByYear',
'uc',
"WITH",
"uc.user = u.id "
) // jointure UserCongeByYear
->andWhere('u.enabled = 1 ')
->andWhere('uc.annee = :annee ') // condition d'année
->getDQL()
;
// récupérer les employés qui n'ont pas encore de congé pour l'année choisie
return $qb
->where('user.enabled = 1')
->distinct('user')
->andWhere($qb->expr()->notIn('user.id', $nots)) // condition NOT IN
->setParameter(':annee', $annee)
->orderBy('user.nom', 'ASC')
;