Laravel - Model ID guarding - php

Say we have a Topic submission html form which uses the following input fields names:
name
text
At the controller level we may have written something like this:
public function create(Request $request) {
// Validation logic ...
Topic::create($request->all());
}
What if a client user add an id input field:
id
name
text
Will Laravel populate also the id field of the new Model object?
Can I guard the id of a Model, or should I use $request->only()?

You do not need to use $fillable array or $guarded for primary key which is id by default. Eloquent will not populate primary key when you're using create() method.

Laravel has two ways of achieving this:
class Topic extends Model {
protected $fillable = [
"name" , "text"
];
}
Alternatively there is the opposite:
class Topic extends Model {
protected $guarded = [ "id" ];
}
$fillable contains what is allowed to be mass assigned (via fill or the constructor etc) in the model and $guarded contains what should never be mass assigned.
More info at https://laravel.com/docs/5.5/eloquent#mass-assignment

Related

Remove specific field from model before creating after processing laravel

I am trying to make a trait for storing images for models. I am not able to remove the thumbnail from the model.
Is there any way to remove the thumbnail field from the model because there is no field like a thumbnail in the table?
trait ModelHelpers
{
protected static $thumbnail;
public static function boot()
{
parent::boot();
self::creating(function($model){
$collection = collect($model);
self::$thumbnail = $collection->only('thumbnail');
$collection->except(['thumbnail']);
$model->ignoreField('thumbnail');
// ... code here
});
}
}
OR
Is there any way to add the data in the model that don't process while mysql query but is available in the model for processing before or after creating?
Right now I am adding the thumbnail key in fillable to get into the model but it is processed while the insert query that i don't want to:
protected $fillable = ['user_id', 'title', 'meta_title', 'slug', 'summary', 'published','published_time', 'thumbnail'];
$fillbale is used to define the properties you want to use in inserting.
If you want to skip some properties to insert it, you must use $guarded

How to sync if model id is hidden field?

I'm trying to sync data to pivot table for my model. But my Recipe model has an hidden id field. Like this;
protected $hidden = ['id', 'content', 'difficulty_id'];
And when I try to sync relationships to pivot table, recipe_id becomes zero. If I remove id from $hidden above, it sync id without any problem. I also tried to call makeVisible("id") for the model but didn't help.
$changedMeals = $record->meals()->sync($meals);
How can I sync id when keeping it in $hidden?
Thank you very much...
currently, im using pivot with $hidden in primary, and foreign not in pivot, im using sync($request->field_to_sync) and im using validator to validate ids, and it worked
eg:
class Recipe ...
{
protected $hidden = ['id'];
public function meals(){
return $this->belongsToMany(Pivot::class);
}
}
class Meals ...
{
protected $hidden = ['id'];
public function recipe(){
return $this->belongsToMany(Pivot::class);
}
}
so i assume u are using sync() in your code without using Request::input(), you can try this :
$meals = Meals::select('id')->get()
->map(function($value, $key){
return $value->setVisible(['id']);
});
then u can use sync() like this :
Recipe::find(1)->meals()->sync($meals);

Get specific columns using with() in laravel with appends fields in model

In my User model, I have an appends fields:
protected $appends = [
'is_admin'
];
It will appends is_admin field in every request by using with() eager loading. However, in some scenario I don't want to return is_admin field, I am trying to use the follows:
$this->belongsTo('App\Models\User')
->select(['id', 'username', 'first_name', 'last_name']);
But it doesn't work.
Is the appends field always be appended even I use custome select field ?
appends is used when the model is serialized; it 'appends' attributes to the output.
If you have a single model and you want to not have the appends accessors added to the serialized data, you can set them hidden.
Example:
$test = new class extends Illuminate\Database\Eloquent\Model {
protected $appends = ['is_admin'];
public function getIsAdminAttribute() {
return rand(0, 1);
}
};
dump($test->toArray()); // will contain 'is_admin'
$test->makeHidden('is_admin');
dump($test->toArray()); // will not contain 'is_admin'
// This can be applied to Eloquent Collections.
$model->relation->makeHidden('is_admin');
One way of doing it.
Simply put this result to a variable
$data = $this->belongsTo('App\Models\User')->select(['id', 'username', 'first_name', 'last_name']);
and use directly
$data->makeHidden("is_admin");
This will work for you

