Laravel Eloquent combine Model::forceCreate and Model::firstOrCreate - php

With Laravel & Eloquent, I'd like to :
Create a model, unless it already exists into the database (like Model::firstOrCreate allows)
At the same time, pass it a few attributes, including some which are not listed in the $fillable array of the model (like Model::forceCreate allows).
But how do I combine the capacities of firstOrCreate and forceCreate? Apparently, Model::forceFirstOrCreate doesn't exist!

Use the unguarded method:
$model = Model::unguarded(function() {
return Model::firstOrCreate($attributes);
});

Related

Does a one-to-one relationship in Laravel always need first()?

I have a one-to-one relationship between User and UserSettings models,
But (after $user = auth()->user()) when I try $user->settings()->something it throws an Undefined property error.
It's gone when I use $user->settings()->first()->something...
My question is, is this how it's supposed to work? or am I doing something wrong?
You cannot directly run $user->settings()->something.
Because when you call $user->settings(), it just return Illuminate\Database\Eloquent\Relations\HasOne object.
So it is not the model's object, you need to take the model's object and call its attribute like this.
$user->settings()->first()->something;
Dynamic Properties
Since you have one-to-one relationship between User and UserSettings.
If you have a one-to-one relationship in your User model:
public function settings()
{
return $this->hasOne('App\Models\UserSettings', 'user_id', 'id');
}
According to Laravel doc
Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model:
Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method. It will then be accessible via a dynamic property by the same name as the relation.
So you can use eloquent's dynamic properties like this:
$user->settings->something; // settings is the dynamic property of $user.
This code will give you a result of collection.
$user->settings;
So calling 'something' is not available or it will return you of null, unless you get the specific index of it.
$user->settings()->something
while this one works because you used first() to get the first data of collection and accessed the properties of it .
$user->settings()->first()->something
The first method returns the first element in the collection that passes a given truth test
see docs here laravel docs
If you want to get the user settings itself simply do this:
$user->settings
Then you can get the fields of the settings doing this:
$user->settings->something
When you do this $user->settings() you can chain query after that. E.g.
$user->settings()->where('something', 'hello')->first()
That's why the output of $user->settings and $user->settings()->first() are the same.
Auth only gives you user info;
Try the following code:
$user = User::find(auth()->user()->id);//and then
$user->settings->something;

save a belongsTo relationship

