What does "Mass Assignment" mean in Laravel? - php

When I went through Laravel Document about Eloquent ORM topic part, I got a new term "Mass Assignment".
Document show How to do Mass Assignment and the $fillable or $guarded properties settings. But after went through that, I didn't have a clearly understand about "Mass Assignment" and how it works.
In my past experience in CodeIgniter, I also didn't hear about this term.
Does anyone have a simple explanation about that?

Mass assignment is when you send an array to the model creation, basically setting a bunch of fields on the model in a single go, rather than one by one, something like:
$user = new User(request()->all());
(This is instead of explicitly setting each value on the model separately.)
You can use fillable to protect which fields you want this to actually allow for updating.
You can also block all fields from being mass-assignable by doing this:
protected $guarded = ['*'];
Let's say in your user table you have a field that is user_type and that can have values of user / admin
Obviously, you don't want users to be able to update this value. In theory, if you used the above code, someone could inject into a form a new field for user_type and send 'admin' along with the other form data, and easily switch their account to an admin account... bad news.
By adding:
$fillable = ['name', 'password', 'email'];
You are ensuring that only those values can be updated using mass assignment
To be able to update the user_type value, you need to explicitly set it on the model and save it, like this:
$user->user_type = 'admin';
$user->save();

Mass assignment is a process of sending an array of data that will be saved to the specified model at once. In general, you don’t need to save data on your model on one by one basis, but rather in a single process.
Mass assignment is good, but there are certain security problems behind it. What if someone passes a value to the model and without protection they can definitely modify all fields including the ID. That’s not good.
Let's say you have 'students' table, with fields "student_type, first_name, last_name”. You may want to mass assign "first_name, last_name" but you want to protect student_type from being directly changed. That’s where fillable and guarded take place.
Fillable lets you specify which fields are mass-assignable in your model, you can do it by adding the special variable $fillable to the model. So in the model:
class Student extends Model {
protected $fillable = ['first_name', 'last_name']; //only the field names inside the array can be mass-assign
}
the 'student_type' are not included, which means they are exempted.
Guarded is the reverse of fillable. If fillable specifies which fields to be mass assigned, guarded specifies which fields are not mass assignable. So in the model:
class Student extends Model {
protected $guarded = ['student_type']; //the field name inside the array is not mass-assignable
}
you should use either $fillable or $guarded - not both.
For more details open link:- Mass Assignment

Mass assignment means you are filling a row with more than one column using an array of data. (somewhat of a shortcut instead of manually building the array) using Input::all().
Technically just from the top of my head. Fillable means what columns in the table are allowed to be inserted, guarded means the model can't insert to that particular column.
Notice that when you try to do a mass assignment with like, insert to a column named "secret", and you have specified that it is guarded, you can try to insert to it via the model, but it will never really get inserted into the database.
This is for security, and protection on your table when using the model. Mass assignment seems to be just a notice or warning that you didn't tell the model which are fillable and guarded and makes it vulnerable to some kind of attacks.

This is when an array of data received is saved at once in a model.
Because of the security issues with this method in laravel, it's recommended you define the fields you wish the requested data to populate on the Model.
You can use the $fillable variable to define the fields you want to populate on the database table.
E.g
Protected $fillable = [‘username’, ‘dob’, ‘email’,];
When laravel detects you are mass assigning data, it forces you to define the fields you want to mass assign in the model class.
Someone can easily pass unwanted data into an html form to your database.

There are two ways to handle this.
Laravel Eloquent provides an easy way to achieve this.
In your model class, add $fillable property and
specify names of columns in the array like below:
You can achieve this by adding $guarded property in model class:
You can either choose $fillable or $guarded but not both.

Related

How laravel defines a related table to a model that will be executed to get some data? [duplicate]

