How to save current URL in session before submit in CakePHP? - php

I have several contact forms through my site. The main one (from the "Contact" section) works through an action in my "Clients" controller, and I have several other forms in other pages (in views from other controllers, where I send the form to the main controller's action and then redirect to the original form), and everything works just fine. The email notifications are being sent and the records are being saved into my database.
The problem came after I implemented a Recaptcha plugin. The plugin works correctly (as in "if you check the recaptcha, it works as intended; if you don't, it displays an error message"), but when I'm using the "secondary" forms, instead of redirecting back to the original starting page, it always redirects me to the page for the main controller's action (and I loose the info at the hidden fields where I'm registering the specific form the client is currently using).
I tried deactivating the redirect, but that doesn't work. The user is still "brought" to the main controller's page.
Then I searched (in google and stack overflow) for some solution, and in a similar question there was the answer "save your current url into a session and load it for the redirection", and it made sense.
However, when I tried saving it I found out the session is being saved after the process starts, so my session is saving the url after it jumps to the main action, instead of before submitting the form.
I tried saving the session in beforeFilter and beforeRender, and it still didn't work.
What can I do to save the url in the session before the form is submitted to the main action?
My main controller's action:
class ClientsController extends AppController
{
public function beforeFilter(\Cake\Event\Event $event)
{
parent::beforeFilter($event);
$route = $this->request->getParam('_matchedRoute');
$session = $this->request->getSession()->write('Origin',$route);
}
public function contact()
{
$cliente = $this->Clients->newEntity();
if ($this->request->is('post')) {
if ($this->Recaptcha->verify()) {
// Verify recaptcha
$client = $this->Clients->patchEntity($client, $this->request->getData());
if ($this->Clients->save($client)) {
$email = new Email();
$email->setProfile('default');
$email->setFrom($client->email)
->to('contact#server.com')
->setSubject('Contact form sent from: ' . $client->source)
->setEmailFormat('both')
->setViewVars([
'source' => $client->source,
'name' => $client->first_name . ' ' . $cliente->last_name,
'company' => $client->company,
'localphone' => $client->local_phone,
'email' => $client->email,
'comments' => $client->comments
])
->viewBuilder()->setTemplate('default','default');
$email->send([$client->comments]);
$this->Flash->success('Youyr message has been sent. We'll contact you soon!');
$this->redirect($this->referer());
} else {
$this->Flash->error('There was a problem with your Contact form. Please, try again!');
}
} else {
// user failed to solve the captcha
$this->Flash->error('Please, check the Google Recaptcha before proceeding.');
$this->redirect($this->request->getSession()->read('Origin'));
}
}
}
}
(The recaptcha plugin is loaded at my AppController's Initialize.)
And as an example, one of the forms in another controller's view where I'm calling the main controller's action:
<?= $this->Form->create('client',['url' => ['controller' => 'clients','action' => 'contact']]); ?>
<?= $this->Form->hidden('source',['value' => 'Product page']) ?>
<?= $this->Form->control('first_name', ['label' => 'First name:','required' => true]) ?>
<?= $this->Form->control('last_name', ['label' => 'Last name:','required' => true]) ?>
<?= $this->Form->control('email', ['label' => 'Email:','required' => true]) ?>
<?= $this->Form->control('local_phone', ['label' => 'Local phone:','maxlength' => 10,'required' => true]) ?>
<?= $this->Form->control('comments', ['label' => 'Comentarios:', 'rows' => 3]) ?>
<?= $this->Recaptcha->display(); ?>
<?= $this->Form->button('Send') ?>
<?= $this->Form->end(); ?>

You could use JavaScript on the frontend to add an event listener to hook the form submit button click.
In your event listener, save the current URL of the window to sessionStorage in the browser.
Then let the submit click event pass to the default action.
This solution will store the URL before it is changed to have the form field contents added to it.
For future visitors, this solution involves use of the following JavasCript concepts which the OP is already across but can be researched seperately:
add event listener
action = 'click'
window.href
sessionStorage
allow default
You could set the object your are listening to (the form submit button) in a number of ways. I usually give it an ID and specify the element using document.getElementById
More info:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
https://www.w3schools.com/JSREF/prop_win_sessionstorage.asp

Related

Yii force login returning to home page always

In my website there is a section to create ad.So i need to force login before creating an ad.
my access control code is like
'access' => [
'class' => AccessControl::className(),
'only' => ['logout','signup','createad','upload','remove'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout','createad','upload','remove','update-leads'],
'allow' => true,
'roles' => ['#'],
],
],
],
This code snippet is forcing the user to login when clicking the create ad button.But after logging in,the user getting redirected to the home page always.I want to redirect to the create ad controller.But my login code looks fine
if($model->login())
return $this->redirect(Yii::$app->request->referrer);
If the user logged in then i need the user to get redirected to the controller where the force login called.How can i do that
The problem is common and it is related to the issue that at the time when you post login, your actual referrer is login page - actionLogin(), so you are redirected back again and off course you get passed throughout the condition that you are not the Guest. In order to handle this, you have to assign a referrer to a modal field, so it can be posted with the login information. So at the time when login is validated, you have the required referrer url in your field. Check if you have this field identified in your form:
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
<?= $form->field($model, 'referer')->hiddenInput()->label(false) ?>
Controller
$form = new LoginForm();
//get previos viewed page url and store in the new model
$form->referer = Yii::$app->request->referrer;
if ($form->load(Yii::$app->request->post())) {
if($form->login()){
return $this->goBack((($form->referer) ? $form->referer : null));
}
}
LoginForm() model
public $referer;
/**
* {#inheritdoc}
*/
public function rules()
{
return [
//...
['referer', 'string'],
];
}
After that, when it will be post request, this field will contain a referrer, which you will pass in your controller.
Let's take a look what is going on:
The user access some /protected-site, (referer: doesn't matter)
The user is redirected to /loginand the form is displayed, (referer: /protected-site)
The user submits the form to /login (referer: /login)
The user is logged in and redirected to referer from step 3.
From this you can see that you can't use the referer value for redirecting user back. To where he was before he was sent to login form. For cases like that there is a goBack() method in yii\web\Controller. You can use it like this:
if ($model->login()) {
return $this->goBack();
}
This method uses yii\web\User::$returnUrl instead of referer. This value is stored in session when the AccessControl filter denies the access and redirects user to login action.

Yii2 Page link to another with the use of button

This is my first time using Yii2 so i am confused on how it works. I have this card page in my views/people/card.php .However i can only access the page through web/people/card. Why?
I am able to link the button in card.php to _card.php (without changing the url) using controller but how do i link my button in _card.php to _data.php?
My controller
public function actionCard()
{
$dataProvider = new ActiveDataProvider([
'query' => People::find(),
]);
$model = '';
if (Yii::$app->request->post() && isset($_POST['card'])) {
if(isset($_POST['selection'])){
$model = People::find()->select('id, name, ic')->where(['id' => $_POST['selection']])->all();
$content = $this->renderPartial('_card',['model'=>$model]);
$selection = implode(',', $_POST['selection']);
}
return $this->render('_design', [
'dataProvider' => $dataProvider,
'model' => $model,
]);
}
First You can only access the page through web/people/card. because this is the route managed by yii (is one of the possibile routing way you can see more in this guide
Second how do you link button in _card.php to _data.php? (in another controller)
also for this you can do using the routing rules above. In this case you should add the controller name to the route(controller/view) eg:
$content = $this->renderPartial('data/_data',['model'=>$model]);
but remember is not a good practice to use view from different controller.

User information in modal before submitting form in Yii

I have a form and after user submits the form and validation goes OK, I want to ask him for his email and nickname in modal window. If user fills and submit an email and nickname, I want to validate it and save it as new record or get id of existing one (in case email was already used in past). If validation is not successful, user should be able to correct values in the same modal. If everything is OK, I want to save the form including create user id.
I already have form saving and user create/find process done. I just do not know, how to put this together, to work in scenario I described above. Could anyone explain, how this should be done in Yii? I am using Yii 1.1.15 and Yii Booster. Thank you.
In Yii the _form.php view file is used both in update.php and create.php views by default.
So, you might need to do smth. similar: insert form with modal in both update.php and create.php views.
Actions and different for these, so you keep logic separate; this is the MVC basic advantage.
public function actionCreate() {
$model = new Users;
if (isset($_POST['Users'])) {
$model->attributes = $_POST['Users'];
if ($model->save()) { // here in the save() method the valadation is included
// ONLY after we validate and successfully saved we go to update action
$this->redirect(array('update', 'id' => $model->id));
}
}
$this->render('create', array(
'model' => $model,
));
}
The main thing is that when you try to save save() method the validation happend automatically.
So if validation is not successful the logic brings back to the same action (create for example) with fields populated in view since model is already having data passed into it: $model->attributes = $_POST['Users'].
If validation is successful we redirect further. Not nessesary ajax form submit, even casual submit fits here.
public function actionUpdate($id) {
$model = $this->loadModel($id);
if (isset($_POST['Users'])) {
$model->attributes = $_POST['Users'];
if ($model->save()) { // after saving EXISTING record we redirect to 'admin' action
$this->redirect(array('admin'));
}
}
$this->render('update', array(
'model' => $model,
));
}
Forms in views(update/create) you keep as originally designed.
Validation for uniqueness is simple in model rules():
array('username, email', 'unique'),
Email valadation for email syntax is seems like this:
array('email', 'email'),

Symfony2 form submitting on page refresh

I have a form in Symfony2 framework. On successful submission of the page it renders another twig template file and returns the values by passing the parameters in an array. But after submission, if I refresh the page, again it is submitting the form and the table entry is created. Here is the code that is executed after submission in the controller,
$this->get('session')->setFlash('info', $this->get('translator')->trans('flash.marca'));
return $this->render('NewBundle:Backend:marca.html.twig', array(
'active' => 1,
'marca' => $marca,
'data' => $dataCamp,
'dataMarca' => $this->getMarcas($admin->getId()),
'admin' => $admin,
));
I want the form to be redirected to the twig files mentioned there with the parameters and the alert message mentioned above. But I don't want the form to be submitted on page refresh.
Thanks
This worked for me:
return $this->redirectToRoute("route_name");
You should save submitted data in session and redirect user. Then you will be able to refresh page as much as you want without additional submission.
Example code - your action algorithm should be similar:
...
/**
* #Route("/add" , name="acme_app_entity_add")
*/
public function addAction()
{
$entity = new Entity();
$form = $this->createForm(new EntityType(), $entity);
$session = $this->get('session');
// Check if data already was submitted and validated
if ($session->has('submittedData')) {
$submittedData = $session->get('submittedData');
// There you can remove saved data from session or not and leave it for addition request like save entity in DB
// $session->remove('submittedData');
// There your second template
return $this->render('AcmeAppBundle:Entity:preview.html.twig', array(
'submittedData' => $submittedData
// other data which you need in this template
));
}
if ($request->isMethod('POST')) {
$form->bindRequest($request);
if ($form->isValid()) {
$this->get('session')->setFlash('success', 'Provided data is valid.');
// Data is valid so save it in session for another request
$session->set('submittedData', $form->getData()); // in this point may be you need serialize saved data, depends of your requirements
// Redirect user to this action again
return $this->redirect($this->generateUrl('acme_app_entity_add'));
} else {
// provide form errors in session storage
$this->get('session')->setFlash('error', $form->getErrorsAsString());
}
}
return $this->render('AcmeAppBundle:Entity:add.html.twig', array(
'form' => $form->createView()
));
}
Redirect to same page is preventing additional data submission. So lean of this example modify your action and you will be fine.
Also instead save data in session you can pass it through redirect request. But I think this approach is more difficult.
Save your data (session/db/wherever you want it saved)
redirect to a new action, retreiving the new data in that action, and rendering the template
this way, refreshing the new action, will only refresh the template, as the saving of your data happened in the previous action
understand ?
so basically replace your
return $this->render....
by
return $this->redirect($this->generateUrl('ROUTE_TO_NEW_ACTION')));
and in this new action, you put your
return $this->render....

Zend framework _redirect url stays the same

I'm trying to redirect with Zend framework but something really strange happens what I just can't understand.
At first you are at token.phtml, the loginform action looks like this:
<?php print $this->url(array('controller' => 'login', 'action' => 'login'));?>"
In the loginAction I'm checking if a user exists or not. When an user is not found I want it to stay at token.phtml so I do this:
$this->_redirect('/login/token');
But the URL changes to the URL like you where logged in also if I do view page source in Firefox it shows the source of the logged on page.
But it does go to token.phtml because it outputs the <div>'s and everything just fine.
change your way: if bad login stay in same page ad show message error and if login right, redirect where you want:
try to change your action controller so:
public function loginAction()
{
$form = new Form_Login();
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getPost())) {
//stuff check login
$loginResult = //call method check, if bad return message error
if (true === $loginResult) {
//login success redirect where you want
$this->_helper->redirector('index', 'index');
} else {
// auth failed
foreach ($loginResult as $field => $message) {
$form->getElement($field)->addError($message);
}
}
}
$this->view->form = $form;
}
try to leave form action empty, so you'll get the request in tokenAction. In tokenAction check if user exist and all that stuff, then if true redirect to login action
$this->_helper->redirector->gotoRoute(
array(
// route like:
'controller' => 'login'
'action' => 'login'
),
'routenameifyouwant'
);
Apparently jquery mobile is causing this problem.
jquery mobile submits its forms via AJAX automatically, if i turn AJAX off the URL changes correctly and so does the source.

Categories