Symfony2 Change checkbox values from 0/1 to 'no'/'yes' - php

I created a form with one checkbox.
UserSettingsType.php:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('newsletter', 'checkbox', array(
'label' => 'Newsletter erhalten',
'attr' => array(
'class' => 'form-control',
),
'required' => false,
));
}
In the UserSettings.php Entity:
/**
* #ORM\Column(name="newsletter", type="boolean")
*/
protected $newsletter;
In the User.php:
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $user_settings_id;
/**
* #ORM\OneToOne(targetEntity="UserSettings", cascade={"persist"})
* #ORM\JoinColumn(name="user_settings_id", referencedColumnName="id")
*/
protected $settings;
In the PageController.php i handle the settings action:
public function settingsAction() {
$user = $this->getUser();
if ($user->getSettings() !== null) {
$settings = $user->getSettings();
} else {
$settings = new UserSettings($user);
}
$settings_form = $this->createForm(new UserSettingsType(), $settings);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$em = $this->getDoctrine()->getManager();
$settings_form->bind($request);
if ($settings_form->isValid()) {
$user->setSettings($settings);
$em->persist($user);
$em->flush();
}
}
return $this->render('MyCompMyAppBundle:Page:settings.html.twig', array(
'settings_form' => $settings_form->createView(),
));
}
I want to change the checkbox values from false (unchecked) / true (checked) to 'no' / 'yes' and change the definition of the newsletter field to: * #ORM\Column(name="newsletter", type="string", columnDefinition="ENUM('yes', 'no')")
It would be nice if there would be 'yes' and 'no' enum values in the database.
Please correct me if i am wrong: There is no way to change this via form element attributes, right?
I heard something about a DataTransformer:. But is there any easier way to realize this?

do you want checkbox or radio button? for checkbox in peresentation use:
$builder->add('newsletter', 'choice', array(
'label' => 'Newsletter erhalten',
'attr' => array(
'class' => 'form-control',
),
'choices' => array(array('yes' => 'yes'), array('no' => 'no')),
'expanded' => true,
'multiple' => true,
'required' => false,
));

Don't use ENUM for this!
In MySQL, use either data type BIT(1) or TINYINT(1) (=same as BOOLEAN). See here: Which MySQL data type to use for storing boolean values
In PostgreSQL, there is a true BOOLEAN type. But no ENUM. So if you're ever thinking about migrating, better get rid of ENUM ;-)

Related

Doctrine tries to insert a null object Symfony 5.4

when i submit my form, I have two values ​​to choose from:
WorkPlanningDay and workPlanningHour.
if workplanninghour is specified, we insert a row in the workplanninghour table and vice versa
When I submit a workPlanningHour, I want to prevent doctrine from inserting a workPlanningDay object with null data. I tried to use a $form->remove but without success.
here is my request datas :
{"statuses":[6],"work_planning":1,"work_planning_hour":{"count_jrtt":1,"end_at":"31-12","jrtt":true,"lower_hour_jrtt":35,"nbr_jrtt":24,"start_at":"01-01","upper_hour_jrtt":39},"work_planning_period":0,"working_time_aspect":{"days":["MON","TUE","WED","THU","FRI"],"time":0,"weekly_hours":35}}
here is my form with my EventListener :
class WorkingTimeParametersRESTType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('work_planning', Field\ChoiceType::class, array(
'property_path' => 'workPlanning',
'required' => true,
'choices' => WorkingTimeParameters::getAllowedWorkPlannings(),
))
->add('work_planning_period', Field\ChoiceType::class, array(
'property_path' => 'workPlanningPeriod',
'required' => false,
'choices' => WorkingTimeParameters::getAllowedWorkPlanningPeriods(),
))
->add('working_time_aspect', WorkingTimeAspectType::class, array(
'property_path' => 'workingTimeAspect',
'required' => true,
'constraints' => array(new Valid())
))
->add('work_planning_hour', WorkPlanningHourType::class, array(
'property_path' => 'workPlanningHour',
'required' => true,
'constraints' => array(new Valid())
))
->add('work_planning_day', WorkPlanningDayType::class, array(
'property_path' => 'workPlanningDay',
'required' => true,
'constraints' => array(new Valid())
))
->add('statuses', Field\CollectionType::class, array(
'entry_type' => CategoryIntegerType::class,
'entry_options' => array(
'category_type' => Category::TYPE_STATUS,
),
'allow_add' => true,
'allow_delete' => true,
'required' => true,
'error_bubbling' => false,
))
->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'))
->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
/** #var WorkingTimeParameters $contract */
$parameters = $event->getData();
$form = $event->getForm();
// dd($form->has('work_planning_day'));
// Remove useless work planning
if ($parameters->getWorkPlanning() == Contract::WORK_PLANNING_HOUR) {
$parameters->setWorkPlanningDay(null);
$form->remove('work_planning_day');
}
else if ($parameters->getWorkPlanning() == Contract::WORK_PLANNING_DAY) {
$parameters->setWorkPlanningHour(null);
$form->remove('work_planning_hour');
}
else {
dd('rerer');
$form->remove('work_planning_day');
$form->remove('work_planning_hour');
$parameters->setWorkPlanningDay(null);
$parameters->setWorkPlanningHour(null);
$parameters->setWorkPlanningPeriod(null);
}
})
;
}
/**
* #param FormEvent $event
*/
public function onPreSetData(FormEvent $event)
{
$rttParameters = $event->getData();
$form = $event->getForm();
// The company can be set only on creation
if (!$rttParameters || !$rttParameters->getId()) {
$form->add('company', CompanyIntegerType::class, array(
'required' => true,
));
}
}
and here are the requests that doctrine is trying to launch :
INSERT INTO w2d_tm_work_planning_hour (startAt, endAt, jrtt, countJrtt, lowerHourJrtt, upperHourJrtt, nbrJrtt) VALUES ('1970-01-01 00:00:00', '1970-12-31 00:00:00', 1, 1, 35, 39, 24);
UPDATE w2d_tm_work_planning_day SET startAt = NULL, endAt = NULL, nbrDays = NULL, nbrJrtt = NULL WHERE id = 1;
how to do so that doctrine does not launch the second request with the null values ?
Symfony form type are not made to handle different entities depending on a option you selected inside.
This not how Symfony FormType are supposed to be used. This is why the data_class attribute is made for one entity.
You best option is to create two distinct FormType and submit only the one needed depending on what the user selected on frontend. (easy with a little of javascript)
The second advantage of this is you will have much more understandable and maintable code.