I am curious about how eloquent knows in which table it should save the records we give it by running $ php artisan tinker . I do not actually remember setting so an option.
In Laravel when using Eloquent you should assign a table name using the property $table for example:
protected $table = 'some_thing';
Otherwise it assumes that the table name is the plural form of the model name and in this case for User model the table name should be users. Follwing paragraph is taken from Laravel website:
Table Names
Note that we did not tell Eloquent which table to use for our Flight
model. The "snake case", plural name of the class will be used as the
table name unless another name is explicitly specified. So, in this
case, Eloquent will assume the Flight model stores records in the
flights table.
// You may use this instead:
class Flight extends Model
{
// Explicit table name example
protected $table = 'my_flights';
}
So, if you don't follw this convention when creating/naming your database tables that Laravel expects then you have to tell Laravel the name of the table for a model using a protected $table property in your model.
Read the documentation here.
Actually if you not set the $table property, Eloquent will automatically look the snake case and plural name of the class name. For example if class name is User, it will users.
Here the code taken from Illuminate/Database/Eloquent/Model.php
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
Model name is mapped to the plural of table name, like User model maps to users table and so.
When you do
User::all() laravel knows that you want the records from users table.
To specify the table name explicitly you use protected $table ='name' field on model.
Actually, Eloquent in its default way, is an Active Record System just like Ruby On Rails has. Here Eloquent is extended by a model. Those model name can be anything starts with capital letter. Like for example User or Stock
but the funny thing is this active record system will imagine that if no other name of custom table is specified within the class model then the table name should be the small cased plural form of the Model name. In these cases users and stocks.
But by keeping aside theses names you can extensively can provide your own table name within the model. As in Laravel protected $table= 'customTableName'
Or, in a more descriptive way,
class Stock extends Eloquent{
// Custom Table Name
protected $table = 'custom_tables';
}
I hope this will solve your curious mind.

Connecting database fields and model attributes in Laravel

I'm just getting going with Laravel, and have used Eloquent to define my Campaign table. I have a Campaign model which is currently empty.
I'm not sure how to add attributes to this model to represent the fields in the db - or even if I should. The Laravel documentation seems thin on models and searches keep leading me to accessors and mutators.
If I have a database field called platform_type in my campaigns table, how do I link the PlatformType model attribute to this field?
To clarify:
This is not a question about relationships - there is only one entity in my solution thus far.
platform_type is a field in my campaigns table because it is an attribute of a campaign - I'm asking how to represent this in my model.
The model has an internal array which stores the attributes of a given row (it's called $attributes and replicated by $original if you look for them in the source code). The reason it's replicated is so when you call save() it will only do a save if you actually changed them from the originals.
You can access said attributes via $modelInstance->getAttribute("platform_type") or $modelInstance->platform_type which will call the magic __get method that in turn calls the getAttribute
So in your case you can have:
$campaign = Campaign::find($id);
echo $campaign->platform_type;
The ORM will automatically create the relevant SQL query and fill the model instance with the attributes of the row it finds.
You need to define relationships. In the PlatformType model:
public function campaigns()
{
return $this->hasMany(Campaign::class, 'platform_type');
}
And in the Campaign model:
public function platformType()
{
return $this->belongsTo(PlatformType::class, 'platform_type');
}
You also need to rename the campaign table to campaigns. Or you should add this to the model to be able to use a custom name:
protected $table = 'campaign';
At this point, these tables will be connected and relationships will work. However, it is recommended to add foreign key constraints.

Disable Laravel Pluralization For Person To People

I have a table called agency_persons with some data already in it. I created a model using php artisan:
php artisan make:model AgencyPerson
Now when I try to use Laravel's Eloquent methods i face following error:
Base table or view not found: 1146 Table
'my_database.agency_people' doesn't
Laravel is looking for people table instead of persons.
I know Laravel is trying to do the right thing and I should have named my table agency_people in the first place, but I cannot change name of the table, because other applications are using this table too.
How can I disable laravel's pluralization for person to people?
In the model, add the line
protected $table = 'agency_persons';
See https://laravel.com/docs/5.5/eloquent for more details, look for section Tablenames
If you are using persons table and person model in laravel. Laravel Pluralization For Person To People will give you this error whatever your query would be:-
Base table or view not found: 1146 Table 'lrv_db.people' doesn't exist (SQL: select `posts`.*, `people`.`country_id` from `posts` inner join `people` on `people`.`id` = `posts`.`person_id` where `people`.`country_id` = 1)'
Solution for this is :-
Define your table in the person model as below:
class person extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'persons';
}
You can also define which model attributes you want to make mass assignable. You may do this using the $fillable property on the model.
Example:
protected $fillable = ['title', 'description'];
Once you have made the attributes mass assignable, you can use the create method to insert a new record in the database.
The use of $fillable to protect which fields you want this to actually allow for updating.

