Adding custom (guarded) field to Laravel 5.3 Auth - laravel-5

I am trying to add a custom field 'role' to Laravel 5.3 User Auth. The role will determine whether the user is admin amongst other roles and so because the Auth scaffolding uses mass assignable attributes, there is a vulnerability.
Therefore I have changed my User model to:
protected $guarded = [
'role'
];
RegisterController I have added my custom fields (a default user will have the role = customer);
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'facebook_id' => $data['facebook_id'],
'linkedin_id' => $data['linkedin_id'],
'avatar' => $data['avatar'],
'token' => $data['token'],
'role' => 'customer',
I am getting this error message:
SQLSTATE[HY000]: General error: 1364 Field 'role' doesn't have a default >value (SQL: insert into users (name, email, password, >facebook_id, linkedin_id, avatar, token, updated_at, >created_at) values (name, name#domain.co.uk, hashed password, , , , , >2017-01-20 17:21:16, 2017-01-20 17:21:16))
Can't for the life of me figure it out.
I was thinking that maybe I don't use the mass assignable input, but I have a feeling that may mess up the rest of the Auth scaffold.
Thanks for any help

An easy way to set the default role is to actually define it in the model
class User extends Model
{
protected $attributes = [
'role' => 'customer',
];
protected $guarded = [
'role'
];
//...
Now when you use the create method and don't pass the the 'role' attribute, the insert will use the value 'customer'

In your migration for the users table where you add the role field, you either need to set the field as nullable, or give it a default value, so that when you mass assign without it, the database knows how to deal with that field.
Schema::table('users' function(Blueprint $table){
$table->string('role')->default('customer');
});
or
Schema::table('users' function(Blueprint $table){
$table->string('role')->nullable();
});
if your code can deal with a null role value.

Related

Add the inserted id to the pivot table

I have a users, items, user_item tables. I need to populate the user_item table with a user_id and item_id when a user is created.
so far, I have a basic registration function
public function register(Request $request) {
$user = User::create([
'name' => $request->name,
'user_type' => $request->user_type,
'email' => $request->email,
'password' => bcrypt($request->password)
]);
$token = auth()->login($user);
return $this->respondWithToken($token);
}
So far it saves only to the users table ofcourse.
I've looked at some documentations on using attach(), however, I got stuck on this one..
In the register function, i added a $item array:
$item = Item::create([
'user_id' => !!!!, -> How do I get the id of the inserted user
'instrument_id' => $request->instrument_id
]);
$user->role()->attach($item)
Also, what is role()? is it a built-in laravel function?
Note that I haven't tried running this function since I got stuck on these problems. So I don't event know if it's gonna work.
Anyone help me on this one? I'm a laravel newbie and got really confused on the documentations.
the method create return the model it self after loading it's attributes from db,
so when you want the user id just use $user->id after create() method.
for the default permission that shipped with laravel it is
spatie/laravel-permission
and to assign role to a user you can use:
$user->assignRole('writer'); // just set role name

Laravel Backpack::crud set permission (role) to a category

I'm trying to set Role (or permission) to my category in Laravel Backpack (newscrud).
I have added the field of Role in CategoryCrudController class and category_role table in DB and set relations in Category and Role models.
the relation data is now stored in the table, although the checkbox remains unchecked!
$this->crud->addField(
[
'label' => 'Roles',
'type' => 'checklist',
'name' => 'roles',
'entity' => 'roles',
'attribute' => 'name',
'model' => "Backpack\PermissionManager\app\Models\Role",
'pivot' => true,
]
);
Added role field
Now I want to allow the users with the granted role to use crud on the category's articles.
I know I can use hasRole and use denyAccess() in CrudController's setup function but it doesn't what I want.
public function setup(){
if (backpack_user()->hasRole('certainCategoryRole')) {
$this->crud->denyAccess([ 'delete','edit','write']);
}
}
I need to give articles operations access to users by their category's assigned role.
Can anyone help?
Thanx

Laravel 5.6 Validation on empty fields

Somehow I feel like this should be a common question, but I can't seem to find a definite answer on that one.
The problem is quite simple:
On validating a form, I would like to exclude the empty non-required fields from the resulting array - and this in order to use the default value set at database level.
Since Laravel is using the ConvertEmptyStringsToNull middleware by default (and I am not so keen on changing that), it means that my empty fields will be converted to 'null' and sent to my database (hence not getting their default value, and actually breaking the query since those fields are not nullable at database level).
$userData = $request->validate([
'email' => 'required|string|email|max:255|unique:users',
'number_of_whatever' => //if this field is empty, I want it stripped out the $userData array - or automatically default to the database default
]);
Any help on how to solve this in the cleanest way possible would be much appreciated! I was thinking about making a custom rule that would exclude the field itself (so I could reuse this validation rule across the project without having to manually do it every time we come across the situation).
Another option would be to set it at Model level - but not so keen on doing that, it seems weird to have to do it there when it's already done at DB level.
Thanks!
i think you can use nullable rule
$userData = $request->validate([
'email' => 'required|string|email|max:255|unique:users',
'number_of_whatever' => 'nullable'
]);
Hey so i've found your issue and also a sort of work around for this. Based on the below example i've replicated and now understood your issue properly, even if the validator allows null values the create method throws an error and does not set default values.
Controller
$validator = Validator::make($data, [
'name' => 'max:255',
'email' => 'max:255',
'password' => 'max:255',
]);
if ($validator->fails()) {
dd('Validator has failed');
}
// This throws an error saying that the fields cannot be null!
User::create($data);
Users Table
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->default('Ken');
$table->string('email')->default('ken#stackoverflow.com');
$table->string('password')->default(bcrypt('password'));
$table->rememberToken();
$table->timestamps();
});
The work around i've devised is this, remove all null values from the post request before it hits the validator like so.
Example
$data = ['name' => null, 'email' => null, 'password' => null];
foreach($data as $key => $value)
{
if($value == null)
{
unset($data[$key]);
}
}
The logic here is by removing the fields from the post request that are null, the USER object does not see them as having a value, therefore allowing the tables default values to table place, but if the value is null this is still deemed as a value so the default value will be ignored.
I hope this makes sense.
Result of my full code
Create a FormRequest and filter out the null values using the prepareForValidation method:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class TestRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return
[
'username' => 'required|string|email|max:255|unique:users',
'number_of_whatever' => 'sometimes|integer',
];
}
protected function prepareForValidation()
{
if($this->number_of_whatever == null) {
$this->request->remove('number_of_whatever');
}
}
}
You can apply any validation other than 'required' after the 'sometimes' rule and will be applied only if the value isn't null.