Symfony3.0 When saving a form with Entity Type dropdown; SQL error cannot insert null

Using Symfony 3.0, I have a form with a dropdown list generated from a Doctrine Entity. When I complete the form & Submit I can see in the profiler that the dropdown value has been passed through correctly, yet I get the following error:
Any idea what might be happening? EDIT I am not wanting to pass a null value. The form is passing in the selected value from the entity dropdown. But the insert into the db doesn't seem to be using this?
SQLSTATE[23000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]Cannot
insert the value NULL into column 'account_type', table 'CRM.dbo.accounts';
column does not allow nulls. INSERT fails.
The form is: (AccountType.php)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('accountTypeId', EntityType::class, array(
'class' => 'AppBundle:AccountType',
'choice_label' => 'typeName',
//'label' => 'Account Type',
))
->add('name')
->add('notes', null, array('label' => 'Long Name', 'required' => false))
->add('address')
->add('city')
->add('region')
->add('country', CountryType::class)
->add('postcode')
->add('telephone', null, array('required' => false))
->add('website', null, array('required' => false))
->add('email', null, array('required' => false))
->add('save', SubmitType::class);
}
Controller: (AccountController.php)
public function addAction(Request $request)
{
$account = new Account();
$form = $this->createForm(AccountType::class, $account);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
try {
// create account
//$account = $form->getData();
// save data to db
$em = $this->getDoctrine()->getManager();
$em->persist($account);
$em->flush();
// add flash message and return to profile
$this->addFlash('success', 'Account: ' . $account->getName() .' created successfully.');
return $this->redirectToRoute('accounts');
}
catch(Exception $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('accounts');
}
}
// load form for new account
return $this->render('accounts/add.html.twig', array(
'form' => $form->createView()
));
}
Account Model relation:
/**
* #ORM\ManyToOne(targetEntity="AccountType", inversedBy="accounts")
* #ORM\JoinColumn(name="account_type", referencedColumnName="id")
*/
private $accountTypeName;
AccountType Model relation:
/**
* #ORM\OneToMany(targetEntity="Account", mappedBy="accountTypeName")
*/
private $accounts;
Update your Account Entity according to this:
/**
* #ORM\ManyToOne(targetEntity="AccountType", inversedBy="accounts")
* #ORM\JoinColumn(name="account_type", referencedColumnName="id", nullable=true)
*/
private $accountTypeName;
And now I feel really dumb!
After all this, I was using the wrong variable in my account form.
I was using the account type id in my entity. Instead I should have been using the variable set in the relationship:
My form was using:
/**
* #ORM\Column(type="integer", name="account_type")
*/
private $accountTypeId;
Form:
$builder
->add('accountTypeId', EntityType::class, array(
'class' => 'AppBundle:AccountType',
'choice_label' => 'typeName',
//'label' => 'Account Type',
))
I have now changed the form to be:
$builder
->add('accountTypeName', EntityType::class, array(
'class' => 'AppBundle:AccountType',
'choice_label' => 'typeName',
//'label' => 'Account Type',
))
From :
/**
* #ORM\ManyToOne(targetEntity="AccountType", inversedBy="accounts")
* #ORM\JoinColumn(name="account_type", referencedColumnName="id")
*/
private $accountTypeName;
Which obviously works!!

