change value of $request before validation in laravel 5.5 - laravel

I have a form in route('users.create').
I send form data to this function in its contoller:
public function store(UserRequest $request)
{
return redirect(route('users.create'));
}
for validation I create a class in
App\Http\Requests\Panel\Users\UserRequest;
class UserRequest extends FormRequest
{
public function rules()
{
if($this->method() == 'POST') {
return [
'first_name' => 'required|max:250',
It works.
But How can I change first_name value before validation (and before save in DB)?
(Also with failed validation, I want to see new data in old('first_name')
Update
I try this:
public function rules()
{
$input = $this->all();
$input['first_name'] = 'Mr '.$request->first_name;
$this->replace($input);
if($this->method() == 'POST') {
It works before if($this->method() == 'POST') { But It has not effect for validation or for old() function

Override the prepareForValidation() method of the FormRequest.
So in App\Http\Requests\Panel\Users\UserRequest:
protected function prepareForValidation()
{
if ($this->has('first_name'))
$this->merge(['first_name'=>'Mr '.$this->first_name]);
}

Why not doing the validation in the controller? Than you can change things before you validate it and doing your db stuff afterward.
public function store(Request $request)
{
$request->first_name = 'Mr '.$request->first_name;
Validator::make($request->all(), [
'first_name' => 'required|max:250',
])->validate();
// ToDo save to DB
return redirect(route('users.create'));
}
See also https://laravel.com/docs/5.5/validation

Simply use
$request->merge(['New Key' => 'New Value']);
In your case it can be as follows for saving
$this->merge(['first_name'=>'Mr '.$this->first_name]);

Related

Can't pass Request from controller to another controller's view

I'm trying to pass a Request from a controller, but for reasons I don't understand the data simply isn't being passed through to the view and I get Undefined variable: request. I have confirmed that right up until the redirect to the action the request is populated with all the additional variables, so the issue must be after that.
ManufacturerController
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
return redirect()->action([TransactionController::class, "index"])->with($request);
}
abort(404);
}
Manufacturer model:
public function oneplus($request) {
$id = $request->id;
/* BUSINESS LOGIC THAT GENERATES $new FROM $id... */
$request->merge([
'new' => $new
]);
return $request;
}
Route in web.php
Route::get('/payment', [TransactionController::class, "index"]);
TransactionController:
public function index()
{
return view('payment');
}
payment.blade.php
{{ dd($request->new) }}
The problem when using redirects is that the redirect will cause a brand new request to happen. When using redirect()->with('variable', 'value') you need to then access that variable using:
session('variable')`
the reason being that the variable is "flashed" to the next request via the session (in practice it's not sent to the next request, it's just available for the next request through the session and then disappears).
While this may be an easy solution to your problem a better solution is to not use a redirect if possible. Here's a simplification of an alternative:
ManufacturerController:
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
$transactionController = app()->make(TransactionController::class);
return $transactionController->index($request);
}
TransactionController:
public function index(Request $request)
{
return view('payment')->with("request", $request);
}
This will call the other controller method within the same request.
You need to make few changes in TransactionController and ManufacturerController to make it work
TransactionController:
public function index(Request $request)
{
return view('payment', [
'request' => $request->session()->get('request')
]);
}
ManufacturerController:
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
return redirect()->action([TransactionController::class, "index"])->with('request', $request->all());
}
abort(404);
}
You can pass like this
ManufacturerController :
return redirect()->action(
[TransactionController::class, "index"],
['data' => $request]
);
Route in web.php
// ? = Optional
Route::get('/payment/{data?}', [TransactionController::class, "index"]);
TransactionController:
public function index($data)
{
return view('payment');
}

Laravel unique validation if ID isn't in request

I want to do some validation for a field. Right now works for unique values, the problem is that on Update I get the same error. So I want to filter the request, if that post request contain ID field then this field shouldn't be unique.
public function rules()
{
return [
'customer_id' => 'required|unique:customers',
];
}
You can use Rule class' unique method for the update method
public function rules()
{
return [
'customer_id' => [
'required',
Rule::unique('customers')->ignore($customer->customer_id),
];
}
Laravel docs: https://laravel.com/docs/8.x/validation#rule-unique
For common rules() function it can be done as
use Illuminate\Validation\Rule;
class CustomerController extends Controller
{
protected function rules($customer)
{
return [
'customer_id' => [
'required',
Rule::unique('customers')->ignore($customer->exists ? $customer->customer_id : null),
];
}
public function store(Request $request)
{
$customer = new Customer;
$request->validate($this->rules($customer));
}
public function update(Request $request, Customer $customer)
{
$request->validate($this->rules($customer);
}
}
In my case I have a single method for store/update and I check If I have an ID or not. Also I added $customer = request()->all(); and ignore($customer['ID'] , that is for my specific case.
Laravel Docs warns against passing user controller request input to the ignore method
For your specific case you can do
$customer = !empty($request->input('ID') ? Customer::findOrFail($request->input('ID')) : new Customer;
//Then pass the customer to the rules()
$validated = $request->validate($this->rules($customer));

Laravel default values for fields in FormRequest

Can I set a default value to a not-existing field in a FormRequest in Laravel?
For example, if a field called "timezone" does not exist in the incoming request, it get set to "America/Toronto".
Well I wrote a trait for this, which checks a function called 'defaults' exist in the form request it will replace the default values
trait RequestDefaultValuesTrait {
protected function prepareForValidation(){
// add default values
if( method_exists( $this, 'defaults' ) ) {
foreach ($this->defaults() as $key => $defaultValue) {
if (!$this->has($key)) $this->merge([$key => $defaultValue]);
}
}
}
}
the thing that you need to do is adding this trait to FormRequest class and then add a function like this:
protected function defaults()
{
return [
'country' => 'US',
'language' => 'en',
'timezone' => 'America/Toronto',
];
}
Being honest I don't link this method, but It works.
Try this
if(!$request->has('timezone') {
$request->merge(['timezone' =>'America/Toronto']);
}
I'm not so sure if you need to do it in this way, but if you want to:
class CreateUpdateDataFormRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
protected function getValidatorInstance()
{
$data = $this->all();
if(!isset($data['timezone'])) {
$data['timezone'] = 'America/Toronto';
$this->getInputSource()->replace($data);
}
// modify data before sending to validator
return parent::getValidatorInstance();
}
in request class add
public function prepareForValidation()
{
$this->mergeIfMissing([
'timezone' => 'America/Toronto'
]);
}

Laravel | Validate generated value

I have an endpoint for data create.
The request is "name". I need to generate "slug" and validate that slug is unique.
So, let's say
book_genres table.
id | name | slug
Request is ["name" => "My first genre"].
I have a custom request with a rule:
"name" => "string|unique:book_genres,name".
I need the same check for the slug.
$slug = str_slug($name);
How can I add this validation to my custom request?
Custom request class:
class BookGenreCreate extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
"name" => 'required|string|unique:book_genres,name',
];
}
}
So basically what you want to do is try to manipulate the request data before validation occurs. You can do this in your FormRequest class by overriding one of the methods that is called before validation occurs. I've found that this works best by overriding getValidatorInstance. You can then grab the existing data, add your slug to it and then replace the data within the request, all before validation occurs:
protected function getValidatorInstance()
{
$data = $this->all();
$data['slug'] = str_slug($data['name']);
$this->getInputSource()->replace($data);
return parent::getValidatorInstance();
}
You can also add the rules for your slug to your rules method as well:
public function rules()
{
return [
"name" => 'required|string|unique:book_genres,name',
"slug" => 'required|string|unique:book_genres,slug',
];
}
So your class will look something like this:
class BookGenreCreate extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|unique:book_genres,name',
'slug' => 'required|string|unique:book_genres,slug',
];
}
protected function getValidatorInstance()
{
$data = $this->all();
$data['slug'] = str_slug($data['name']);
$this->getInputSource()->replace($data);
return parent::getValidatorInstance();
}
}
Now when the request comes through to your controller, it will have been validated and you can access the slug from the request object:
class YourController extends Controller
{
public function store(BookGenreCreate $request)
{
$slug = $request->input('slug');
// ...
}
}
You can add the 'slug' to the request, then use validations as usual.
rules() {
// set new property 'slug' to the request object.
$this->request->set('slug', str_slug($request->name));
// rules
return [
'name' => 'string|unique:book_genres,name',
'slug' => 'string|unique:book_genres,slug'
]
}

laravel 5 form request validation issue

in my laravel 5.1 app, I've got a Book model with a required "Title" field and several others non-required fields. To validate Book create/update, I use form request validation like this:
class StoreBookRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'year' => 'numeric',
'pages' => 'numeric',
];
}
}
I then type-hint the request on the controller action and everytning works fine. Now I need to create a new controller action that updates only one of the non-required fields. To do so, I created another request like this:
class StoreReviewRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'vote' => 'numeric',
];
}
}
and I type-hint the request in the controller action:
public function updateReview(StoreReviewRequest $request, Book $book)
{
$input = array_except(Input::all(), '_method');
$book->update($input);
Session::flash('message', 'Review updated');
return redirect('/book');
}
The problem is that when I use the new controller action, the update form does not pass validation, but complains about missing "Title" field, even tough I'm not decalring that field as required in my StoreReviewRequest class. What am I doing wrong? Thanks!
As #Needpoule suggested, I was using the wrong action in my form.

Resources