symfony2 entities data not persisted - symfony

I'm trying to persist a new entity, a "member", which has a contact field. The contact field is another entity, composed of a mail and a phone field. When I try to persist a new member, I add an email and a phone number, but the phone is not persisted. I did a var_dump over the object in my controller, and I found out that the private phone => null but doctrine added a new attribute : public phones => <the actual phone number>. This attribute doesnt exist in my entity.. What did I do wrong ? the relation between member and contact is
#ORM\OneToOne(targetEntity="Interne\FichierBundle\Entity\Contact", cascade={"persist", "remove"})
Thanks a lot for your help
EDIT :
result of the var_dump over my"member", for the contact entry :
private 'contact' =>
object(Interne\FichierBundle\Entity\Contact)[891]
private 'id' => null
private 'telephone' => null
private 'email' => string 'test#gmail.com' (length=25)
public 'telephones' => float 2187187392749
As you can see, telephone is empty, but telephones isnt. Problem is, there are no telephones attribute in my entities.

Probably your setter is not ok. Please check that your telephone setter method is:
public function setTelephone($telephone)
{
$this->telephone = $telephone;
}

Related

User(Serializable) must not be accessed before initialization symfony

When i try to connect as a user (my user entity implement UserInterface), i always get this error:
Typed property Symfony\Component\Security\Core\Exception\AccountStatusException::$user must not be accessed before initialization
At: D:\cours\symfony\blog\vendor\symfony\security-core\Exception\AccountStatusException.php:45
So i implement *Serializable* like someone says it here: https://github.com/symfony/symfony/issues/38274#issuecomment-697231222 like this:
public function serialize(): array {
return ['id' => $this->getId(), 'email' => $this->getEmail(), 'password' => $this->getPassword(), 'roles' => $this->getRoles()];//FIXME ajouter rôle?
}
public function unserialize($serialized): void {
list($this->id, $this->name, $this->email, $this->roles) = unserialize($serialized);
}
But i still get "User must not be accessed before initialization". 🤔 So maybe implementing \Serializable is the old way to do it (from 2020).
I just need to update all my bundle. Like my last edit suggested: Somes of my bundles was too old.

Doctrine weird behavior, changes entity that I never persisted