Laravel: static::create vs DB:insert

If I use the following code snippet in my model it inserts the data:
$instance = DB::table('users')->insert(compact('email', 'username'));
But if I do this instead:
$instance = static::create(compact('email', 'username'));
It inserts null, but created_at and updated_at are inserted.
Laravel's created_at/updated_at are part of Illuminate\Database\Eloquent\Model. A raw DB::table query builder isn't an Eloquent model and thus doesn't have those automatic parameters.
NULL data is being inserted in the Eloquent query because Eloquent has a $fillable parameter you need to define. This parameter sets which columns can be mass-assigned. Laravel strips attributes not in this array when you do a fill, create, or otherwise instantiate a new object. In your model, you'd want:
class User extends Eloquent {
protected $fillable = ['email', 'username'];
}
ceejayoz answer is great, here's an explanation of how to call the model. Once the model is created, let's say this model:
class User extends Eloquent {
protected $fillable = ['email', 'username'];
}
Then you need to call by using the model directly and eloquents ORM like so:
// example is this. True method is TableName->ColumnName = Value;
$user = User::find($id);
$user->username = '';
$user->fullname = '';
$user->save();
The save will update the columns based on what you describe. With this you don't even need the fillable variable.
Some other variables for models that are good to know is:
protected $primaryKey = 'userid'; #if you have an primarykey that isn't named id
protected $table = 'tablename'; #if table name isn't pulling by the name of the model
protected $timestamps = true; #bool value, whether u have timestamp columns in table
You said us that you done
class User extends Eloquent {
protected $fillable = ['email', 'username'];
}
however in your comment you told us you got the following error in your apache log
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ''
for key 'users_email_unique' (SQL: insert into ``users
(updated_at, created_at``) values (2015-01-06 21:52:35, 2015-01-06 21:52:35))
Make sure to also include users_email_uniquein your fillable array if you want to set it.
class User extends Eloquent {
protected $fillable = ['email', 'username', 'users_email_unique'];
}

Laravel Eloquent Save to DB Using Create - Unhelpful Error

I get a very unhelpful error when I try and insert a new record in to my db. Does anyone have any idea where to start to solve this error?
user_id
That's all it says. (This is the name of one of my required fields in the table I'm saving to but it's not very descriptive.)
For reference here's my code:
$data = array(
'user_id'=>1,
'post_type'=>'0',
'post_title'=>'blah',
'description'=>'blah');
//it fails on this line
$id = Post::create($data);
Here's what my model looks like:
class Post extends Eloquent{
public static $rules = array(
'user_id'=>'required',
'post_type'=>'required',
'post_title' => 'required|max:25',
'description'=>'required'
);
public static function validate($data){
return Validator::make($data, static::$rules);
}
public function user(){
return $this->hasOne('User', 'id', 'user_id');
}
}
Tried getting rid of all relationships and validation in the model. That didn't work.
This is called mass-assignment in Laravel, what you need to do to get it working on your model is to set a protected array called $guarded to be empty. Add this to your model.
protected $guarded = array();
What this array does, it can prevent attributes to be mass-assigned with an array, if you don't want an attribute to be filled with the Model::create() method, then you need to specify that attribute in the $guarded array.
If instead you want to specify only the fillable attributes, Laravel's Eloquent also provides an array called $fillable where you specify only the attributes that you want to fill via the mass-assigment way.
Further reading:
Mass Assignment:
http://laravel.com/docs/eloquent#mass-assignment
Create Method:
http://laravel.com/docs/eloquent#insert-update-delete

Categories