Laravel Collective - Model binding issue for non eloquent table names

I have a User model that has to have a table named admin_users, which is already stipulated in the model (protected $table = 'admin_users';)
I am using Laravel Collective form as follows:
{!! Form::model($user, ['route' => ['users.update', $user->id], 'method' => 'put']) !!}
My validation as follows:
$rules = array(
'first_name' => 'required',
'last_name' => 'required',
'email' => 'email|max:255|unique:users',
'country_id' => 'required|numeric',
'user_status' => 'required'
);
The only reason I am using Laravel Collective FORM::model for the ease of getting the request input back when validation fails:
(return redirect()->back()->withErrors($validator)->withInput($request->all())
On validation success though I am getting:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'crm.users' doesn't exist (SQL: select count(*) as aggregate from `users` where `email` = jocelyn33#example.com)
The weird thing is that it's not taking the table from User class table.
My question is if there is a way to have FORM::model get admin_users table name rather than users, and if I decide to let go of FORM::model and use FORM::open, would I still be able to get back request inputs of a failed validation?
Your validation rules are defining what table to use for a unique check:
'email' => 'email|max:255|unique:users',
unique:users is telling the unique rule to use the users table.
unique:table,column,except,idColumn -
Laravel Docs 5.6 - Validation - Unique Rule

Laravel profile update with e-mail unique:users

I'm new in Laravel. I try to make profile update page... all works good but if I try to apply rule to set email field unique:users I have problem when user try to update for example name and don't want change email.
public function rules()
{
return [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
];
}
I want restrict that user to use the same e-mail that someone else is using... but I want to ignore that if this is the same e-mail already in that user profile and he don't want to change that.
public function updateData(UpdateDataRequest $request)
{
DB::table('users')
->where('id', Auth::user()->id)
->update(array('email' => $request->email, 'name' => $request->name));
return redirect('panel');
}
How to do it right?
This exact situation is used as an example in the docs.
https://laravel.com/docs/5.2/validation#rule-unique
Forcing A Unique Rule To Ignore A Given ID:
Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. You only want to throw a validation error if the user provides an e-mail address that is already used by a different user. To tell the unique rule to ignore the user's ID, you may pass the ID as the third parameter:
'email' => 'unique:users,email_address,'.$user->id
If your table uses a primary key column name other than id, you may specify it as the fourth parameter:
'email' => 'unique:users,email_address,'.$user->id.',user_id'
In new version. laravel using Rules to ignore a user or record
https://laravel.com/docs/5.8/validation#rule-unique
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
$user->id can be a specific id or the id of current user which is login
try to this validation(Laravel 8.x)
'email' => ['email:rfc','confirmed','unique:App\Models\User,email'],

Resources