Laravel 9: Trait with validation - php

I created a trait to use with a controller. The controller should start the trait function, which validates its input and then does a thing.
Inside the FooController.php:
[..]
$do_stuff = $this->create_stuff($input);
The trait:
<?php
namespace App\Traits;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
[..]
use Illuminate\Support\Facades\Validator;
trait Foo
{
public function create_stuff(Request $input)
{
// validation part
$validatedData = $input->validate([
'Value' => 'required|numeric',
]);
// end of validation part
[..]
Everything works fine without the validation part but as soon as I add it I get the error:
Argument 1 passed to App\\Http\\Controllers\\FooController::create_stuff() must be an instance of Illuminate\\Http\\Request, instance of stdClass given,[..]
I understand the $input is a 'normal' (?) PHP object and it seems the validation only works with 'request' objects, so how can I make this work?

First of all please don't create a trait for validation create a request for validation using PHP artisan
PHP artisan make:request Your_request_name
and inside your request add your validations like this
public function rules()
{
return [
'sponsor_name' => ['required', 'string'],
'sponsor_type' => ['required', 'string'],
'mobile' => ['required', 'string'],
'email' => ['required', 'string'],
'nationality' => ['required', 'string'],
'sponsor_issued_from' => ['required', 'string'],
'sponsor_issued_date' => ['required', 'date'],
'sponsor_address' => ['required', 'string'],
];
}
public function authorize()
{
return true;
}
then inside your request add your validations
after that just call your request in your controller function
for example
public function (Your_request_name $request)
{
...
}

Related

How do I define validation rules in laravel 8 globally?

I have considered defining validation rules for different parts of my application in a class as static variables. For example,
$VALIDATION_RULES = [
'signatures' => [
'first_name' => ['required', 'max:255', 'required','string'],
'last_name' => ['required', 'max:255', 'required', 'string'],
'enabled' => [ 'required', Rule::in(['on', 'off']) ],
'signature_file' => ['required', 'mimes:png,jpeg,jpg', 'max:1024'],
'operator_id' => ['required', 'numeric'],
],
];
However, I get this error.
Symfony\Component\ErrorHandler\Error\FatalError
Constant expression contains invalid operations
This is due to
Like any other PHP static variable, static properties may only be
initialized using a literal or constant before PHP 5.6; expressions
are not allowed. In PHP 5.6 and later, the same rules apply as const
expressions: some limited expressions are possible, provided they can
be evaluated at compile time.
according to the php official documentation.
What is the correct way to do this?
P.S.: This variable is defined inside a class as a public and static member. In the code, wherever I need to validate an input, I can call
$validated_input = $request->validate($VALIDATION_RULES['signatures']);
This way, I can have all the rules centralized in one class.
If you want to have a part of a code and use it in the other FormRequests too, you can use traits.
Suppose you want to validate users in the multi FormRequests:
Create UserRequestTrait and add this method to the trait:
private function userInfoValidator(string $prefix = ''): array
{
return [
$prefix . 'first_name' => ['required', 'string', 'max:100'],
$prefix . 'last_name' => ['required', 'string', 'max:100'],
];
}
Now you can use it in the FormRequest classes:
class UserFormRequest extends FormRequest
{
use UserRequestTrait;
public function rules()
{
$rules = [
// Add the other rules
];
// validate user info
$userValidation = $this->userInfoValidator();
return array_merge(
$rules,
$userValidation
);
}
}
And if you are validating an object, you can add the prefix in the userInfoValidator method, like this:
$userValidation = $this->userInfoValidator('users.*.');
You cannot use functions ,expressions,objects while declaring class properties (includes static and non-static property).which means you cannot call someFunction() or new Sampleclass inside the property, you can only use static values. You'll have to add those values differently inside the constructor or maybe some other method.
so By removing Rule::in(['on', 'off']) inside the property (which is object) will fix the issue
class MyTestClass {
public $VALIDATION_RULES = [
'signatures' => [
'first_name' => ['required', 'max:255', 'required','string'],
'last_name' => ['required', 'max:255', 'required', 'string'],
'enabled' => [ 'required'],
'signature_file' => ['required', 'mimes:png,jpeg,jpg', 'max:1024'],
'operator_id' => ['required', 'numeric'],
],
];
}
$obj = new MyTestClass;
dd($obj);
You can read the docs
https://php-legacy-docs.zend.com/manual/php5/en/language.oop5.static

Laravel 8: Class 'App\Http\Controllers\Admin\Rule' not found

I'm working with Laravel 8 to develop my project, and I have made a Resource Controller under the Admin directory, which goes like this:
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
public function update(Request $request, User $user)
{
$data = $request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email',
'max:255', Rule::unique('users')->ignore($user->id)],
]);
if (!is_null($request->password)) {
$request->validate([
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
$data['password'] = $request->password;
}
$user->update($data);
if ($request->has('verify')) {
$user->markEmailAsVerified();
}
return redirect(route('admin.users.index'));
}
As you can see, I put the method update because it holds some form of validation. But whenever I try to update the data within the form of the Blade file, I get this error:
Error
Class 'App\Http\Controllers\Admin\Rule' not found
I even tried adding use Illuminate\Support\Facades\Validator; but still receives the error. How can I fix this error?
call this in your file
use Illuminate\Contracts\Validation\Rule;

How can I reject user registration with certain username in default laravel register form?

I'm trying to block users from using certain names like 'admin' or 'operator'.
I've tried fiddling with both Controllers/Auth/RegisterController and Controller/RegisterController but failed.
What I've tried was something like this:
in Controllers/Auth/RegisterController,
if ($data['name'] === 'admin' || $data['name'] === 'operator') {
return redirect()->back()->withErrors(['Invalid username']);
}
else {
session()->flash('message', 'Welcome!');
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
The code above gave me this error:
Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an
instance of Illuminate\Contracts\Auth\Authenticatable, string given,
called in /var/www/vendor/laravel/ui/auth-backend/RegistersUsers.php
on line 36
I've also searched whether validators can block specific words but failed.
I know I can work this around by using JS, but I think Laravel would have some function like this.
Go to RegisterController.php.
There will be a validator(array $data) function that validates your registration input.
Add not_in validation check for the name field.
Something like this:
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255', 'not_in:admin,operator'],
'pan' => ['required', 'string', 'min:10', 'max:10', 'unique:users,username'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
Hopefully, this helps.
You can try to validate if requested name is not in the list of predefined blocked names:
use Illuminate\Validation\Rule;
Validator::make($data, [
'toppings' => [
'required',
Rule::notIn(['admin', 'superuser']),//etc..
],
]);
Hope it helps.
Here's what I did in Laravel 9 with the Breeze scaffolding.
I created a separate "Services" trait with the reserved usernames, so that I can easily implement and extend it.
Create a Services folder at app/Services
Create a trait Reserved at app/Services/Reserved.php
Reserved.php
<?php
namespace App\Services;
trait Reserved
{
public static function usernames()
{
return ['admin', 'operator', 'someBadWord'];
}
}
Next open app/Http/Controllers/Auth/RegisteredUserController.php and import the trait, then add it.
Now just add it to your validation rules using the notIn rule.
Rule::notIn(Reserved::usernames())
RegisteredUserController.php
use Illuminate\Validation\Rule;
use App\Services\Reserved;
class RegisteredUserController extends Controller
{
use Reserved;
...
public function store(Request $request)
{
$request->validate([
'username' => ['required', 'string', 'max:16', 'unique:users', Rule::notIn(Reserved::usernames())],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
...
}
}
Create RegisterControllerRequest using the following command:
php artisan make:request RegisterControllerRequest
find out your recent created file in app/Http/Requests, then update rules() to be:
public function rules()
{
return [
'name' => 'required|notIn:admin,operator',
];
}
Then update your controller to use the new validation:
After name space add:
use App\Http\Requests\RegisterControllerRequest;
And finally inject the validation as a parameter in your register method:
public function register (RegisterControllerRequest $request)
For more information check documentation: https://laravel.com/docs/7.x/validation#form-request-validation

Laravel: error "Undefined variable" when i validate form request with using custom Request class

In Laravel (5.8) controller, i try to make update() function for my User model.
I validate data with using my own class UpdateRequest. When i put variable $user in this class, i have error Undefined variable: user.
<?php
namespace App\Http\Requests\Users;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => ['required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($user->id)],
];
}
}
public function update(User $user, UpdateRequest $request)
{
$user->update($request->only(['name', 'email']));
return redirect()->route('users.index');
}
But if I use validate function in controller update() method, all works fine.
public function update(User $user, Request $request)
{
$this->validate($request, [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => 'required|string|email|max:255|unique:users,id,' . $user->id,
]);
$user->update($request->only(['name', 'email']));
return redirect()->route('users.index');
}
In your custom request class, you don't have the $user initialized and you try to use it, while in the controller method the $user is passed as a parameter.
Note $this->user in the Request returns the currently authenticated user, so make sure that you always want to use his ID, instead of an ID of the passed in user, hence the reason I am using request('user') to get the user id from the URL.
So try this instead:
public function rules()
{
return [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => ['required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore(request('user'))],
];
}
You need to change $user->id to $this->user->id and it should work properly. Check below:
return [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => ['required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($this->user->id)],
];
Hope it helps you!!
User class instance is missing in UpdateRequest class constructor or you can try with $this->user->id. It may help you.

"Trying to get property of non-object" from validate

for some reason that I do not know, when I try to pass a validation without request and try to use one if
public function save(Request $request){
$request = $request->validate([
'name' => ['string', 'max:255'],
'email' => ['string', 'email', 'max:255', 'unique:users'],
]);
if($request->name != null){
return $request;
}
return $request;
}
You are replacing the type of your $request with the result from validate()
The validation will handle the what you wish to, so no need to worry. If you say the variable name is required, it will enforce it to not be null or empty;
So, just replace the result to a specific variable instead of replacing $request by doing:
$validationResult = $request->validate([
'name' => ['string', 'required', 'max:255'],
'email' => ['string', 'required', 'email', 'max:255', 'unique:users'],
]);
Better option than this is to create a specific request type by running
php artisan make:request YourRequest`
Your new class will be ready at app/Http/Requests where you can specify not only your rules() as you have in your array, as the messages() you wish each to output.
Then all you need to do is to replace your save(Request $request)
for save(YourRequest $request) which will kick in the validation before it triggers the method, which means you are at ease within the controller method to do the logic instead of having to double check your variables
Examples for common rules() within your class, will be:
public function rules()
{
return [
'email' => 'required|email|unique:users|max:255',
'name' => 'required|min:2|max:200',
];
}
public function messages()
{
return [
'email.required' => 'The email field is required',
'email.email' => 'The email field needs to be an email type. Ex:. type#gmail.com',
....
];
}
Obviously adjust the rules and messages to your project and liking :)

Categories