I am creating a all-in-one page for all errors in Laravl app. The error page should include a layout for currently logged in user: normal user, admin and guest. To be able to use Auth::check(), I created error page using fallback route.
Route::fallback(function () {
return view('errors.general', ['msg'=>'Error Description']);
});
And the view:
#php
if (Auth::guard('admin')->check())
$layout = "layouts.admin";
elseif (Auth::check())
$layout = "layouts.app";
else
$layout = "layouts.start";
#endphp
#extends($layout)
#section('content')
<div class="error-container">
<div class="error-box">
<div class="error-text">
{{ $msg }}
</div>
</div>
</div>
#endsection
The structure is working for 404 errors. But as for 500 errors, Laravel is showing default 500 page. How to direct all errors to use the same view with additonal error messages.
Instead of creating fallback route, handle all exception inside a Error Handler : app/Exceptions/Handler.php
And you can also check which user is logged in inside handler with below code it is just a basic example with which you can handle 500 errors like below code:
public function render($request, Exception $exception)
{
// 404 page when a model is not found
if ($exception instanceof ModelNotFoundException) {
if (Auth::guard('admin')->check()) {
// Your custom view for admin
} else {
//Your custom view for another user
}
}
if ($exception instanceof \ErrorException) {
if (Auth::guard('admin')->check()) {
// Your custom view for admin
} else {
//Your custom view for another user
}
}
return parent::render($request, $exception);
}
The fallback route is only catches non-existent routes (i.e., 404):
https://laravel.com/docs/6.x/routing#fallback-routes
But you can define your own error pages.
https://laravel.com/docs/6.x/errors#custom-http-error-pages
Laravel makes it easy to display custom error pages for various HTTP status codes. For example, if you wish to customize the error page for 404 HTTP status codes, create a resources/views/errors/404.blade.php.
In order to use your single error layout, you could do something like this:
resources/views/errors/500.blade.php
#include('layouts.error',['msg' => $exception->getMessage()])
EDIT: However, I do not believe that error pages load the session middleware, so you will likely have trouble attempting to use the Auth facade without additional effort.
Related
Im trying to redirect users with "TokenMismatchException" to login page. All my website is based on JQuery, the user never change the main page, only the content, so the problem is that the response from Handler.php about the error will be passed to the jquery functions, but there's tons of functions, i dont want to make an if in all them.
I tried creating a blade with this content:
<script>
window.location.replace('https://brasilbitcoin.com.br/entrar');
</script>
And return this blade if error, but doesn't work either...
Any suggestions?
inside your Exceptions/Handler.php
public function render($request, Exception $exception)
{
if ($this->isTokenMismatchException($exception)){
return redirect('/login');
}
}
<form method="post" action="{{action('PLAYERController#update', $ply->reg_no)}}">
{{csrf_field()}}
Getting method not allowed exception on custom validation with false return. Tried mentioning PUT, PATCH and DELETE inside csrf field. Still, does not work.
UPDATE
using post for form method. Using method_field('POST'). not defining get method for the update function. If I go back from the error page back to the form page and press refresh, then the validation message is displayed as it should.
UPDATE 2
Validator::extend('check_sold_amount', function($attribute, $value, $parameters, $validator) {
if(($value%5000)==0)
{
return true;
}
return false;
});
}
UPDATE 3
Controller code
public function update(Request $request, $reg_no)
{
//
$this->validate($request, [
'sold_amount' => 'required|check_sold_amount',
'sold_to_team'=>'required'
]);
$ply = Player::find($reg_no);
$ply->sold_amount = $request->get('sold_amount');
$ply->sold_to_team = $request->get('sold_to_team');
$team_name=$ply->sold_to_team;
$team=Team::find($team_name);
if($ply->category=='indian')
{
$team->indian_players=$team->indian_players+1;
}
else {
$team->foreign_players=$team->foreign_players+1;
}
$team->balance=$team->balance-$ply->sold_amount;
$ply->save();
$team->save();
//return view('player.index');
}
Method not allowed means you do not have a route set up for the request that happened. There are 2 possibilities:
The route for the form submission is not set up
The code you have shown us does not include any method_field(...), so it looks like you are doing a normal POST. So you need a corresponding POST route like:
Route::post('/some/path', 'PLAYERController#update');
The route for the failed validation response is not set up
I'm guessing this is the problem. Say you are on pageX, and you landed here via a POST. You have a post route set up, so that you can land on this page OK. Now from this page, you submit the form you have shown us, but validation fails. When that happens, Laravel does a GET redirect back to pageX. But you have no GET route set up for pageX, so you'll get a Method not allowed.
Along with your POST route for the current page, you need a GET route to handle failed validations.
Also, you say Tried mentioning PUT, PATCH and DELETE inside csrf field - as others pointed out, you should use method_field() to spoof form methods, eg:
<form ...>
{{ csrf_field() }}
{{ method_field('PATCH') }}
Laravel form method spoofing docs
UPDATE
Based on your comments, I think it is actually your initial POST that is failing. Checking your code again, I think your action() syntax is incorrect.
According to the docs, if the method specified in the action() helper takes parameters, they must be specified as an array:
action="{{ action('PLAYERController#update', ['reg_no' => $ply->reg_no]) }}"
If your update route using patch method (example Route::patch('.....');) then add this {{ method_field('PATCH') }} below {{csrf_field()}} in your update form
UPDATE
If you are not using PATCH method for the update route, try this :
Route::patch('player/update/{reg_no}', 'PLAYERController#update')->name('plyupdate');
and then in the form you can do like below :
<form method="POST" action="{{route('plyupdate', $ply->reg_no)}}">
{{csrf_field()}}
{{ method_field('PATCH') }}
//Necessary input fields and the submit button here
</form>
This way always works fine for me. If it still didn't work, maybe there's something wrong in your update method in the controller
UPDATE
Untested, in your update method try this :
public function update(Request $request, $reg_no) {
$input = $request->all();
$ply = Player::find($reg_no);
$validate = Validator::make($input, [
'sold_amount' => 'required|check_sold_amount',
'sold_to_team'=>'required'
]);
if ($validate->fails()) {
return back()->withErrors($validate)->withInput();
}
$ply->sold_amount = $request->get('sold_amount');
$ply->sold_to_team = $request->get('sold_to_team');
$team_name=$ply->sold_to_team;
$team=Team::find($team_name);
if($ply->category=='indian') {
$team->indian_players=$team->indian_players+1;
}
else {
$team->foreign_players=$team->foreign_players+1;
}
$team->balance=$team->balance-$ply->sold_amount;
$ply->save();
$team->save();
return view('player.index');
}
Don't to forget to add use Validator; namespace
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
........................
Did you reference a validation request controller?
Hope this helps :)
I want to make a cancel button on a simple CRUD edit form. However it seems that when there are validation errors the cancel button does not work.
I guess because it routes from controller#edit to controller#update the button just goes to controller#edit again instead of the actual previous page. Is this normal or did I do something wrong? How do I make it work?
attendee/edit.blade.php
<div class=pull-right>
{{Form::submit('Update',array('class'=>'btn btn-success'))}}
<a href = "{{URL::previous()}}" class = 'btn btn-warning'>Cancel</a>
</div>
{{ Form::close() }}
routes.php
Route::get('user/attendees', 'UserController#getAttendees');
Route::resource('attendee', 'AttendeeController');
attendee controller
public function edit($id)
{
$user = Auth::user();
if(empty($user->id))
return Redirect::to('/');
//return if attendee doesn't belong to user
if( !($user->attendee->contains($id)) )
return Redirect::to('user/index')->with( 'error', 'attendee id error.' );
$attendee = Attendee::find($id);
return View::make('attendees.edit', compact('attendee'));
}
/**
* Update the specified attendee in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
$attendee = Attendee::findOrFail($id);
$validator = Validator::make($data = Input::all(), Attendee::$rules);
if ($validator->fails())
{
return Redirect::back()->withErrors($validator)->withInput()->with('id', $id);
}
$attendee->update($data);
return Redirect::intended();
}
user controller
public function getAttendees()
{
list($user,$redirect) = $this->user->checkAuthAndRedirect('user');
if($redirect){return $redirect;}
// Show the page
return View::make('site/user/attendees/index', compact('user'));
}
It's actually working correctly, it's just the usage that is incorrect.
Take the following:
You submit a form at GET /attendee/edit/{id}
The form takes you to POST /attendee/edit/{id}
You fail validation and are redirected to GET /attendee/edit/{id}
You cannot link to a page using a method other than GET. Your previous route was actually POST /attendee/edit/{id} but the link will always be GET.
Instead, nominate a page to be redirected to, I usually use the index for the section.
I think you should add a hidden input, like this
{!! Form::hidden('redirect_to', old('redirect_to', URL::previous())) !!}
and use this value in your link:
cancel
Redirect::back() doesn't really accomplish the right thing when using the validator provided by Laravel. What I've done before is pass the page to redirect back to as a hidden input in the form, and simply ignore it using Input::except("return"). Here's what I mean:
// On your HTML Form
<input type="hidden" name="return" value="{{ Request::path() }}" />
// In your PHP Controller
$validator = Validator::make($data = Input::except("return"), Attendee::$rules);
if ($validator->fails())
{
return Redirect::to(Input::get("return"))->withErrors($validator)->withInput()->with('id', $id);
}
Hope that can help shed some light. Other options are returning to a higher up, such as instead of attendee/edit/{id} redirect to attendee/edit/, but it all depends on the structure of you website.
I am now using the browser back via JS in onclick. Seems to work:
<a onclick="window.history.back();">Back</a>
I used this jquery for the cancel button.
$(document).ready(function(){
$('a.back').click(function(){
parent.history.back();
return false;
});
});
May you use the Front-End validation to test the input validation without a need to reload the page. So the {{URL::previous()}} won't affected.
The simple way to do that is by using Ajax or validator.js in your Laravel cade.
Here is a full example how to use jquery ajax in Laravel 5 to test the validation, may help:
http://itsolutionstuff.com/post/laravel-5-ajax-request-validation-exampleexample.html
I have the following code inside my app/start/global.php file:
App::missing(function($exception){
return Response::view('missing', array('url' => Request::url()), 404);
});
And I have a file called missing.blade.php at app/view. However, the above code gives me a FatalErrorException, telling me "Call to a member function getPath() on a non-object". The formatting of the otherwise pretty error page that I got the above information from is also messed up.
But everything works fine when I change my code in global.php to the following:
App::missing(function($exception){
return Response::make("Page not found", 404);
});
I don't get what's going on. How can I display a specific view when a route is not found?
EDIT:
Here is my missing.blade.php file:
#extends('master')
#section('header')
<h2>404 Error</h2>
#stop
#section('content')
<p>
Unable to locate page.
</p>
#stop
EDIT 2:
Also inside my app/views folder, I have a master.blade.php file with the following structure:
...
#yield('header')
...
#yield('content')
...
The following should work for you and gives you more control on other errors as well:
App::error(function(Exception $exception, $code)
{
Log::error($exception);
switch ($code)
{
case 403:
return 'Your 403 message';//or load any custom view
break;
case 404:
return Redirect::to('/');//or load any custom view
break;
case 500:
return 'Your 500 Error Message';//or load any custom view
break;
default:
return Redirect::to('/');//or load any custom view
}
});
I have a problem repopulating my form after validation fails. Problem is my url contains an additional uri which I access by clicking a link. This is what it looks like:
http://www.example.com/admin/trivia/add/5
At first trouble was that the segment 4 of the uri completely disappeared, so even though the validation errors showed and the form was repopulated, I lost my added uri.
Then I found in another question that the solution was to set form open like this:
echo form_open(current_url());
Problem is now it isn't showing any validation errors and the form is not repopulated. Is there a way to achieve this?
This is what my controller looks like:
function add()
{
$data = array('id' => $this->uri->segment(4));
if($_POST)
{
$this->_processForm();
}
$this->load->view('admin/trivia_form', $data);
}
And inside _processForm() I got all the validation rules, error message and redirecting in case success.
[edit] Here is my _processForm() :
function _processForm()
{
$this->load->library('form_validation');
//validation rules go here
//validation error messages
$this->form_validation->set_rules($rules);
$this->form_validation->set_error_delimiters('<div style="color:red">', '</div>');
if ($this->form_validation->run())
{
//get input from form and assign it to array
//save data in DB with model
if($this->madmin->save_trivia($fields))
{
//if save is correct, then redirect
}
else
{
//if not show errors, no redirecting.
}
}//end if validation
}
To keep the same url, you can do all things in a same controller function.
In your controller
function add($id)
{
if($this->input->server('REQUEST_METHOD') === 'POST')// form submitted
{
// do form action code
// redirect if success
}
// do your actual stuff to load. you may get validation error in view file as usual if validation failed
}
to repopulate the form fields you are going to need to reset the field values when submitting it as exampled here and to meke it open the same page you can use redirect() function as bellow:
redirect('trivia/add/5','refresh');
i don't know what you are trying to do, but try this to repopulate the form with the values user entered
<?php
echo form_input('myfield',set_value('myfield'),'placeholder="xyz"');
?>