Change redirection after validation failed - laravel - validation

I am validating a user registration form
for EX: (Requests validation class)
class UserCreateAccountRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'email' => 'required|unique:users,email',
'password' => 'required|min:6|max:32'
];
}
}
If the email is already registered I want to redirect to the password reset page.
How can i achieve this using request validation class without putting the validation in to the controller?

Inside the authorize function check whether the email already exists,
public function authorize()
{
$email = Request::input('email');
$result = User::where('email',$email)
->exists();
if($result)
{
return false;
}
return true;
}
If this returns false, forbiddenResponse function will be fired, therefore you need to include that function and inside that you can redirect to the page you want. This function will only returns false if the email is already exist.
public function forbiddenResponse()
{
return redirect('password_reset');
}
That's all.For your reference following is the structure of the Request class,
<?php namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Response;
class FriendFormRequest extends FormRequest
{
public function rules()
{
return [
'first_name' => 'required',
'email_address' => 'required|email'
];
}
public function authorize()
{
// Only allow logged in users
// return \Auth::check();
// Allows all users in
return true;
}
// OPTIONAL OVERRIDE
public function forbiddenResponse()
{
// Optionally, send a custom response on authorize failure
// (default is to just redirect to initial page with errors)
//
// Can return a response, a view, a redirect, or whatever else
return Response::make('Permission denied foo!', 403);
}
// OPTIONAL OVERRIDE
public function response()
{
// If you want to customize what happens on a failed validation,
// override this method.
// See what it does natively here:
// https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Http/FormRequest.php
}
}

Related

Does Laravel support "typed" requests?

To transform a database entity to an API response Laravel support resources, eg. UserResource extends JsonResource. The resource allows me to cleanly define which fields from the entity should be included in the response, how to transform them etc.
Is there a similar functionality for requests? My requests typically look like this:
public function create(JsonRequest $request): UserResource
{
$data = $request->json()->all();
/* Remove, transform, add request fields etc. */
$user = User::create($data);
$user->save();
return new UserResource($user);
}
In our case we have a legacy database behind a modern API so there are a number of fields that need to transformed, renamed etc. before pushing them into the entity class. The fields differ from request to request but the steps are very similar. Is there a less boilerplate-y way to do this, something similar to how resources transform entities to responses?
Something like:
class UserRequest extends JsonRequest {
public function fromArray(JsonRequest $request) {
…
}
}
Then the request could look like this:
public function create(UserRequest $request): UserResource
{
$user = User::create($request);
$user->save();
return new UserResource($user);
}
I suppose, that most of your problems can solve form request. See example below
Form request class:
namespace App\Http\Requests;
use Carbon\Carbon;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class TestRequest 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()
{
return [
'date' => 'required|date_format:Y-m-d H:i:s',
'name' => 'required|string',
];
}
// here you can specify custom error messages
public function messages()
{
return [
'date.required' => 'No date specified',
'date.date_format' => 'Invalid date format',
'name.required' => 'No name specified',
'name.string' => 'Invalid name format',
];
}
// here you can implement some data mapping before validation
protected function validationData()
{
return $this->transform($this->all());
}
// some data transformation logic
// You can place it anywhere in your applciation services
protected function transform($input)
{
$transformed = [];
foreach ($input as $field => $value) {
if ($field == 'name') {
$value = strtoupper($value);
} elseif ($field == 'date') {
$value = Carbon::parse($value)->toDateTimeString();
}
$transformed[$field] = $value;
}
return $transformed;
}
public function failedValidation(Validator $validator)
{
// here you can implement custom validation failure
parent::failedValidation($validator);
}
}
Here is my test route: Route::get('/test', 'TestController#index');
And controller:
use App\Http\Requests\TestRequest;
class TestController extends Controller
{
public function index(TestRequest $request)
{
return response()->json($request->validated());
}
}
So, then requesting route: curl -H 'Accept: application/json' 'http://localhost:8000/test?date=01.01.2019&name=petya'
And getting response: {"date":"2019-01-01 00:00:00","name":"PETYA"}
And dont be shy to see source code of request and form request, cause of not all methods you wish are described in docs. Hope this helps

laravel auth add a admin