I have a classic one-to-many relationships, and I am trying to save the model of the belongsTo side.
The 2 models have these relationships:
// Model myModel
function domicile()
{
return $this->belongsTo('App\Address', 'domicile_id');
}
// Model Address
function myModels()
{
return $this->hasMany('App\MyModel', 'domicile_id');
}
This is what I am tryng to do to save it:
$myModel->domicile()->save($my_array);
With this code I get the error:
Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::save()
if I use this code (without the brackets):
$myModel->domicile->save($my_array);
I do not get any error but the model is not saved.
I know there is the method associate, but I need to update an existent record, not to save a new one.
Because $myModel->domicile()->save($my_array); is totally different to $myModel->domicile->save($my_array); :
$myModel->domicile() will produce a BelongsTo object, doesn't support the save because save is a method of HasMany instances, instead for BelongsTo instances you should use associate(YourModel)
$myModel->domicile will produce a Model object of the associated element, which support the save(array) method, but that array is a options array, as api says https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Model.html#method_save
So in other words, if you have a one (address) to many (domicile) relation, if you want to associate to the address one or many domiciles, you have to use save or saveMany (https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Relations/HasMany.html#method_save), instead if you want to associate to a domicile a address, you should use associate (https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Relations/BelongsTo.html#method_associate)... keep in mind that if you want to do this, you should call the properties with the brackets, in order to have back a HasMany object or a BelongsTo object, and not a Model or a Collection (which you will get if you call the properties without the brackets)
Instead of using the save function, in order to save a belongsTo relationships you have to use the fill function.
In this way:
$myModel->domicile->fill($my_array);
$myModel->domicile->save();
You must use associate() + save() in order to store a BelongsTo relationship:
$myModel->domicile()->associate($domicile);
$myModel->save();
See Laravel Docs

What's difference between Laravel Model functions "create" and "insert"?

Laravel Model allows two functions for inserting the values to the database table. They are
Create:
User::create(['id'=>1,'name'=>'stack']);
Insert:
User::insert(['id'=>2,'name'=>'overflow']);
I found they perform similar operations. What's difference between them?
insert() :
If you using insert() method you can't default created_at and updated_at database column
it will be null
DefaultUser::insert(['username' => $request->username, 'city' => $request->city, 'profile_image' => $request->profile_image]);
create() :
when we use create method you must define this model in fillable fields
Add in Your Model
protected $fillable = ['username','city', 'profile_image'];
Add your Controller
DefaultUser::create(['username' => $request->username, 'city' => $request->city, 'profile_image' => $request->profile_image]);
then we can use create method without **mass assignment error **
basically here , table defined fields are protected in your model
you should define which model attributes you want to make mass assignable. You may do this using the $fillable property on the model
The model does not have an insert, calling Model::insert results in a call to (the Query Builder) Builder::insert through the __call() magic method which then avoids the Eloquent benefits like setting the timestamps for created_at and updated_at fields.
It also avoids the Mass-assignment protection which Eloquent protects you from inserting unintentional data.
So I would always use create or setting each field separately (if you need to modify the incoming data) and call save() on the model instance.
Insert method :
The insert method accepts an array of column names and values.using this method you can insert data without specify fillable and guarded attribute on the model and here created_at and updated_at values put as NULL value by default.
User::insert(['userName'=>'manish','email'=>'test#gmail.com']);
Create method
The create method also used to insert a new model in a single line. It's instance will return you from that method. before using create() will need to specify fillable or guarded attribute on model its protect against mass-assignment by default and its auto fillable value for create_at and updated_at
User::create(['userName'=>'manish','email'=>'test#gmail.com'])
save()
save() method is used both for saving new model, and updating existing one. here you are creating new model or find existing one, setting its properties one by one and finally saves in database.
save() accepts a full Eloquent model instance
create()
while in creating method you are passing an array, setting properties in model and persists in the database in one shot.
create() accepts a plain PHP array

Accessing Eloquent Relationship Automatically when loaded

I am working on a project which requires me to get all the list of all information from a table --Just like in a blog, i used the all() method to do this but when i try to get the method i declared in my Model i get an error, saying
the collection instance does not exists
But when i use The
Model::find($id)->relationship()->name;
it works fine. Is there any way to load all relationship with the all() function in laravel.
Thanks for your help..
When you perform Model::find($id)->relationship(); you are actually accesing to the Dynamic relationships Properties
You need to convert it into a collection using Model::find($id)->relationship()->get();
Then you can perform any collection method to get the result you want. After doing this you can access to its attributes like this:
$model_varible = Model::find($id)->relationship()->get();
$model_variable = $model_variable->find($id)->name;
Let me know if this works for you.
You should use relationship without brackets to access the model:
Model::find($id)->relationship->name;
And use "with()" to populate the relationships:
Model::where('published', 1)->with('relationship')

How can I instantiate a new hasMany Eloquent relationship with at least one empty model?

I have a model (let's call it PageModel) with a hasMany relationship (let's call it rulesList). When I create a new PageModel, I want to default rulesList with at least one empty model. How can I do this in Eloquent?
Code Sample:
// Normal instantiation
$this->rulesList; // Equals NULL
// I can set it manually like so, but is that right?
$this->rulesList = Collection::make([new RulesListModel]);
// NOTE: Doing this does not create an empty model when PageModel is output as JSON
There isn't (to my knowledge) a way to do this within the relationship itself. The reason is that an eloquent model is defined by the database query return values.
You could set up some sort of null row in your database, but I would advise against that.
One way that may work: I think it is possible to create an eloquent model without running a query. I think something like EloquentModel::fill($attributes) would do it. Where $attributes is an array of attributes for your model e.g. array('title' => null, 'description' => null);
You'd have to create this manual model and then add it to your relationship.

Categories