phalcon 2.0.13 set data with magic setter to related model - php

I have a problem with phalcon model magic getter and setter.
I want to update like this tutorial :
https://docs.phalconphp.com/en/latest/reference/models.html#storing-related-records
But the thing is my proj is multi module and separated models folder.
So I have to use alias for hasOne and belongsTo
$this->hasOne('user_id', '\Models\UserProfile', 'user_id', array('alias' => 'UserProfile'));
and
$this->belongsTo('user_id', '\Models\CoreUser', 'user_id', array('alias' => 'CoreUser'));
What i want to do is like this.
$CoreUser = new CoreUser();
$user = $CoreUser->findFirst(array(
//...condition here to find the row i want to update
));
$user->assign($newUserData);
$user->setUserProfile($newProfileData);
$user->update();
But above this code only save user data and don't save Profile data at all. (have profile data -- confirmed)
So do you have any idea what the error is? if u know, Please help me or give me a tip.

I got it now.. when assigning like $user->UserProfile = $newUserProfile;
$newUserProfile should b a Model Object.
So my new code is
$CoreUser = new CoreUser();
$user = $CoreUser->findFirst(array(
//...condition here to find the row i want to update
));
$profile = $user->UserProfile; //$profile is now model object which related to $user
//assign new array data
$profile->assign($newProfileData);
$user->assign($newUserData);
/*
* can also assign one by one like
* $user->first_name = $newProfileData['first_name'];
* but cannot be like $profile = $newProfileData or $user->UserProfile = $newProfile
* since it's gonna override it the model with array
*/
$user->UserProfile = $profile;
$user->update(); // it's working now
Thanks to #Timothy for the tips too .. :)

Instead of doing
$profile = $user->UserProfile;
You should instantiate a new UserProfile object
// find your existing user and assign updated data
$user = CoreUser::findFirst(array('your-conditions'));
$user->assign($newUserData);
// instantiate a new profile and assign its data
$profile = new UserProfile();
$profile->assign($newProfileData);
// assign profile object to your user
$user->UserProfile = $profile;
// update and create your two objects
$user->save();
Note that this will always create a new UserProfile. If you want to use the same code to update and create a UserProfile, you can maybe do something like:
// ...
// instantiate a (new) profile and assign its data
$profile = UserProfile::findFirstByUserId($user->getUserId());
if (!$profile) {
$profile = new UserProfile();
}
$profile->assign($newProfileData);
// ...

Related

Laravel How to get AI id in controller before saving

I have tried to get the auto increment ID from the booking table before saving the new data's, but I have errors all the time.
This is the code in the controller:
public function addAppointment(Request $request) {
$user = auth()->user();
$booking = new Booking();
$booking->vac_center_id = $request->get('vaccination_center');
$booking->vac_id = $request->get('vaccination_id');
$booking->date_of_shot = $request->get('date_of_shot');
$booking->time = $request->get('time');
$booking->shot_number = $request->get('shot_number');
$booking->isDone = 0;
$booking->isCancelled = 0;
$booking->user_id = $user->id;
$booking->save();
$booking = new BookingHasVaccinationCenters();
//here below I want to get the auto increment id
$booking->booking_id->id;
$booking->vac_center_id = $request->get('vaccination_center');
$booking->save();
return redirect('/home');
}
This is the error that I had last time when I try to do this:
Attempt to read property "id" on null
instead of this
$booking = new BookingHasVaccinationCenters();
//here below I want to get the auto increment id
$booking->booking_id->id;
$booking->vac_center_id = $request->get('vaccination_center');
$booking->save();
use below code
$bookingHasVaccination = new BookingHasVaccinationCenters();
//change here
$bookingHasVaccination->booking_id = $booking->id;
$bookingHasVaccination->vac_center_id = $request->get('vaccination_center');
$bookingHasVaccination->save();
Note : always try to define variable with the name same as model class while crud operations
Your error is that you declare with the same name the variable $booking , when you
save the $booking you should declare a instance of object with other name for example
$bookingvaccine->booking_id = $booking->id;
I know your questions has already been answered, but let me share another way of doing what you are doing, so you prevent this errors and your code is better.
If you have relations between this tables/models (relations functions created) then you can use the relation to create new models between them, without the need of sharing or passing the parent model's ID.
Assuming your User's relation name with Booking is bookings and for Booking -> BookingHasVaccinationCenters relation (strange name) is bookingHasVaccinationCenters, you should be able to do this:
public function addAppointment(Request $request)
{
$booking = $request->user()
->booking()
->create([
'vac_center_id' => $request->input('vaccination_center'),
'vac_id' => $request->input('vaccination_id'),
'date_of_shot' => $request->input('date_of_shot'),
'time' => $request->input('time'),
'shot_number' => $request->input('shot_number'),
'isDone' => false,
'isCancelled' => false,
]);
$booking->bookingHasVaccinationCenters()->create([
'vac_center_id' => $request->input('vaccination_center'),
]);
return redirect('/home');
}
Another super small tip, remember to cast isDone and isCancelled to boolean, so you can use those fields as boolean so you can do true or false instead of 1 or 0.
And last tip, try to always stick to the Laravel's conventions: snake_case column names, isDone and isCancelled should be is_done and is_cancelled.