Hi I am trying to follow the laravel multi auth example as seen here:
I am using laravel 5.6, I think dev marketer is using 5.2.
https://www.youtube.com/watch?v=Ir2nAD9UDGg&t=1930s
So my admin controller is as below:
The problem is if I go to : localhost/site1/admin
I get a error in the browser
"This page isn’t working
localhost redirected you too many times.
Try clearing your cookies.
ERR_TOO_MANY_REDIRECTS"
I guess as it says it is stuck in some kind of redirect loop???
If I comment out the constructor it goes to admins page without
being logged in, which is obviously not good.
I also added a function to : handler.php is shown below :
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Auth;
class AdminLoginController extends Controller
{
protected $guard = 'admin';
use AuthenticatesUsers;
public function __construct()
{
$this->middleware('auth:admin')->except('logout');
}
protected function guard()
{
return Auth::guard('admin');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//return view('auth/admin');
return view('auth/admin');
}
public function showLoginForm()
{
return view('auth.admin-login');
}
public function login( Request $request )
{
// validate form
$this->validate( $request , [
'email' => 'required|email',
'password' => 'required|min:6'
]);
// attempt login
if (Auth::guard('admin')->attempt(['email'=>$request->email,'password'=>$request->password])) {
// if successful goto intended page
return redirect()->intended(route('admin.dashboard'));
}
// unsuccessful - redirect.
return redirect()->back()->withInput( $request->only('email','remember'));
}
}
Handler.php
public function unauthenticated($request, AuthenticationException $exception)
{
if($request->expectsJson()) {
return response()->json(['error'=>'Unauthenticated' , 401 ]);
}
$guard = array_get( $exception->guards(),0);
switch($guard) {
case 'admin':
$login='admin.login'; break;
default:
$login ='login'; break;
}
return redirect()->guest(route( $login ));
}
Also not sure if it's relevant or useful - but if I comment out the unauthenticated() function in handler.php it redirects to standard login/ instead of new admin login.
and keeping the function in gives me "The page isn't redirecting properly" in firefox
think i solved it...
in handler I changed redirect to:
case 'admin':
if(Auth::guard($guard)->check()) {
return redirect()->route('admin/dashboard');
}
break;
In RedirectIfAuthenticated:
case 'admin':
if(Auth::guard($guard)->check()) {
return redirect()->route('admin/dashboard');
}
break;
In routes added Middleware :
Route::get('/' , 'Auth\AdminLoginController#index')->name('admin.dashboard')->middleware('auth:admin');
In the admin controller I commented out the constructor:
// public function __construct()
// {
// $this->middleware('auth:admin')->except('logout');
// }
I changed:
return redirect()->guest(route( $login ));
To:
return redirect()->to( $login );
This seems to work - whether it's the "official" way to solve it I'm not sure!!

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 - return variable from Form Requests to Controller

How can I return a variable from Form Requests (App\Http\Requests) to Controller (App\Http\Controllers)?
I am saving a record on function persist() on Form Requests.
My goal is to pass the generated id so that I can redirect the page on edit mode for the user. For some reason, the Controller cannot receive the id from Form Requests.
App\Http\Requests\MyFormRequests.php:
function persist()
{
$business = Business::create([
'cart_name' => $this['cart_name'],
'product' => $this['product']
]);
return $myid = $business->id;
}
App\Http\Controllers\MyControllers.php:
public function store(MyFormRequests $request)
{
$request->persist();
return redirect()->route('mypage.edit.get', $request->persist()->$myid);
}
Important
I must add that this is not the recommended way. Your FormRequest should only be responsible for validating the request, while your Controller does the storing part. However, this will work:
App\Http\Requests\MyFormRequests.php:
function persist()
{
return Business::create([
'business_name' => $this['business_name'],
'nationality' => $this['nationality']
])->id;
}
App\Http\Controllers\MyControllers.php:
public function store(MyFormRequests $request)
{
$id = $request->persist();
return redirect()->route('register.edit.get', $id);
}
A guy name Snapey helped me:
public function store(MyFormRequests $request)
{
$business = $this->persist($request);
return redirect()->route('register.edit.get', $business->id);
}
private function persist($request)
{
....
return $business;
}
hope this could help someone in the future.

Laravel validation request class return model with errors

When validating a form with a request class you can manually validate the data using the validate() method but what do you return back I've tried return $this and return $this->errors but it just shows SQL integrity constraint duplicate entry which is correct but it doesn't show my form with the errors. When doing validation inside the controller you return the model and the errors but what do I return and set errors on validate method in the request class.
Request Class:
namespace App\Http\Requests;
use App\Http\Requests\Request;
use Auth;
class ProductRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
protected $action;
public function authorize()
{
if(Auth::check()) {
return true;
}
}
public function validate() {
$v = \Validator::make(parent::all(), $this->rules());
if ($v->passes()) return true;
$this->errors = $v->messages();
// tried returning $this; and $this->errors
return false;
}
public function all()
{
$data = parent::all();
if( $data['slug'] === '') {
// if the slug is blank, create one from title data
$data['slug'] = str_slug( $data['title'], '-' );
}
return $data;
}
public function messages()
{
}
public function rules() {
}
}
your rule method is empty your not validating any thing the error you got is an SQL exception not a validation error.

Resources