Removing custom error from MessageBag Laravel - laravel

I am trying to display a custom error message when the user who is trying to log in isn't registered in my website. I have this code for that.
if (!(User::where('nickname',$request->input('nickname'))->exists())) {
// adding a custom error if user with such nickname doesn't exist
$errors = new MessageBag;
$errors->add('noExist', 'User with such nickname doesnt exist');
return view('login')->withErrors($errors)->with('title','Login');
}
The error prints, but i want to remove it from my MessageBag, so it won't be displayed after a refresh. How can I achieve this?

If you return a view() in a POST method, like the Controller function handling a login attempt, any subsequent refreshes will simply re-submit the form. For this reason, the ErrorBag won't refresh as you'd expect (return to default state). To get around this, use a proper redirect() to handle re-rendering the view():
// return view('login')->withErrors($errors)->with('title','Login');
return redirect("/login")->withErrors($errors);
$errors will be passed from the POST request back to the GET request handling the display of the login view, and on refresh, will be cleared.

Related

refresh page after updated model - Laravel

I want to refresh current page after any user update
I'm trying to do something like that in User Model :
public static function boot()
{
self::updated(function ($model) {
return back(); //or redirect(Request::url())
});
}
but it wasn't working.
How can I refresh the page if any user updated
In general, the model event functions creating/created/updating/updating/saved/saving should only ever return false or nothing (void). Returning false in for instance updating (that is: before the model is persisted in the database) cancels the model update (this works for all propagating events, see https://laravel.com/docs/9.x/events#stopping-the-propagation-of-an-event).
To "refresh" the current page after a user update, you have to be more specific about what you require. The back() function that you use (or the aliases redirect()->back() or even app('redirect')->back()) is (to my knowledge) to be used in controllers and it uses the Referer header or a property in the user's session to determine to which page to send the client to. This is most often used with validation errors, so that you can send the user back to the page they came from along with any possible validation error messages.
Using back() (or any other request completions like return response()->json('mydata')) inside events is wrong and it doesn't even work since the result of such events is not being used to complete the request. The only valid thing you "could" do is to try validation inside an event, which in turn could throw ValidationExceptions and is therefore automatically handled.
What you should do is use the controller method that actually handles the request that updates the user:
// UserController.php
/** (PUT) Update a user */
public function update(Request $request, User $user)
{
if($user->update($this->validate($request, [/* validations */])) {
return redirect()->back();
// or even be explicit and use `return redirect()->route('users.show', $user);`
}
// `update()` returned false, meaning one of the model events returned `false`
// (there is no exception thrown here).
session()->flash('alert-info', 'Something went wrong');
return redirect()->back();
}

Changing back the url to original if exception thrown and return back to form

I have a thymeleaf signup form, which if we submit then a controller at "/signup_do" is called which validates and saves the user to database:
<form action="/signup_do" method="post">
...
</form>
The controller at "/signup_do" passes the request to the accountRegistration service method, which does the validation:
#PostMapping("/signup_do")
public String register(Account account, HttpSession session) {
session.setAttribute("accountToRegister", account);
accountManagement.accountRegistration(account);
return "Success";
}
The account registration method can throw an exception SignupFormException, which is handled by the #ExceptionHandler defined in that controller class:
#ExceptionHandler(value=SignupFormException.class)
public String handle(HttpSession session, Model response) {
Account returnDataToForm = (Account) session.getAttribute("accountToRegister");
response.addAttribute("name", returnDataToForm.getFirstName());
session.invalidate();
return "signup";
}
Now the problem is that when exception occurs, the inputs entered in the form is passed back to the signup form, and the entered data remains intact, but the url still remains as /signup_do.
I have tried using return "redirect:/signup" instead, which does change the url, but it ends up making a get request to the /signup url like
/signup?name=John...
but my /signup controller is not designed to handle a get request, it just knows to display the form, so the information is lost.
#GetMapping("/signup")
public String signupPage() {return "signup";}
I also tried using forward:/signup, but that just ended up throwing 405 error.
I figured out a clean workaround a few hours after asking this question.
What I did is change the name of the controller that handles the signup process to ("/signup") as well. Since the controller that displays the page is a #GetMapping("/signup") and the one that handles the signup process is a #PostMapping("/signup") there is no clash.
Now even if the controller changes, the url remains the same, since both of them are signup...
#GetMapping("/signup")
public String signupPage() {return "signup";}
#PostMapping("/signup")
public String register(Account account, HttpSession session) {
session.setAttribute("accountToRegister", account);
accountManagement.accountRegistration(account);
return "success";
}
And this works just like I wanted!!
Redirecting will make a get request to the controller looking for the view to display, which in your situation means losing your data for the reasons you give. I can think of two workarounds:
Don't do the redirect and change the URL manually with javascript everytime you enter this view. If you dislike having a "wrong" URL in a view, editing it manually looks the most reasonable and direct approach. You can see how to do this here, including it in a script that executes everytime the page loads/the submit button is pressed.
Do the redirect and avoid losing your info by storing it in the session for a while longer, accessing it in thymeleaf in this way, instead of getting it from a model attribute. This would mean you would have to be careful to remove this session attributes later. It's also not very "clean" that your get request for the form view includes the user info, so I wouldn't go with this solution if avoidable.

How to forward argument for redirect::route->with when hitting an auth filter using Laravel?

I have the following problem:
After a user is created and the user has confirmed her email.
I would like the user to login,
I use the following code to do that:
Redirect::route('login-forward')->with('alert_message', ...)
the alert messages simply states that everything went well, and I would like her to login.
login-forward is protected with an before filter, that runs the actual login form,
When the user then logs in sucesfully, she is brought back to login-forward, whic then puts the user at her personal landing page.
the code for the route 'login-forward is:
Route::get('my-login', array(
'as' => 'login-forward',
'before' => 'auth',
function ()
{
$user = Auth::user();
switch ($user->role)
{
case 'Administrator':
return Redirect::route('admin_dashboard');
case 'FreeUser':
return Redirect::route('cs-dashboard');
default:
return Redirect::route('/');
}}));
the problem is, the ->with('alert_message',...) is not seen by the real login route called by the before filter.
How do I solve this?
The best approach is to let the user logs in automatically when the email is confirmed, if the user confirms the account creation then when you find that user is valid then you may log in that user using something like:
// $user = Get the user object
Auth::login($user);
Also you may use:
Session::put('alert_message', ...);
Redirect::route('login-forward');
Then when the user logs in for the first time, just get the message from Session using:
// Get and show the alert_message
// from session and forget it
#if (Session::has('alert_message'))
{{ Session::pull('alert_message') }}
#endif
So, when you pull the message from the Session to show it, the message will no longer be available in the Session or you may use Session::reflash() to flash the flashed session data for another subsequent request until you get in the page where you want to show the message.
The best choice is - you can make forward to login form without redirect from method of controller for url of personal page.
return Route::dispatch(Request::create('login'))->getOriginalContent();

Applying form errors manually

I have a situation where I'm editing a snippet of data within a larger context. The user submits this data to a specialized action for handling and redirects back to the parent page. Because it's a redirection, validation errors aren't getting automagically set, so I'm trying to work around that.
In the event of an error, I'm writing a validation_errors key to the session with a value of $model->validationErrors. In the form, though, I'd like to tell Cake to set each error so I can leverage my existing styles and not have to make a lot of changes to my $this->Form->input() methods.
Is something like this possible? Essentially, I'm looking to manually achieve the same result you'd get if a regular form was submitted and allowed to drop through with validation errors. I was hoping I could loop over each validation error and set the field error, but that's not making any change at all.
Thanks.
This can be achieved in the controller by
$this->Model->invalidate('fieldName', __('ErrorMessage', true));
If the values are available, you can also call
$this->Model->validates();
to validate all values with the validators defined in the model.
Save the data to the session and revalidate it.
function childAction() {
if(isset($this->data)) {
$this->Session->delete('invalid_data');
if($this->Test->save($this->data)) {
// ...
} else {
$this->Session->write('invalid_data', $this->data);
}
$this->redirect(array('action'=>'parentAction'));
}
}
function parentAction() {
if($this->Session->check('invalid_data')) {
// This will cause $this->Test->validationErrors to be populated
// Assuming your parent page has the form set up properly, the
// errors will be automagically filled. ie: $form->input('Test.field1')
$this->Test->set($this->Session->read('invalid_data'));
$this->Test->validates();
}
}
If you want to do the same with CakePHP 3, use the method "errors".

CakePHP validation error messages - how to pass them around?

Please note: I'm not trying to do this anymore, because I found an alternative, but it may be useful in the future to know the answer.
I have a form that is in a view (index.ctp) associated with the index() action on a controller. That form should post data to another action, contact(), in the same controller. This second action doesn't have a view, it's just to process the information and redirect the user according to the outcome. This action is doing the validation and redirecting the user to the referer (index in this case) in case of an error, and then the error should be displayed in index. Note that the model doesn't use a database table, but it's used only to define validation rules.
The validation is taking place correctly and reporting the expected errors. In order to retrieve the errors after the redirect, it writes the $this->ModelName->invalidFields() array to a session variable that is retrieved on the index() action after the redirection.
This array is passed on to the $errors variable to the view. Now comes the problem. The errors, although being passed correctly between redirects, aren't getting attached to the respective forms. How can I accomplish this? The form has all the conventional names, so it should be automatic, but it isn't.
Here's part of the relevant code:
Index view:
echo $this->Form->create('Contact', array('url' => '/contacts/contact'));
echo (rest of form) ...
echo $this->Form->end(__('send message', true));
Contacts controller:
function index() {
if ($this->Session->check('Contact.errors')) {
$this->set('errors', $this->Session->read('Contact.errors'));
}
}
function contact() {
if (!empty($this->data)) {
$this->Contact->set($this->data);
if ($this->Contact->validates()) {
(send the email)
}
else {
$this->Session->write('Contact.errors', $this->Contact->invalidFields());
$this->redirect($this->referer);
}
}
}
I don't think it's a good idea to write the validation errors in a session variable. I'm no CakePHP expert, but I don't think that's the way you are supposed to do it. All your forms should point to the same url you are on, so the data that the user has entered will not be lost.
Could you add some code to your question?

Resources