Laravel 5.2 updated table now model wont work

I updated my notes table with 4 new columns: classification, pod, sampled, followup.
I would update my model like so (which still works like this):
$note->account_id = $account->id;
$note->name = $request->input('account-note-title');
$note->description = $request->input('account-note-description');
$note->save();
But if I try and post to the new columns it fails.
$note->account_id = $account->id;
$note->name = $request->input('account-note-title');
$note->description = $request->input('account-note-description');
$note->classification = $request->input('account-note-classification');
$note->pod = $request->input('account-note-pod');
$note->sampled = $request->input('account-note-samplebrand');
$note->followup = $request->input('account-note-followup-date');
$note->save();
Do I have to refresh the model or anything?
You can create new value using laravel Create methode like below
ModelName::create($request->all())
In this case you have to put your all input field in the $fillable variable of MODEL.
You can update item using the following method
$model = findOrFail($id)
$model->update($request->all())

Symfony2 get new value after UPDATE query

in my Symfony2.8 app I got the following controller:
public function changetariffAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$user = $this->container->get('security.context')->getToken()->getUser();
$userid = $user->getId();
$tariff = $user->getTariff();//tariff1 here
$paymentForm = $this->createPaymentForm($user);
$paymentForm->handleRequest($request);
if($tariff != 'tariff2') {
$query = $em->createQuery('UPDATE My\UserBundle\Entity\User u SET u.tariff = :tariff2 WHERE u.id = :userid');
$query->setParameter('userid', $user->getId());
$query->setParameter('tariff2', 'tariff2');
$query = $query->getResult();//returns 1 here, tariff field in DB is set to tariff2 as expected
$query = $em->createQuery('SELECT u FROM My\UserBundle\Entity\User u WHERE u.id = :userid');//getting once again user entity but it did not change
$query->setParameter('userid', $user->getId());
$user = $query->getResult();
$tariff_upd = $user[0]->getTariff();//tariff1 here but I need tariff2!
//Also I tried to persist and flush user entity here but it did not work
return $this->render('MyBundle:Pages:tariffchangesuccess.html.twig', array(
'user' => $user,
'form' => $paymentForm->createView(),
'tariff' => $tariff_upd //still tariff1 but I need tariff2
));
}
return $this->render('MyBundle:Pages:tariffchangesuccess.html.twig', array(
'user' => $user,
'form' => $paymentForm->createView(),
'tariff' => $tariff
));
}
My Controller works ok and all the values are updated in my DB as expected but new values (tariff2) are not rendered in my twig template. New values are rendered only when I update the page in my browser (hit F5), but this is not an expected behavior. Any ideas how to fix that? Thank you.
Doctrine use something similar as cache and maybe your use of queries instead of natives methods short-circuit this system. Docrtine can handle your entities and know what to record and has been changed etc. But you have to use Doctrine functions or repositories for that, and not do it througt custom queries... The Doctrine way should be something like:
$em = $this->getDoctrine()->getManager();
$userid = $this->container->get('security.context')->getToken()->getUser()->getId()
// Get object user from DB values
$user = $em->getRepository('My\UserBundle:User')->findOneById($userid );
// Update tarif in the user object
$user->setTariff('tariff2');
// Let Doctrine write in the DB. The persist() may not be necesary as Doctrine already manage this object, but it's a good practise.
$em->persist($user);
$em-> flush();
// Doctrine should already have update the $user object, but if you really really want to be sure, you can reload it:
$user = $em->getRepository('My\UserBundle:User')->findOneById($userid );
You can use the refresh method of the EntityManager in order to:
Refreshes the persistent state of an entity from the database,
overriding any local changes that have not yet been persisted.
So add the refresh call, as example:
$query = $em->createQuery('SELECT u FROM My\UserBundle\Entity\User u WHERE u.id = :userid');//getting once again user entity but it did not change
$query->setParameter('userid', $user->getId());
$user = $query->getResult();
// Force refresh of the object:
$em->refresh($user);
$tariff_upd = $user[0]->getTariff();//tariff1 here but I need tariff2!
Hope this help

