how to update email admin with Custom Rule? - laravel

I am trying to edit the admin information using a Custom Rule, I want the admin to be able to reset her email when she edits her information but not to reset her email to others.
This is my Custom Rule checkAdminEmailExist.php, please correct it wherever there is a problem
<?php
namespace App\Rules;
use App\Repositories\Interfaces\AdminRepositoryInterface;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Auth;
class checkAdminEmailExist implements Rule
{
public AdminRepositoryInterface $admin_repository;
public function __construct()
{
$this->admin_repository = app()->make(AdminRepositoryInterface::class);
}
public function passes($attribute, $value):bool
{
if($value == Auth::user()->email) {
return true;
}
if ($this->admin_repository->checkAdminEmailExist($value)) {
return false;
}
return true;
}
public function message():string
{
return 'The :attribute duplicate';
}
}

You can leverage try to leverage afterHook like
class UpdateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
/** Other rules **/
'email' => ['required', 'email'],
];
}
/**
* Configure the validator instance.
*
* #param \Illuminate\Validation\Validator $validator
* #return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
$alreadyExists = DB::table('users')
->where('id', '<>', auth()->id())
->where('email', $this->email)
->exists();
if (auth()->user()->isAdmin() && $alreadyExists) {
$validator->errors()->add('email', 'The email address is already taken');
}
});
}
}
You will need to implement a isAdmin() method on User model to verify whether the user is an admin or not.
//USer model
public function isAdmin()
{
//Determine if the user has the role of admin
return $this->hasRole('admin');
// or if there's a is_admin boolean column on users table
return $this->is_admin === true;
}
Laravel Docs - Validation - After Validation Hook

Related

Laravel 8 Gate issue iam trying to check condition with different model but there are error show

In my laravel 8 iam define gate but there some problem my gate is accept only one model name is that Admin when i try to check another model name there are error show
here is my authserviceprovider
<?php
namespace App\Providers;
use App\Models\Admin\Role;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('isAdmin', function(Role $role) {
if ($role->role === 'Admin') {
return true;
} else {
return false;
}
});
}
}
here is controller
public function index(Role $role)
{
if (!Gate::allows('isAdmin', $role))
{
abort(403);
}
$users = Admin::with('roles')->get();
return view('Admin.user.index', compact('users'));
}
error message
TypeError
App\Providers\AuthServiceProvider::App\Providers{closure}(): Argument #1 ($role) must be of type App\Models\Admin\Role, App\Models\Admin given, called in D:\xampp\htdocs\education\vendor\laravel\framework\src\Illuminate\Auth\Access\Gate.php on line 477
http://127.0.0.1:8000/admin/users
Gate are mostly used to authored login user. if you need to authorise in any model specific then use policy
so in gate we get login user instance as call back automatically
so in your case code will be like this
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('isAdmin', function($user) {
return $user->role->name === 'Admin';
});
}
then in controller
public function index(Role $role)
{
abort_if(!Gate::allows('isAdmin'));
$users = Admin::with('roles')->get();
return view('Admin.user.index', compact('users'));
}

Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL)

I am trying to back and implement FormRequest objects for validation. I have successfully setup the form requests for all of my models except for the User model. I am getting the following error Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL). Researching this error it seems like it may be an issue with the way that I'm handling the authorization through Policies. Note that the UserStoreRequest works but the UserUpdateRequest returns the error.
UserStoreRequest
<?php
namespace App\Http\Requests;
use App\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - create-user
return Gate::allows('create', User::class);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
'markets' => 'required|array',
'roles' => 'required|array',
];
}
/**
* Save the user.
*
* #return \App\User
*/
public function save()
{
// Create the user
$user = new User($this->validated());
// Set the password
$user->password = Hash::make($this->validated()['password']);
$user->setRememberToken(Str::random(60));
// Save the user
$user->save();
// Set users markets
$user->markets()->sync($this->validated()['markets']);
// Update the users role if included in the request
if ($this->validated()['roles']) {
foreach ($this->validated()['roles'] as $role) {
$user->roles()->sync($role);
if ($user->hasRole('admin')) {
$user->markets()->sync(Market::all());
}
}
}
return $user;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'password.required' => 'The password is required.',
'password.confirmed' => 'The passwords do not match.',
'password.min' => 'The password must be at least 8 characters.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
UserUpdateRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - update-user
return Gate::allows('update', $this->user);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
];
}
/**
* Get the user from the route.
*
* #return \App\User
*/
public function user()
{
return $this->route('user');
}
/**
* Save the email role.
*
* #return \App\Role
*/
public function save()
{
// Update the user
$this->user->update($this->validated());
// // Check to see if password is being updated
// if ($this->validated()['password']) {
// $this->user->password = Hash::make($this->validated()['password']);
// $this->user->setRememberToken(Str::random(60));
// }
// // Set users markets
// $this->user->markets()->sync($this->validated()['markets']);
// // Set users roles
// // // Update the users role if included in the request
// if ($this->validated()['roles']) {
// foreach ($this->validated()['roles'] as $role) {
// $this->user->roles()->sync($role);
// if ($this->user->hasRole('admin')) {
// $this->user->markets()->sync(Market::all());
// }
// }
// }
// // Save the user
// $this->user->save();
return $this->user;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
As you can see I have commented out most of the code for the UpdateRequest for troubleshooting. It seems that the issue is with the authorize() method. Below is the code from the UserPolicy
UserPolicy
/**
* Determine whether the user can create models.
*
* #param \App\User $user
*
* #return mixed
*/
public function create(User $user)
{
return $user->hasPermission('create-user');
}
/**
* Determine whether the user can update the model.
*
* #param \App\User $user
* #param \App\User $model
*
* #return mixed
*/
public function update(User $user, User $model)
{
return $user->hasPermission('update-user');
}
UserController
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\UserStoreRequest $request
*
* #return \Illuminate\Http\Response
*/
public function store(UserStoreRequest $request)
{
return redirect($request->save()->path());
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\UserUpdateRequest $request
* #param \App\User $user
*
* #return \Illuminate\Http\Response
*/
public function update(UserUpdateRequest $request, User $user)
{
return redirect($request->save()->path());
}
I'm using a permission based authorization for this system. The user has the hasPermission() method on it to verify if the user has the required permission to perform the action. I fear that I've confused myself on this setup and that I am not validating correctly. Everything has worked up until trying to implement this on the User model.
hasPermission()
/**
* Check to see if the model has a permission assigned.
*
* #param string $permission
*
* #return bool
*/
public function hasPermission($permission)
{
if (is_string($permission)) {
if (is_null(Permission::whereName($permission)->first())) {
return false;
} else {
return $this->hasRole(Permission::where('name', $permission)->first()->roles);
}
}
return $this->hasRole($permission->roles);
}
hasRole()
/**
* Check to see if model has a role assigned.
*
* #param string $role
*
* #return bool
*/
public function hasRole($role)
{
if (is_string($role)) {
return $this->roles->contains('name', $role);
}
return (bool) $role->intersect($this->roles)->count();
}
Update
I have tried renaming the user() method in UserUpdateRequest to frank() to resolve any issues overriding the Request user. This clears up the error listed above, but then the response is returned unauthorized. The logged in user has permissions set to allow updating users. This is called in the authorize() method using Gate::allows. I'm just not sure if it's checking the logged in user or the model user.
I investigated further and found that there is a new error after changing the method to frank(). I am getting Call to a member function update() on null. I should be returning the user pulled from the route from the frank method but it seems to be returning null.
Updated UserUpdateRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - update-user
return Gate::allows('update', $this->frank);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
];
}
/**
* Get the user from the route.
*
* #return \App\User
*/
public function frank()
{
return $this->route('user');
}
/**
* Save the email role.
*
* #return \App\Role
*/
public function save()
{
// Update the user
$this->frank->update($this->validated());
// // Check to see if password is being updated
// if ($this->validated()['password']) {
// $this->user->password = Hash::make($this->validated()['password']);
// $this->user->setRememberToken(Str::random(60));
// }
// // Set users markets
// $this->user->markets()->sync($this->validated()['markets']);
// // Set users roles
// // // Update the users role if included in the request
// if ($this->validated()['roles']) {
// foreach ($this->validated()['roles'] as $role) {
// $this->user->roles()->sync($role);
// if ($this->user->hasRole('admin')) {
// $this->user->markets()->sync(Market::all());
// }
// }
// }
// // Save the user
// $this->user->save();
return $this->frank;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
The issue is the user() method you defined on your UserUpdateRequest class.
UserUpdateRequest extends Illuminate\Foundation\Http\FormRequest, which in turn extends Illuminate\Http\Request. Illuminate\Http\Request already has a user() method defined, so the user() method in your UserUpdateRequest class is attempting to override this definition.
Since your UserUpdateRequest::user() method doesn't match the Illuminate\Http\Request::user($guard = null) signature, you're getting that error.
You can either:
Remove the user() method from your UserUpdateRequest class, or
Rename your user() method on your UserUpdateRequest class, or
Add the $guard = null parameter to your user() method on your UserUpdateRequest class, so that it matches the signature of the base user() method.

How to use 2 attributes in Validation Rule Class Laravel

How can I use two attributes in the Validation Rule of Laravel. This is my function where I have 2 variables groupid and grouppassword. Currently only groupid is taken.
public function groupPasswordValidationReal(Request $request){
$groupid = $request->input('groupid');
$grouppassword = $request->input('grouppassword');
$validator = \Validator::make($request->all(), [
'groupid' => [new ValidRequest] //How to pass grouppassword in this function???
]);
return redirect('home')->with('success', 'Request is send!');
}
How can I pass both to my Validation Class? Here you can see the functions in the Validation Class.
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Group;
class ValidTest implements Rule
{
public function passes($attribute, $value)
{
//$value is groupid
$validPassword = Group::where([['idgroups', $value],['group_password', /*Here I need grouppassword*/]])->first();
if($validPassword){
return true;
}else{
return false;
}
}
public function message()
{
return 'Wrong Password!';
}
}
Add property and constructor to your ValidTest class. Pass the required value as an argument to the new object.
ValidTest.php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Group;
class ValidTest implements Rule
{
/**
* The group password.
*
* #var string
*/
public $groupPassword;
/**
* Create a new rule instance.
*
* #param \App\Source $source
* #param string $branch
* #return void
*/
public function __construct($groupPassword)
{
$this->groupPassword = $groupPassword;
}
public function passes($attribute, $value)
{
//$value is groupid
//$this->groupPassword is group_password
$validPassword = Group::where([['idgroups', $value],['group_password', $this->groupPassword]])->first();
if($validPassword){
return true;
}else{
return false;
}
}
public function message()
{
return 'Wrong Password!';
}
}
Controller
public function groupPasswordValidationReal(Request $request){
$groupid = $request->input('groupid');
$grouppassword = $request->input('grouppassword');
$validator = \Validator::make($request->all(), [
'groupid' => new ValidTest($grouppassword)
]);
return redirect('home')->with('success', 'Request is send!');
}
Source : custom-validation-rules-in-laravel-5-5
Note : This is not a tested solution.
Use the Rule constructor like
class ValidUser implements Rule
{
private $grouppassword;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct($grouppassword)
{
$this->grouppassword = $grouppassword;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
// $this->grouppassword
// $groupid = $value
// Do your logic...
return true;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute must something...';
}
}
Usage
Route::post('/user', function (Request $request) {
// Parameter validation
$validator = Validator::make($request->all(), [
'groupid' => 'required',
'grouppassword' => ['required', new ValidUser($request->groupid), ]
]);
if ($validator->fails())
return response()->json(['error' => $validator->errors()], 422);
});
I think you could use a closure there. So something like this:
$validator = \Validator::make($request->all(), function() use ($groupid, $grouppassword) {
$validPassword = Group::where([['idgroups', $value],['group_password', $grouppassword]])->first();
if($validPassword){
return true;
}else{
return false;
}
}
I haven't run it though.
If you are calling the validation from a Request class, you can access the extra value as e.g.
request()->validate([
'groupid' => [new ValidTest(request()->input('grouppassword'))]
]);

redirect to controller instead of view when validation failed in laravel 5.1

in my controller :
public function getData(\App\Http\Requests\NewNameRequest $request)
{
return 'Your name is : '.$request->input('myName');
}
in my NewNameRequest.php class
namespace App\Http\Requests;
use App\Http\Requests\Request;
class NewNameRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'myName'=>'required|min:3|max:10'
];
}
}
what i want is ...
if (NewNameRequest is Failed)
{
do this...
}
else
{
proceed ahead in controller
}
thanks in time ahead

Validate a field in Laravel only if it's zero or a value from db

I'm new to Laravel so sorry for my newbie question:
I have in input field, it must be valid only if it's zero or if it's value exists in a "products" db table.
I'm using Form Request Validation with Laravel 5.2.
This is my code:
class CreateRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'product_id' => 'sometimes|exists:products,id'
];
}
}
This works for the database validation, but how can I make it valid if it's zero?
Thanks for your help!
This might be helpful
public function rules()
{
return [
'product_id' => 'integer|size:0|exists:products,id'
];
}
You have to create a Custom validation rules
If you are using 5.6 you can create a custom rule or pass a closure
class CreateRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
public function rules()
{
return [
'product_id' => ['integer', function($attribute, $value, $fail) {
$product = Product::find($value);
if ($value != 0 && !$product ) {
return $fail($attribute.' is invalid.');
}
},
];
}
}
Hope this helps

Resources