I have this situation:
Symfony 4.4.8, in the controller, for some users, I change some properties of an entity before displaying it:
public function viewAction(string $id)
{
$em = $this->getDoctrine()->getManager();
/** #var $offer Offer */
$offer = $em->getRepository(Offer::class)->find($id);
// For this user the payout is different, set the new payout
// (For displaying purposes only, not intended to be stored in the db)
$offer->setPayout($newPayout);
return $this->render('offers/view.html.twig', ['offer' => $offer]);
}
Then, I have a onKernelTerminate listener that updates the user language if they changed it:
public function onKernelTerminate(TerminateEvent $event)
{
$request = $event->getRequest();
if ($request->isXmlHttpRequest()) {
// Don't do this for ajax requests
return;
}
if (is_object($this->user)) {
// Check if language has changed. If so, persist the change for the next login
if ($this->user->getLang() && ($this->user->getLang() != $request->getLocale())) {
$this->user->setLang($request->getLocale());
$this->em->persist($this->user);
$this->em->flush();
}
}
}
public static function getSubscribedEvents()
{
return [
KernelEvents::TERMINATE => [['onKernelTerminate', 15]],
];
}
Now, there is something very weird happening here, if the user changes language, the offer is flushed to the db with the new payout, even if I never persisted it!
Any idea how to fix or debug this?
PS: this is happening even if I remove $this->em->persist($this->user);, I was thinking maybe it's because of some relationship between the user and the offer... but it's not the case.
I'm sure the offer is persisted because I've added a dd('beforeUpdate'); in the Offer::beforeUpdate() method and it gets printed at the bottom of the page.
alright, so by design, when you call flush on the entity manager, doctrine will commit all the changes done to managed entities to the database.
Changing values "just for display" on an entity that represents a record in database ("managed entity") is really really bad design in that case. It begs the question what the value on your entity actually means, too.
Depending on your use case, I see a few options:
create a display object/array/"dto" just for your rendering:
$display = [
'payout' => $offer->getPayout(),
// ...
];
$display['payout'] = $newPayout;
return $this->render('offers/view.html.twig', ['offer' => $display]);
or create a new non-persisted entity
use override-style rendering logic
return $this->render('offers/view.html.twig', [
'offer' => $offer,
'override' => ['payout' => $newPayout],
]);
in your template, select the override when it exists
{{ override.payout ?? offer.payout }}
add a virtual field (meaning it's not stored in a column!) to your entity, maybe call it "displayPayout" and use the content of that if it exists

Perform operation on an entity before its persistence

I am trying to do a PUT request on an entity, from an angular 5 client to API Platform.
On the angular side, I retrieve an address via Google maps. This address is a property of an Entity JourneyAddress, so I send a PUT request to API Platform with my JourneyAddress model, with an address property which is an array of google map address components (street_address, locality, etc.).
Now I need to perform some operations on this property before submitting it to Doctrine, ie I need to match the locality given by google with a Locality in our Database.
I was thinking about a listener which would listen for JourneyAddress prePersist and preUpdate events, find the locality instance I need with something like LocalityRepository::findBy(['name' => 'Paris']), update the journeyAddress instance and give it back to Doctrine to perform persist/update operations.
The problem is that API Platform checks if the type of the data submitted corresponds to what Doctrine expects. I sent API Platform an array, but Doctrine actually expects a string.
For context, the array sent could be :
src/Doctrine/EventListener/JourneyAddressListener.php:32:
object(App\Entity\JourneyAddress)[2615]
private 'id' => null
private 'title' => string 'dzfkdqsmlfjsldkflm' (length=18)
private 'search' => string 'mlsqjfkldsjfsqdjlmf' (length=19)
private 'address' =>
array (size=8)
'street_number' => string '2650' (length=4)
'route' => string 'Avenida Rivadavia' (length=17)
'sublocality_level_1' => string 'Balvanera' (length=9)
'administrative_area_level_2' => string 'Comuna 3' (length=8)
'administrative_area_level_1' => string 'Buenos Aires' (length=12)
'country' => string 'Argentine' (length=9)
'postal_code' => string 'C1034' (length=5)
'postal_code_suffix' => string 'ACS' (length=3)
private 'latitude' => float 50.6507791
private 'longitude' => float 3.0657951
private 'media' => null
private 'indication' => string 'klqsjflkmqjfkqjfksflmlqfmlks' (length=28)
I need to extract the street_address and save it as the address property of my JourneyAddress, but the Doctrine entity is :
/**
* #ORM\Column(type="string", length=255)
* #Groups("journey")
* #Assert\Type("string")
* #Assert\NotBlank(
* message = "Le champs 'Adresse du point de départ' doit être rempli",
* groups={"departureFormValidation"}
* )
*/
private $address;
Is there a way that my listener will be used before actual API Platform type-checking ? I also tried to do a custom operation but the result was the same, type-checking always comes first and prevents any further action.
I could of course replace the type of address by array and then send ['my string'], but I feed it should not be that way.
Doctrine listeners are always executed after validation. There are built in api-platform (Symfony) event listeners that are executed before validation: https://api-platform.com/docs/core/events/ PRE_VALIDATE seems like a good place for this.
However, having mixed data type (array, string) for the same field is not a good idea, consider using a separate model class for your array address or a separate unmapped field.

Symfony-Disabling specific field validations from controller

I am using Symfony 2.7.6. I have created an entity called employee and its interactive forms are generated using doctrine crud generator. Entity have the following fields
1. id
2. firstname
3. lastname
4. email
5. username
6. password
validations are working as expected from user registration form for all the fields.
ISSUE: I have created a login form and i want to suppress validation for the fields firstname, lastname and email and exclude these elements from rendering on my page
I have modified my controller like this for rendering my form
$entity = $em->getRepository('XXXEmployeeBundle:Employee');
$form = $this->createForm(new \XXX\EmployeeBundle\Form\EmployeeType(), $entity, array(
'action' => $this->generateUrl('user_login'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Update'));
$form->remove('firstname');
$form->remove('lastname');
$form->remove('email');
$form->handleRequest($request);
This works fine when the from is rendering as the fields are excluded from the form. But my $form->isvalid() is returning false. As I have printed the errors using $form->getErrorsAsString() method, its showing like:
firstname: ERROR: First name cannot be empty. lastname: ERROR: Last name code cannot be empty. employeeFirstName: ERROR: Employee first name cannot be empty. email: ERROR: Email cannot be empty.
Is this the right method to achieve this functionality?? Please help me in solving the issue. Thanks
In your entity you mush include nullable=true like this
/**
* #ORM\Column(type="string", nullable=true)
*
* #var string
*/
protected $nombre;
And telling doctrine that is nullable, neither backend/frontend check the value.
Greetings !
I think problem in logic.
When you create registration form - you want to create and save new
entity.
When you create login form - you want to compare login and
password between form and entity.
So. You should create special form class for login (not from registration) and don't set data-enitity (second parameter in createForm function)
And, please check if you have the same form object in controller action that handles this form.
You can make a work around
Get all form's errors within your controller by
$form->getErrors()
and then loop over them, if it's the error you know it would happen, just bypass it on purpose and process further.
if ($form->isSubmitted()) { // remove $form->isValid() check
foreach($form->getErrors() as $error) {
// check if it's expected error, then do nothing and proceed further for user
// if it's unexpected throw an exception, catch them below and add error message to session flashbag. or something similar
}
}

What's the 'correct' way to include unrelated entities subset in a form?

Imagine three entities - Account, Address, Purchase. Account has a OneToMany relationship with Address. A Purchase is related to an Account, but not with an Address - it does however have a text field for the address (this is because addresses can change, I don't want the address directly related). On the users' account page they can add addresses. Whilst logged into the site, a Purchase id is stored in the session and used to retrieve the Purchase details when required.
What I want to do on the checkout page is display a list of all the addresses a user currently has in a <select>, allow them to pick one, and update the address in the current Purchase. $account->getAddresses() exists and will show the addresses relevant to the user.
I have read http://symfony.com/doc/current/reference/forms/types/collection.html and http://symfony.com/doc/current/cookbook/form/form_collections.html and can't see how to apply it to this situation, although an embedded form isn't really necessary - I don't want to change other details of the Purchase at that stage.
So my question is (at least one of): how do I pass the results of $account->getAddresses() to a form type? Or in the form type, should I use an entity field type, and if so, how do I get the custom query_builder to contain the current user in a form type? Or how else should I do this?
You need to pass the entity in to the Type's constructor and then use it to get the parameter.
Class YourType extends AbstractType
{
private $account;
public function __construct($account)
{
$this->account = $account;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$accountId = $account->getAccountId();
$builder->add('addressId',
'entity',
array('class' => 'YourBundle:Address',
'query_builder' => function(EntityRepository $er) use ($accountId) {
return $er->createQueryBuilder('a')
->where('a.accountId = ?1')
->setParameter(1, $accountId)));
}
}

Resources