Flush One-To-Many, Self-referencing

I have self-referencing one-to-many relationship (I did it in accordance with Documentation: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-self-referencing )
Now I want flush new element to Entity, but how can I use ID of new flush element to put it in referencing place?
I try with:
$newProject->setSubprojectId($newProject);
and with:
$newProject->setSubprojectId($newProject->getId());
but I think that it's impossible to get ID of object before flush it. I'm right?
My code looks like:
/**
* #Route("/project/manage", name="project_edit");
*/
public function registerAction(Request $request)
{
$user = $this->get('security.token_storage')->getToken()->getUser();
$newProject = new Project();
$newProject->setIsActive(1);
$newProject->setOwner($user);
$newProject->setCreateDate( new \DateTime() );
$newProject->setSubprojectId($newProject);
$formProject = $this->createForm(AddProject::class, $newProject);
$formProject->handleRequest($request);
if($formProject->isSubmitted() && $formProject->isValid()){
$em = $this->getDoctrine()->getManager();
$em->persist($newProject);
$em->flush();
return $this->render('xxx/projectEdit.html.twig', array(
'form' => $formProject->createView(),
));
}
return $this->render('xxx/projectEdit.html.twig', array(
'form' => $formProject->createView(),
));
}
EDIT
I found different solutions but the question remains valid - it's possible to get this id before flush or to flush id for two columns in the same time?
You could try setting cascade persist, however why not just do:
$em = $this->getDoctrine()->getManager();
$em->persist($newProject);
$em->flush();
$newProject->setSubProject($newProject); // *why* do you want to do this?
$em->persist($newProject);
$em->flush();
You shouldn't need to mess about with setting ids directly. You should be able to accomplish this by using the setter on your object and doctrine should take care of the ids for you.

Models incorrectly try to be replaced instead of update

I try to update the name of a user id=1. I tried following code (v 1.3). But instead of updating, it try to relace the user and var_dump($n->getMessages()); output error relating to not null attributes.
class UserApi extends Phalcon\DI\Injectable{}
$n=new User;
$n->id=1;
$n->name='Tom';
$n->save(); //or even $n->update()
User::findFirst(1)->save(); works. But I need to use a single code for bothe create and update operations.
If you want phalcon to do an update and not an insert you have to load the model from the database before changing its properties.
To use the same code for both the create and update operations simply do the following.
$user = User::findFirst($userId);
if (!$user) {
// Create new user
$user = new User();
$user->id = $userId;
}
// Set/update values
$user->name = $userName;
$user->save();
Hope this helps.

Categories