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?
Related
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.
I'm having problem on my view not seeing any $Message variable, which is working on my login controller.
public function index()
{
$data = somedataFromModel::find(1);
return View::make('SomeView',compact(['sampleData' => $data]);
}
public function postOrStoreData(CustomFormRequest $request)
{
/* where update or insert or store occurs */
//after all my updating codes or inserting codes
return back()->with('Message','test');
}
with these codes I am not able to run my view correctly, it does not see $Message
it has the same implementation as my login controller and views.
right now my view needs to be authenticated to be used, so it is under the Middleware Group of 'auth', I also see the MiddleWareGroups, web and api. help me I'm lost.
My only objective is after I post any data, without using AJAX, just standard Form Action and Submit Method, I will display an alertClass with bootstrap.
redirect()->with() stores it in the session.
Per the docs, you thus access it via session('Message') in the view, not $Message.
The syntax may appear similar to view()->with(), but the functionality is not identical.
This is a basic issue, when submitting and performing a post, you normally want to avoid giving the user the chance to re-iterate the submit by refreshing or going back and forth with browser history.
(Backend re-submit, controls and checking is not questioned here. Of course they should be in place for security)
My solution was to have in Laravel web routes defined a post and a get route.
Like:
Route::post('/action', 'ActionController#doAction')->name('do.action');
Route::get('/action', 'ActionController#doActionConfirm')->name('do.action.confirm');
In ActionController something like:
public function doAction(Request $request)
{
....
return redirect()->route('do.action.confirm', [ 'data' =>
base64_encode(json_encode([
'action_id'=> $action_id,
'sent_to'=> $email,
'sent_success'=> $sent_success,
'sent_errors'=> $sent_errors,
]))]);
}
....
public function doActionConfirm(Request $request)
{
return view('confirmation')->with('data',$request->input('data'));
}
Then in my confirmation.blade.php get that $data decoded and displayed.
Is this the correct way to do it with Laravel?
What I don't like here:
is there's a better and more elegant way to forward data from the redirect()
is there a better way to manage get parameters to the GET route just to avoid people understanding and trying to inject unwanted data to the confirmation blade? (even if they will obtain nothing but no-sense views..because the page is doing nothing, it's simply displaying data in HTML blade)
Where to clean up/ validate/ verify the user input data? In the controller or the model?
In controller.
Look at it this way: Your form will post to a controller function with the form data in $_POST variable. You validate the data in that function of the controller and do some DB inserts or updates. Then you show the success message as a view or in case of error a fail message.
See the form validation tutorial in CodeIgniter's user guide here.
I'd go with the model so your validation can be reused. Models should handle the data and the controller should direct it to where it needs to go.
The code that make the validation must be in the model, but the call to this code must be in the controller.
Something like this:
class MyAwesomeUserModel {
public function isValid()
{
//some code to validate the user
}
}
class MyUserController {
public function myUserAction()
{
//some code to insert the input of the user in the model
if($userModel->isValid()){
//do nice things with the data and send some message/data to the view
} else {
//send 'nice' error messages to the view
}
}
}
This is just the way I use, may not be the best way, but it's the best fit in my application. And that's what matters, you should look for what best suits your application.
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".