Symfony2 collection Form uniquenes

I have a symfony2 main form, with a field what is a collection type of an other field, like a Product entity with multiple Tag, but these tag has a unique hash.
There is an eventListener attached to the main form. If I send a data to the form and I send a Tag along with this unique has, the unique constraint on the class will say, that that field has to be unique. This work good, but in this EventListener I'm search in the DB for this unique field and if it's the right one, I do an assign, I replace the post content with an entity from the DB.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('eventDate', 'datetime',array(
'widget' => 'single_text',
'format' => 'yyyy-MM-dd HH:mm',
'invalid_message' => 'Wrong datetime format. Please use like this: 2015-09-20 14:45:12',
))
->add('eventEnds', 'datetime', array(
'widget' => 'single_text',
'format' => 'yyyy-MM-dd HH:mm',
'invalid_message' => 'Wrong datetime format. Please use like this: 2015-09-20 14:45:12',
))
->add('tag','collection', array(
'type' => new TagType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'prototype' => true,
'property_path' => 'professional',
'label' => false,
'options' => array(
'professional' => true,
),
))
->addEventListener(FormEvents::SUBMIT, [$this, 'submit'])
;
}
public function preSubmit(FormEvent $event)
{
/** #var MainForm $data */
$data = $event->getData();
foreach ($data->getTags() as $tag) {
if ($tag->getId() == null && $tag->getHash()){
$tagDB = $this->entityManager
->getRepository('ApplicationBundle:Tag')
->findOneBy([
'hash' => $professional->getHash(),
]);
if ($tagDB) {
$data->removeTag($tag);
$data->addTag($tagDB);
}
}
}
$event->setData($data);
}
If I dump the $data value after the setData, I see there the entities from the DB, but I still got a Unique validation error and I check in the validator, symfony pass in the original POST content.
Why is it like that and how can I solve this problem?
Should be
->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'submit'])
(PRE_SUBMIT instead of SUBMIT)
Your code should be something like:
public function preSubmit(FormEvent $event)
{
/** #var MainForm $data */
$data = $event->getData();
$num = count($data['tag']);
for ($i=0;$i<$num;$i++) {
$tag = $data['tag'][$i];
if (!isset($tag['id']) && isset($tag['hash'])){
$tagDB = $this->entityManager
->getRepository('ApplicationBundle:Tag')
->findOneBy([
'hash' => $tag['hash'],
]);
if ($tagDB) {
unset($data['tag'][$i]);
$data['tag'][$i] = array (
'id' => $tagDB->getId();
'hash' => $tagDB->getHash();
);
}
}
}
$event->setData($data);
}
Not sure the code is 100% correct as I have not been able to test it, but you get the idea.

Symfony2 - Entity of type ...\Entity\Users is missing an assigned ID for field 'userId'

I always get this message:
Entity of type Reuzze\ReuzzeBundle\Entity\Users is missing an assigned
ID for field 'userId'. The identifier generation strategy for this
entity requires the ID field to be populated before
EntityManager#persist() is called. If you want automatically generated
identifiers instead you need to adjust the metadata mapping
accordingly.
I tried to delete:
#ORM\GeneratedValue(strategy="AUTO")
Or change it to:
#ORM\GeneratedValue(strategy="IDENTITY")
#ORM\GeneratedValue(strategy="NONE")
I also pasted in:
id:
userId:
primary: true
autoincrement: true
But nothing works!
My UserController register action:
public function registerAction(Request $request)
{
if ($this->get('security.context')->isGranted('ROLE_USER'))
{
return $this->redirect($this->generateUrl('reuzze_reuzze_homepage'));
}
$user = new Users();
$person = new Persons();
$address = new Addresses();
$region = new Regions();
$role = new Roles();
$address->setRegion($region);
$user->setPerson($person);
$user->setUserRating('1');
$user->setRole($role);
$person->setAddress($address);
$address->setRegion($region);
$role->setRoleName('Student');
$form = $this->createForm(new RegisterType(), $user);
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if($form->isValid())
{
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($user->getuserPassword(), $user->getuserSalt());
$user->setuserPassword($password);
$user->setRole($role);
$date = new \DateTime('NOW');
//$user->setuserId('1');
$user->setuserCreated($date);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->persist($person);
$entityManager->persist($address);
$entityManager->persist($region);
$entityManager->persist($role);
$entityManager->flush();
return $this->redirect($this->generateUrl('reuzze_reuzze_homepage'));
}
}
return $this->render('ReuzzeReuzzeBundle:User:register.html.twig', array(
'form' => $form->createView()
));
}
My RegisterType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('person' , new PersonType())
->add('userUsername' , 'text', array(
'label' => 'Username',
'attr' => array('placeholder' => 'Username')
))
->add('userEmail' , 'email', array(
'label' => 'E-mailadres',
'attr' => array('placeholder' => 'E-mail address')
))
->add('userSalt' , 'repeated', array(
'type' => 'password',
'first_name' => 'password',
'second_name' => 'confirm',
'first_options' => array(
'attr' => array('class' => 'form-control', 'placeholder' => 'Password'),
'label' => 'Password',
),
'second_options' => array(
'label' => 'Repeat Password',
'attr' => array('class' => 'form-control', 'placeholder' => 'Repeat Password'),
),
'invalid_message' => 'The passwords are not identical!',
)
);
}
Users Model (userId)
/**
* #var integer
*
* #ORM\Column(name="user_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $userId;
/**
* Set userId
*
* #param integer $userId
* #return Users
*/
public function setUserId($userId)
{
$this->userId = $userId;
return $this;
}
/**
* Get userId
*
* #return integer
*/
public function getUserId()
{
return $this->userId;
}
The only thing that works is when I put $user->setuserId('1'); in the Usercontroller register action. But obviously that isn't what I want, someone has a fix?
If I comment $entityManager->persist($user); in my UserController it creates all the other objects except for the User, but I don't get an error in this case.
The solution:
delete all the orm.yml files in Resources > config > doctrine

