Laravel eloquent firstOrNew method doesn't update or insert - php

I have a problem with firstOrNew() method of the Laravel eloquent class. the problem is that when I give the method some attributes and values and call save() on the model, it doesn't get saved (inserted or updated).
PHP :
<?
$flightModel = Flight::firstOrNew([
'arrival' => $flightData['arrival'],
'plane' => $flightData['plane']
]);
$flightModel->departure = $flightData['departure'];
$flightModel->save();//this doesn't save any data
But when I try this with a new model it gets saved :
<?
$flightModel = new Flight();
$flightModel->arrival = $flightData['arrival'];
$flightModel->plane = $flightData['plane'];
$flightModel->departure = $flightData['departure'];
$flightModel->save();
Thanks for helping.

Related

Update a Relationship Model with one Line - Laravel

I have a massive edit page and the values are taken from 4 tables. I have them all in a object and sorted which ones go where. Although when I call my main model, can I update its relationship by passing in the object or array?
Main Model
$officiant = Officiant::find($id);
Its relationship is the "detail" and "profile"
Example:
$officiant->fname = $request->fname;
$officiant->lname = $request->lname;
$officiant->phone = $request->phone;
$profile = new \StdClass();
$profile->gender = $request->gender;
$profile->profile = $request->profile;
$detail = new \StdClass();
$detail->street = $request->street;
$detail->city = $request->city;
I can update officiant by passing it like this
$officiant->update(array ($officiant));
Although, can I update the detail one by doing something similar, as in
$officiant->detail->update(array ($detail));
$officiant->profileupdate(array ($profile));
If you are updating via a relation ship it should be
$officiant->detail()->update(array ($detail));
Using ->detail() instead of ->detail sends a query builder instance that can be chained with update().

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())

phalcon 2.0.13 set data with magic setter to related model

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);
// ...

ZF2 Doctrine Hydratation

When I query a table, for example:
$query = $this->entityManager->createQueryBuilder();
$query->select('TaPost')->from("Application\Entity\TaPost", 'TaPost');
return $query->getQuery()->getResult()
)
I get an array of object "Tapost".
Is there an easy way (and not ruining performance) to get an array of a given new class ? An equivalent to zend/db/sql:
new HydratingResultSet(new \Zend\Stdlib\Hydrator\ClassMethods(), new myNewClass())
Do you want to get directly array result? There are two way. You get an entity object which is \Application\Entity\TaPost. You can create a method to your entity like that
class TaPost {
// Your entity attributes and methods
// ...
public function toArray()
{
return array(
"id" => $this->getId(),
"title" => $this->getTitle(),
"description" => $this->getDescription(),
// ...
);
}
}
And use them them when your for loop.
Another solution is, you can use Doctrine HYDRATE_ARRAY
$results = $query->getQuery()->getResult( Doctrine\ORM\Query::HYDRATE_ARRAY );
Try to use doctrine hydrator instead of zend hydrator.
$model = new \Blog\Model\Post();
$hydrator = new \DoctrineModule\Stdlib\Hydrator\DoctrineObject($this->getEntityManager(), 'Blog\Model\Post');
$model = $hydrator->hydrate($array, $model);
thank you for your answer but that's not exactly my objective.
I'm trying to do the tutorial and, instead of zend-db-sql i'm using Doctrine.
I have a method findAll() which have to return an array of objects from class PostInterface based on a custom model (post).
With Doctrine, I get an array of TaPost (TaPost being an entity of Doctrine) but I need to return an array of Post.
How can I tell Doctrine to automatically hydrate Post and not TaPost ? will i need to made a foreach on my doctrine result and hydrate an object Post one by one ?
ps: with zned-sql, they do it when getting the result:
$resultSet = new HydratingResultSet(new \Zend\Stdlib\Hydrator\ClassMethods(), new \Blog\Model\Post());
return $resultSet->initialize($result);

Update without touching timestamps (Laravel)

