Laravel 5.5 conditional form request validation rule on update - php

I created a validation rule for the image form.
It works fine on store method but I do not want the image field to be required on update because I may only update the title for example.
class ImageRequest extends Request
{
/**
* Rules array
*/
protected $rules = [
'title' => 'required|string|between:3,60',
'alt' => 'sometimes|string|between:3,60',
'image' => 'required|image|max:4000|dimensions:min_width=200,min_height=200',
];
/**
* 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 $this->rules;
}
}
For unique validation we can add custom query conditions:
'email' => Rule::unique('users')->ignore($user->id, 'user_id')
or
'email' => Rule::unique('users')->where(function ($query) {
return $query->where('account_id', 1);
})
Is it a clean way to achieve something similar for required?
Apply required only for new images.

you Can use switch statement inside rule
public function rules()
{
switch ($this->method()) {
case 'GET':
case 'DELETE': {
return [];
}
case 'POST': {
return [
'first_name'=>'required',
'last_name'=>'required',
'email'=>'required|email|unique:users,email,'.$this->id,
'password'=>'',
'dob'=>'required',
'phone_one'=>'required',
'phone_two'=>'required',
//'user_role'=>'required',
// 'profile_image'=>'required'
];
}
case 'PUT':
case 'PATCH': {
return [
];
}
default:break;
}
Also you can use condtion like on update yuo have id so based on that you can check whether its update or insert since on insert you dont have id so

Create another class that extends the Request class, DI that into your update controller action
class UpdateImageRequest extends Request
{
/**
* Rules array
*/
protected $rules = [
'title' => 'required|string|between:3,60',
'alt' => 'sometimes|string|between:3,60'
];
/**
* 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 $this->rules;
}
}

much better way is to use nullable in Laravel 5.5 validations
Ref Docs
The field under validation may be null. This is particularly useful
when validating primitive such as strings and integers that can
contain null values.
class ImageRequest extends Request
{
/**
* Rules array
*/
protected $rules = [
'title' => 'required|string|between:3,60',
'alt' => 'nullable|string|between:3,60',
'image' => 'nullable|image|max:4000|dimensions:min_width=200,min_height=200',
];
/**
* 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 $this->rules;
}
}
However I have used recently with image and it worked like charm for me. Give it a try!

The simplest way in this case in the other way. By default have rules for update and if it's store add required like so:
class ImageRequest extends Request
{
/**
* Rules array
*/
protected $rules = [
'title' => 'required|string|between:3,60',
'alt' => 'sometimes|string|between:3,60',
'image' => 'image|max:4000|dimensions:min_width=200,min_height=200',
];
/**
* 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()
{
$rules = $this->rules;
if ($this->isMethod('POST')) {
$rules['image'] = 'required|' . $rules['image']
}
return $rules;
}
}

I found a solution.
I renamed image into file.
The route is homestead.app/images/1 on update and homestead.app/images on store so the $image property will be $this->image = 1 on update and $this->image = null on store.
class ImageRequest extends Request
{
/**
* Rules array
*/
protected $rules = [
'title'=> 'required|string|between:3,60',
'alt' => 'sometimes|string|between:3,60',
'file' => [
'image',
'max:4000',
'dimensions:min_width=200,min_height=200',
],
];
/**
* 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()
{
$this->rules['file'][] = is_null($this->image) ? 'required' : 'sometimes';
return $this->rules;
}
}

Related

Custom Form-Request dosen't work as expected- Backpack

I'm creating a user management in Laravel using Backpack package, the main functionallity works well, I mean, you can create new users and then log in with them and deleteor edit them. But there is an aspect that dosent works as I want it. The problem is that when you edit it you must insert a password too to save the edits, this is not correct because you can not modify the password. To solve this, following the BackPack documentation I separate the UserRequest, so now I have two: UserRequest & EditUserRequest.
Nevertheless, the form still mark as required the password field, it seems that it pass trhough the setupCreateOperation function even if I click on edit the user.
I upload some images with the code and what appears me in the screen:
UserCrudController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\UserRequest;
use App\Http\Requests\EditUserRequest;
use Illuminate\Support\Facades\Hash;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
/**
* Class UserCrudController
* #package App\Http\Controllers\Admin
* #property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class UserCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* #return void
*/
public function setup()
{
CRUD::setModel(\App\Models\User::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/user');
CRUD::setEntityNameStrings('user', 'users');
}
/**
* Define what happens when the List operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-list-entries
* #return void
*/
protected function setupListOperation()
{
CRUD::column('name');
CRUD::column('email');
CRUD::column('password');
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
}
/**
* Define what happens when the Create operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-create
* #return void
*/
protected function setupCreateOperation()
{
CRUD::setValidation(UserRequest::class);
//dd('setupCreateOperation');
CRUD::field('name');
CRUD::field('email');
CRUD::field('password');
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
}
/**
* Define what happens when the Update operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-update
* #return void
*/
protected function setupUpdateOperation()
{
//dd('setupUpdateOperation');
$this->crud->setValidation(EditUserRequest::class);
$this->crud->setRequest($this->handlePasswordInput($this->crud->getRequest()));
$this->crud->unsetValidation(); // validation has already been run
$this->setupCreateOperation();
}
/**
* Handle password input fields.
*/
protected function handlePasswordInput($request)
{
// Encrypt password if specified.
if ($request->input('password')) {
//dd($request->input('password'));
$request->request->set('password', Hash::make($request->input('password')));
} else {
//si no lo mete el usuario que no lo tenga en cuenta
$request->request->remove('password');
}
return $request;
}
}
UserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['required', 'string', 'min:8'], // This is the diference
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
EditUserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class EditUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['nullable', 'string', 'min:8'], // this is the difference
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
If you call setupCreateOperation() at the end of your setupUpdateOperation() then the CreateRequest will override the UpdateRequest. What you can do instead is do that first:
protected function setupUpdateOperation()
{
$this->setupCreateOperation();
$this->crud->setValidation(EditUserRequest::class);
}

Make parameter unique in laravel request

hello I have a table called gallery_category_contents
language
title
gallery_category_id
en
FISH
1
en
DOGS
2
and my request rules are like this
public function rules()
{
return [
"language"=>[
"required",
Rule::unique('gallery_category_contents','language')->ignore($this->gallery_category_id,'gallery_category_id')
],
"title"=>[
"string",
"required"
]
];
}
what i want is that it doesn't add already existing language with same gallery_category_id
For example, English language has been added to 1 gallery_category_id, so it should not be added again. my current code works, but it affects all the data in that table, that is, it also affects category 2
how to do it?
Please try this way:
public function rules(): array
{
return [
'gallery_category_id' => [
'required',
Rule::exists('gallery_category'),
],
'language' => [
'required',
Rule::unique('gallery_category_contents', 'language')
->where('gallery_category_id', $this->input('gallery_category_id')),
],
'title' => [
'required',
'string',
]
];
}
You could make your own validation rule:
php artisan make:rule CompositeUnique
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CompositeUnique implements Rule, DataAwareRule
{
private array $data;
private array $columns;
private $model;
private $ignoreId;
/**
* Create a new rule instance.
*
* #param $model
* #param string|array $colums
* #return void
*/
public function __construct($model, $columns, $ignoreId)
{
$this->model = $model;
$this->columns = (array)$columns;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
return $this->model::query()
->where($this->columns, array_reduce(function($where, $column) {
$where[$column] = $this->data[$column];
return $where;
}, [])
->where($this->model->getKeyName(), $this->ignoreId)
->doesntExist();
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute must be unique.';
}
/**
* Set the data under validation.
*
* #param array $data
* #return $this
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
}
And use it like this:
use App\Rules\CompositeUnique;
use App\Models\GalleryCategoryContents;
//...
new CompositeUnique(
GalleryCategoryContents::class,
[ 'language' 'gallery_category_id' ],
$this->gallery_category_id
);`

Laravel 5.5 use custom validation rule in validation request file?

Is it possible to use my custom validation rule in a validation request file?
i want to use my custom rule called EmployeeMail
here is the code of the request file
class CoachRequest 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
*/
public function rules()
{
$rules = [];
if ($this->isMethod('post') ) {
$rules = [
'name' => 'required|string',
'email' => 'required|email|employeemail', <<<--- this
'till' => 'required|date_format:H:i|after:from',
];
}
//TODO fix this
//TODO add custom messages for every field
return $rules;
}
}
it gives me an error when i try to use it like this
Method [validateEmployeemail] does not exist.
code of custom rule
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class EmployeeMail implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
// If mail is that of an employee and not a student pass it
return preg_match("/#test.nl$/", $value) === 1;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'Email is geen werknemers mail';
}
}
can i only use this custom rule like this?
$items = $request->validate([
'name' => [new FiveCharacters],
]);
Rutvij Kothari answered the question in the comments.
It seems you are validating string with a regular expression, the same logic can be achieved by regex buit-in validation method. Check it out. laravel.com/docs/5.5/validation#rule-regex No need to create your own validation rule. – Rutvij Kothari
If you want to use your validation pass it into an array. like this. 'email' => ['required', 'email', new employeemail]