Dynamic $visible, $hidden for a Laravel Model

Let's say I have User model with the following attributes:
uid
username
password
dob
usergroup
avatar
When providing JSON I should hide the password, so I will write:
$protected $hidden = ['password'];
When a request is being made for user data, I would like the model to respond with only: uid, avatar, dob.
When a request is being made for security data, I would like the model to respond with only: uid, username, usergroup.
How can I set predefined groups of $visible and $hidden attributes for different request inside model configuration, without using controllers which will make my code messy.
As #maiorano84 mentioned in the comments you wouldn't add multiple $hidden/$visible properties for this. These properties are more for general purpose so you don't have to worry about removing certain attributes each time you just want to return an instance in a request.
If you're only wanting to return specific fields in certain requests then you would be more explicit about it.
In one of your examples above you mentioned only returning uid, username and usergroup which you could do with the something like:
return collect($user)->only('uid', 'username', 'usergroup');
Hope this helps!

Proper CakePHP model to natively use multiple select and "dynamic" multiple select (e.g. tags)

In my schema Test HABTM Variable (originally I used hasMany but I found more documentation using HABTM even though it seemed overkill to me).
I want to use a multiple select in a CakePHP form and I don't want to have trouble saving, retrieving and pre-filling the data (ie. ugly array manipulations in beforeSave and beforeFind, extra queries for retrieving the selected options and other things that may cause me to lose my hair even earlier than I probably will anyway).
One usecase is a multiple select where the options are known beforehand,
the other one needs to allow for creating new and deleting old options (I'm using select2).
With the help of cake bake and some model HABTM documentation that was I missing when I read the FormHelper documentation I found out that
I have to name my multiple select form field like the model that belongs to it i.e. Variable.
It's implicit in the FormHelper documentation, but definitely could be highlighted more.
Also implicit: Because the find() operation gets the possible values for a field, I had to call the fields in my Variable model id and name (how else would it know from the Model name in the input call what to display). I can change find's options but that broke the convention at some other step I think.
Inconsistently if I want to supply a list of possible values in the controller, I have to set a variable that is lowercase, camelized and pluralized (not uppercase and singular like my Model and like I have to name the form field, not lowercase, underscore-separated and singular like my name field and my table).
I thought I didn't need to set the possible options in the controller (because I either know them or they're added on-the-fly by the user, I don't really want to populate the DB with them beforehand), but I tried to wrap my head around the convention. I could not get it to work unless I populated the DB with them beforehand and set them in the controller.
That seems fragile or at least more narrow compared to the treatment of single selects.
My continuing problems
With HABTM I can't create new options on-the-fly (it's okay for one usecase, but not for another, which is more like tagging).
With HABTM I don't want to have to populate the DB with options. And I don't really want to set the options in the controller, but in the view (because I anticipate this will cause problems with multiple "Tests" on one page, if it doesn't then it's okay).
With HABTM it doesn't work when I change the Form->input to Form->select (doesn't really matter, but adds to that feeling of my solution being fragile).
With hasMany I got as far as automatically selecting values I filled in in the DB, but it does not destroy or create associations (i.e. delete no longer selected options in the child table, even though it is declared as dependent). I think here it's due to the fact, that I don't properly pass the IDs of the child table, but how would be the Cake way to do that?
Sample code
/* Model Variable.php */
class Variable extends AppModel {
public $belongsTo = 'Test';
}
/* Model Test.php */
class Test extends AppModel {
public $belongsTo = 'Study';
public $hasAndBelongsToMany = array(
'Variable' => array(
'className' => 'variable',
'joinTable' => 'tests_to_variables',
'foreignKey' => 'test_id',
'associationForeignKey' => 'variable_id',
'with' => 'TestsToVariables',
),
);
}
/* in baked TestsController.php */
$variables = $this->Test->Variable->find('list');
$this->set(compact('variables'));
/* in edit.ctp, the baked view */
echo $this->Form->input('Variable');
Cake Form::input() has options for multi select, it also auto fills the values and selects previously saved data.
How does this not fit your needs, Have you even tried what is explained in the book?
http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#creating-form-elements

Categories