Is it possible to update a user without touching the timestamps?
I don't want to disable the timestamps completly..
grtz
Disable it temporarily:
$user = User::find(1);
$user->timestamps = false;
$user->age = 72;
$user->save();
You can optionally re-enable them after saving.
This is a Laravel 4 and 5 only feature and does not apply to Laravel 3.
In Laravel 5.2, you can set the public field $timestamps to false like this:
$user->timestamps = false;
$user->name = 'new name';
$user->save();
Or you can pass the options as a parameter of the save() function :
$user->name = 'new name';
$user->save(['timestamps' => false]);
For a deeper understanding of how it works, you can have a look at the class \Illuminate\Database\Eloquent\Model, in the method performUpdate(Builder $query, array $options = []) :
protected function performUpdate(Builder $query, array $options = [])
// [...]
// First we need to create a fresh query instance and touch the creation and
// update timestamp on the model which are maintained by us for developer
// convenience. Then we will just continue saving the model instances.
if ($this->timestamps && Arr::get($options, 'timestamps', true)) {
$this->updateTimestamps();
}
// [...]
The timestamps fields are updated only if the public property timestamps equals true or Arr::get($options, 'timestamps', true) returns true (which it does by default if the $options array does not contain the key timestamps).
As soon as one of these two returns false, the timestamps fields are not updated.
Above samples works cool, but only for single object (only one row per time).
This is easy way how to temporarily disable timestamps if you want to update whole collection.
class Order extends Model
{
....
public function scopeWithoutTimestamps()
{
$this->timestamps = false;
return $this;
}
}
Now you can simply call something like this:
Order::withoutTimestamps()->leftJoin('customer_products','customer_products.order_id','=','orders.order_id')->update(array('orders.customer_product_id' => \DB::raw('customer_products.id')));
To add to Antonio Carlos Ribeiro's answer
If your code requires timestamps de-activation more than 50% of the time - maybe you should disable the auto update and manually access it.
In eloquent when you extend the eloquent model you can disable timestamp by putting
UPDATE
public $timestamps = false;
inside your model.
If you need to update single model queries:
$product->timestamps = false;
$product->save();
or
$product->save(['timestamps' => false]);
If you need to update multiple model queries use
DB::table('products')->...->update(...)
instead of
Product::...->update(...)
For Laravel 5.x users who are trying to perform a Model::update() call, to make it work you can use
Model::where('example', $data)
->update([
'firstValue' => $newValue,
'updatedAt' => \DB::raw('updatedAt')
]);
As the Model::update function does not take a second argument anymore.
ref: laravel 5.0 api
Tested and working on version 5.2.
I ran into the situation of needing to do a mass update that involves a join, so updated_at was causing duplicate column conflicts. I fixed it with this code without needing a scope:
$query->where(function (\Illuminate\Database\Eloquent\Builder $query) {
$query->getModel()->timestamps = false;
})
For Larvel 5.1, you can also use this syntax:
Model::where('Y', 'X')
->update(['Y' => 'Z'], ['timestamps' => false]);
Laravel 9 and above
Taken directly from the documentation.
If you would like to perform model operations without the model having its updated_at timestamp modified, you may operate on the model within a closure given to the withoutTimestamps method:
Model::withoutTimestamps(fn () => $post->increment(['reads']));
So in OP's case, the code will be something like this:
User::withoutTimestamps(function () {
$user = User::find(1);
$user->name = 'John';
$user->save();
});
Laravel 8
Doing some overrides using seeders and on one test I have:
$item = Equipment::where('name', item_name))->first();
$item->description = 'some description';
$item->save(['timestamps' => false]);
Which works fine, but if I use firstOrNew then the $item->save(['timestamps' => false]); does not work.
// This does not work on Seeder file
$item = Model::firstOrNew(['name' => 'item_name']);
$item->description = 'some description';
$item->save(['timestamps' => false]);
// Doing the following works tho
$item = Model::firstOrNew(['name' => 'item_name']);
$item->description = 'some description';
$item->timestamps = false;
$item->save();
So in some cases you would use one over the other... Just check with die and dump to see whether +timestamps: false
$item->timestamps = false;
$item->save();
or
$item->save(['timestamps' => false]);
Edit:
In my project I opted using $item->timestamps = false; so I would recommend using this as well. Here is a working snippet from laravelplayground:
https://laravelplayground.com/#/snippets/4ae950f2-d057-4fdc-a982-34aa7c9fee15
Check the HasTimestamps on Laravel api:
https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Concerns/HasTimestamps.html
and the save method on Model:
https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Model.html
The save method still accepts options but passing timestamps will not work.

Categories