Laravel Changing Request data in Form Request Class

I'm processing a form with multiple date input which is not in A.D. For validation purpose i'm using Form Request.
Before validation and inserting in my database date input must be converted into A.D, so that i can do the proper validation & then if validation succeed date input is stored in A.D .
here is my code for converting date input in A.D
<?php
abstract class Request extends FormRequest
{
public function all()
{
$input = parent::all()
foreach ($input as $key=>$value)
{
if (substr($key, -5) == "_date")
{
$input[$key] = Helper::convert_in_ad($value);
}
}
return $input;
}
}
Now the problem is suppose you have failed validation and redirect back to the previous action and you then use old() or some other method to access the request data from the session, it will be modified, and i cannot get the the original data.
How can i change the date input in A.D when before validation so that i can properly validate in A.D and then store all the date input in A.D. by solving failed validation problem having modified input.
Edit Question
update:
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\Contracts\CourseInterface;
use App\Repositories\Contracts\ClassInterface;
use App\Http\Requests\ClassRequest;
use App\Helpers\Helper;
class ClassController extends Controller
{
public function __construct(ClassInterface $class, CourseInterface $course)
{
$this->class = $class;
$this->course = $course;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$classes = $this->class->paginate();
return view('backend.class.index')->with([
'classes' => $classes
]);
/*return view('backend.class.index')->with([
'classes' => $classes
]);*/
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$courses = $this->course->all();
return view('backend.class.create')->with([
'courses' => $courses
]);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(ClassRequest $request)
{
// dd($request->all());
$this->class->create($request->all());
return redirect()->route('classes.index');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$class = $this->class->find($id);
$courses = $this->course->all();
return view('backend.class.edit')->with([
'class' => $class,
'courses' => $courses
]);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(ClassRequest $request, $id)
{
$class = $this->class->update($request->all(), $id);
return redirect()->back();
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
$this->class->delete($id);
return redirect()->route('classes.index');
}
public function delete($id)
{
$class = $this->class->find($id);
return view('backend.class.delete')->with([
'class' => $class
]);
}
}
My class Request File
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\Helpers\Helper;
class ClassRequest extends Request
{
public function all()
{
$input = parent::all();
foreach ($input as $key=>$value)
{
if (substr($key, -5) == "_date")
{
$input[$key] = Helper::convert_in_ad($value);
}
}
return $input;
}
/**
* 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()
{
//$this->sanitize();
switch($this->method())
{
case 'GET':
case 'DELETE':
{
return [];
}
case 'POST':
{
return [
'name' => 'required',
'course_id' => 'required',
'start_date' => 'required|date',
'end_date' => 'date|after:start_date',
];
}
case 'PUT':
case 'PATCH':
{
return [
'name' => 'required',
'course_id' => 'required',
'start_date' => 'required|date',
'end_date' => 'date|after:start_date',
];
}
default:break;
}
}
}
For validation purpose i need to change the date from B.S in A.D because laraval validation don't recognize B.S date. If i convert date in request file the problem is if validation fails i get the modified request back in form after redirect.
So how can i validate the date by converting it into A.D. The date in database table must be stored in A.D format for that i can use Accessors and Mutators the main problem is how to validate the data which user input in B.S format.
Edit After the suggestion i got
Thank you all for the suggestion, thank you very much for your help. One way i can validate is by making a custom validation rule as suggested. Right now i have another idea for making this work.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Helpers\Helper;
abstract class Request extends FormRequest
{
/**
* Sanitize input before validation
*
* #return array
*/
public function validator($factory)
{
return $factory->make(
$this->sanitizeInput(), $this->container->call([$this, 'rules']), $this->messages()
);
}
protected function sanitizeInput()
{
if (method_exists($this, 'sanitize'))
{
return $this->container->call([$this, 'sanitize']);
}
return $this->all();
}
/**
* Check for input having _date for converting it into AD
*
* #return array
*/
public function sanitize()
{
$input = $this->all();
foreach ($input as $key=>$value)
{
if (substr($key, -5) == "_date")
{
$input[$key] = Helper::convert_in_ad($value);
}
}
return $input;
}
}
By using the following code request data is not changed. And There will be no need for creating custom validation and this will be easy if i later decided to take date in A.D from user then changing every request file for updating validation rule wont be necessary.
What do you think about this?
As has been mentioned in the comments you should try and avoid editing the data in your FormRequest.
What you could do is define a new validation rule specifically for this: https://laravel.com/docs/5.3/validation#custom-validation-rules
So, in your app/Providers/AppServiceProvider (or another registered ServiceProvider) you could have something like:
Validator::extend('bs_date', function ($attribute, $value, $parameters, $validator) {
$date = date_parse(Helper::convert_in_ad($value));
return checkdate($date['month'], $date['day'], $date['year']);
}, 'Your error message');
Validator::extend('bs_after', function ($attribute, $value, $parameters, $validator) {
$data = $validator->getData();
$before = Helper::convert_in_ad($data[$parameters['0']]);
$after = Helper::convert_in_ad($value);
return (new \DateTime($before)) < (new \DateTime($after));
}, 'Your error message');
Rules
'start_date' => 'required|bs_date',
'end_date' => 'date|bs_after:start_date',
Obviously, don't forget to import Validator and Helper in the ServiceProvider.
This should mean that you don't have to edit your input anymore.
Hope this helps!

Phalcon ORM doesn't work

I am learning phalcon. I have some problems with models.
Function FindFirst returns nothing, also it doesn't show any errors or exceptions. Here is my code:
public function indexAction()
{
$user = Users::findFirst(1);
var_dump($user);
}
And all what I get - is empty page.
Here is my Users Model:
<?php
namespace Models\User;
use Phalcon\Mvc\Model\Validator\Email as Email;
class Users extends \Phalcon\Mvc\Model
{
/**
*
* #var integer
*/
public $id;
/**
*
* #var string
*/
public $login;
/**
*
* #var string
*/
public $email;
public function initialize()
{
$this->setSource("users");
}
/**
* Validations and business logic
*/
public function validation()
{
$this->validate(
new Email(
array(
'field' => 'email',
'required' => true,
)
)
);
if ($this->validationHasFailed() == true) {
return false;
}
}
/**
* Independent Column Mapping.
* Keys are the real names in the table and the values their names in the application
*
* #return array
*/
public function columnMap()
{
return array(
'id' => 'id',
'login' => 'login',
'email' => 'email'
);
}
}
Some additional information:
I have edited config files.
Phalcon version is 2.0
First you should ensure that the User model you are trying to load is in the right namespace, what means in your case you should use:
$user = \Models\User\Users::findFirst(1);
And to retrieve an output (depending on your index.php but probably this way) you should return "something", otherwise the buffer will be empty and nothing will be displayed.

Categories