Dynamic $visible, $hidden for a Laravel Model - php

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!

Related

Unable to define relations correctly in laravel 5.5 application

I am developing a multi author blog in laravel 5.5. My scenario is such:
Whenever one wants to join the blog website as an author he/she has to send an application form. These applications are to be approved/rejected by one of the editors (amongst the many editors in the system). The Users table contain the editors.
So whenever an application is made, it can be viewed by multiple editors. One of the editors will need to book the application for processing. This is being done in order to prevent multiple editors to be reviewing the same application. Once an editor books the application, he can approve/reject the author application. If he chooses not to work on the application after he has booked the same, he has to release it so that other editors may book it. Thus one application is not mapped to multiple users/editors at the same time.
Now my requirement is to find all the applications booked by the editor who is currently logged in. I am unable to form the correct relations.
My tables are:
user (represent the editors)
Id, name, email, role_id, password
author_requests (represents the applications submitted by interested editors)
name, password, email, phone, city, country, profile_pic, bio, display_name, sample_article_link1, sample_article_link2, sample_article_link3, status
request_bookings (represent the bookings made by the editors)
id, item_id, item_type, user_id, status, status_date
In the request_bookings table, item_id contains the application id and item_type contains the model type that is “auhor”. These fields have been kept because like booking the author applications, moving ahead the same needs to be done with the suggested post titles and post articles.
My models are:
class User extends Authenticatable
public function bookings(){
return $this->hasMany("App\RequestBooking");
}
}
class AuthorRequest extends Model{
public function bookings(){
return $this->hasMany("App\RequestBooking");
}
}
class RequestBooking extends Model{
public function user(){
return $this->belongsTo("App\User");
}
public function authorReq(){
return $this->belongsTo("App\AuthorRequest");
}
}
When I try:
auth()->user()->bookings->authorReq
It gives me error:
Exception
Property [authorReq] does not exist on this collection instance.
How can I get a list of all author applications that have been booked by the logged in editor?
By default, laravel uses the column with method name suffixed with _id, which according to your method name, looks for authorReq_id.So, you either create a column on author_requests table, if you dont have any column that defines the relation. Or, if you already have a column but with different name then you can pass a second parameter to belongsTo method, Like so:
public function authorReq()
{
return $this->belongsTo("App\AuthorRequest", 'column_that_references_foreign_key');
}
Hope it helps.

Laravel paginate not working with select certain columns on querybuilder

I have user role relation (many to many) defined as follows in Role model:
public function users()
{
return $this->belongsToMany('App\User');
}
Now I want to show all users in certain role. I execute the following:
$list = Role::find(1)->users()->select('name')->orderBy('name')->paginate(10);
Here $list contain all users that belong to role with id 1 and that is correct. But the problem is: when adding breakpoint on $list it shows that: all user model's attributes are retrieved just like select('name') has no effect.
This is a big problem especially when i want to return the $list as json. User password is retrieved even though it's in the $hidden array of User Model.
My question is:
why paginate() on querybuilder does not respect select() nor attributes in model's $hidden array?
Note: I know that there is other solutions to achieve what I want. I just want an answer to my question to figure out what is going on?
select('name') has no effect because paginate() method takes columns as second parameter
$list = Role::find(1)->users()->orderBy('name')->paginate(10, ['name']);
You can read more about parameters and methods here
https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Builder.html#method_paginate
Since users have the role_id then why don't you fetch the users as:
User::where('role_id', 1)->orderBy('name')->paginate(10);
You are basically getting a role and then fetching a list against that role.

What does "Mass Assignment" mean in Laravel?

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.

add model relationship without save

I have the next relationship User hasMany Contacts.
In normal situation is use $user->contacts()->save($contact) to add and save a contact to the user, but I need to associate contacts to users without save the models (User and Contacts).
edit:
I need to build a plant that receives one of such methods and return an XML a collection of templates, only in some of these models will be stored at postiriori.
You can use the associate on your model with belongsTo.
$contact= Contact::find(10);
$user->account()->associate($contact);
$user->save(); // You do need to update your user
Source: http://laravel.com/docs/eloquent
If you know the UserID, just create a new Contact; and make sure to have the correct User ID in the user_id column. Don't even have to touch the User.

Laravel JSON Response with Eloquent

I got three tables called threads,posts,users
threads got
id
title
etc.
posts got
id
thread_id
user_id
post
post_date
etc.
users got
id
username
password
email
etc.
when users wants to view a thread i simply call a jquery ajax request using post data to send thread id and return this code :
Response::eloquent(Thread::find(Input::get('threadid'))->posts()->get());
this code does his job perfectly and return posts by same thread_id. (post model also eager loads the user by looking user_id).
however this code grabs every attribute of posts and users i mean everything to json, post_date, post_updatereason, user_password, user_email all columns in tables.
I just want to grab post, username and post_date with json
You can add public static $hidden = array('list', 'of', 'fields'); to your model which extends Eloquent. Then none of the fields which you enumarate in the array will be returned. For more information refer to the documentation.
For example
class User extends Eloquent {
public static $hidden = array('password', 'email');
}
will return the user model without the password and email.
If you are using laravel 3, and this is probably the same for version 4, you should be able to specific the columns you want using the get method.
Response::eloquent(Thread::find(Input::get('threadid'))->posts()->get(['username','post_date']));

Categories