Doctrine 2: Understand how entities works with doctrine 2

I have 3 Entities: Person, Affiliation and PersonAffiliation.
In my form, I will display each affiliation as a checked checkbox.
Nowm when the user uncecks the checkbox and click submit, this affiliation should be removed from the PersonAffiliation table.
The problem is that when I submit without unchecking, my data are duplicated.
Example: aff1 and aff2. When both checked and submit, I will then get aff1 aff1 aff2 aff2.
The same, If I uncheck aff2, I will then have aff1 aff1.
The error is probably somewhere in using the doctrine:
Here is how I am managing that:
Entity Persom
#ORM\OneToMany(targetEntity="PersonAffiliation", mappedBy="person", cascade={"persist", "remove"})
protected $affiliations;
Entity Affiliation:
#ORM\OneToMany(targetEntity="PersonAffiliation", mappedBy="affiliation")
protected $person_affiliations;
Entity PersonAffiliation
#ORM\ManyToOne(targetEntity="Person", inversedBy="affiliations")
#ORM\JoinColumn(name="person_id", referencedColumnName="id")
protected $person;
#ORM\ManyToOne(targetEntity="Affiliation", inversedBy="person_affiliations")
#ORM\JoinColumn(name="affiliation_id", referencedColumnName="id")
protected $affiliation;
An idea on how to resolve that?
Thank you.
EDIT:
Cotroller part:
foreach( $enquiry->getAffiliations() as $aff )
{
$pAff = new PersonAffiliation();
$pAff->setPersonId( $person->getId() );
$pAff->setAffiliationId( $aff->getAffiliation()->getId() );
$pAff->setPerson( $person );
$pAff->setAffiliation( $aff->getAffiliation() );
$em->persist($pAff);
$em->flush();
}
Form Part:
public function buildForm(FormBuilder $builder, array $options)
{
$person = $this->person;
$user = $this->user;
$builder->add('firstname', 'text');
$builder->add('middlename', 'text', array('required'=>false));
$builder->add('lastname', 'text');
$builder->add('sex', 'choice', array( 'choices' => array('m' => 'Male', 'f' => 'Female'),
'required' => true,
'multiple' => false,
'expanded' => true));
$builder->add('email', 'text', array('required'=>false));
if( $this->addAffiliations ) {
$builder->add('affiliations', 'entity', array(
'label' => 'Athor\'s affiliations',
'class' => 'SciForumVersion2Bundle:PersonAffiliation',
'query_builder' => function($em) use ($person, $user){
return $em->createQueryBuilder('pa')
->where('pa.person_id = :pid')
->setParameter('pid', $person->getId());
},
'property' => 'affiliation',
'multiple' => true,
'expanded' => true,
));
}
}
In the Person entity :
/**
* #ORM\ManyToMany(targetEntity="Affiliation", inversedBy="people")
* #ORM\JoinTable(name="PersonAffiliation")
*/
protected $affiliations;
And in the Affiliation entity :
/**
* #ORM\ManyToMany(targetEntity="Person", mappedBy="affiliations")
*/
protected $people;
You made a $em->flush() on each iteration of the foreach. It should be done after the end of foreach isnt'it ?
Moreover, you may use a ManyToMany relation.

Categories