I have a strange behavior with ZF that I can't resolve. I have a layout.phtml and a login.phtml. So when the user is logged in the layout.phtml should be displayed else the login.phtml. This also works, but before displaying the login.phtml, ZF go through layout.phtml and I can confirm this due to errors in the error.log file.
Here what I have in the bootstrap:
public static function _initAcl()
{
$auth = Zend_Auth::getInstance();
$acl = new BM_Acl($auth);
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(
new BM_Controller_Plugin_Acl($auth, $acl)
);
}
Here what I have in the auth controller:
public function indexAction() {
$form = new BM_Form_Login();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
if ($this->_process($form->getValues())) {
// We're authenticated! Redirect to the home page
//json validation on login page
$var = json_encode(array('valid' => true, 'redirect' => 'index'));
echo $var;
exit();
} else {
$var = json_encode(array('valid' => FALSE, 'error' => 'Authentication failed!', 'redirect' => 'auth'));
echo $var;
exit();
}
}
}// end if is POST
$this->_helper->layout()->setLayout('login'); // special login page
$this->view->form = $form;
}
Any help will be appreciated...
Regards
Andrea
P.S. This only happens when I start the application from a new browser window. If I refersh the login page, the layout is not called anymore...
Views are for single pages. If you have a singular page you wish to display with a template like layout.phtml, you would edit the index.phtml inside the index action's views directory. If you want to disable the main layout
$this->_helper->layout()->disableLayout();
Or use a blank layout
$this->_helper->layout()->setLayout('blank');
Any code specific to a singular page should be done with a view.
Iam not sure, but the i think the layout is redered before the view scripts. You could try to put you logic inside the preDispatch Hook in your Controller.
public function preDispatch() {
$form = new BM_Form_Login();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
if ($this->_process($form->getValues())) {
// We're authenticated! Redirect to the home page
//json validation on login page
$var = json_encode(array('valid' => true, 'redirect' => 'index'));
echo $var;
exit();
} else {
$var = json_encode(array('valid' => FALSE, 'error' => 'Authentication failed!', 'redirect' => 'auth'));
echo $var;
exit();
}
}
}// end if is POST
$this->_helper->layout()->setLayout('login'); // special login page
$this->view->form = $form;
}
Or use an ControllerPlugin:
Zend Controller Plugin - Doc
When I understand right, you have a layout that you use on all pages, except for login. Instead of using the view for login as a layout, you should disable layout for this action and just render the login.phtml normally. You can do this by calling the following in your controller's loginAction, instead of setLayout('login'):
$this->_helper->layout()->disableLayout();
This will just disable the layout, but the view is rendered normally.
If you want to do it your way, you have to place the login.phtml into the layout-path, not in the view-path (if you want a more detailed explanation, just ask in a comment).
Related
I have used 'use-ajax' class to render login form in a modal. I want to handle validation errors on same modal without closing it. On successful login it is redirecting correctly, but when an error occurs it closes modal and redirecting to login page i.e user/login and displaying errors on that page. I tried to use ajax callback to display error on modal itself by altering the form which is working. But, it is giving me drupal ajax error. Here is my code :
$form['#prefix'] = '<div id="modal-form">';
$form['#suffix'] = '</div>';
$form['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -10,
];
$form['actions']['submit']['#ajax'] = array(
'callback' => 'setMessage',
'wrapper' => 'modal-form',
);
=========================================================================
function setMessage(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
$response = new AjaxResponse();
if ($form_state->hasAnyErrors()) {
$response->addCommand(new ReplaceCommand('#modal-form', $form));
}
else {
$command = new CloseModalDialogCommand('#modal-form', FALSE);
$response->addCommand($command);
}
return $response;
}
The above code giving me session id also but due to drupal ajax error it does not redirect on success by closing modal.
If I go with non-ajax ie. if I remove the ajax callback function it works on success but errors are not displaying on modal.
First, check if you have added redirection related changes using hook_login in your module file. You can remove that redirection related changes and handle redirection in your callback function.
function setMessage(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
$response = new AjaxResponse();
$current= \Drupal::currentUser();
if ($form_state->hasAnyErrors()) {
$response->addCommand(new ReplaceCommand('#modal-form', $form));
}
else if (!$current->id()) {
$response->addCommand(new ReplaceCommand('#modal-form', $form));
}
else {
$command = new RedirectCommand(' ');
return $response->addCommand($command);
}
return $response;
}
On success it will close the modal and will redirect correctly. If you found any error or if you are not logged in it will stay on modal form.
My zendframwork 2 application contains a navigation in my application/module.php , this navigation contains many items from which some of them are ( login - logout - register )
I don't need to show the three all the time In the navigation menu.. when the user is n't logged in I must show him : login- register , after he logs-in, I must show him only logout link
How can I do that?
Removing pages
Module.php
public function onBootstrap(MvcEvent $e)
{
$application = $e->getApplication();
$serviceManager = $application->getServiceManager();
if (user not login) {
$container = $serviceManager ->get('navigation');
$logoutPage = $container->findBy('route' , 'logout');
$container->removePage($logoutPage);
}
}
<?php if (isset($_SESSION["login"]) { ?>
Logout
<?php } else { ?>
Login
Register
<?php } ?>
or something similar to this might work. Replace the "login" key with whatever yours is.
Session is not destroying after clicking the logout link on home page. Here is my code
public function login()
{
$config['appId'] = '405802852809513';
$appid=$config['appId'];
$config['secret'] = 'b873cf1c00e9e1554cb0eede34d252d5';
$secret=$config['secret'];
$this->load->library('facebook', $config);
$user = $this->facebook->getUser();
if ($user) {
try {
$user_profile = $this->facebook->api('/me'); print_r($user_profile);
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
if ($user) {
echo"<br>";
echo $data['logoutUrl']=$this->facebook->getLogouturl(array("next"=>site_url('/user/logout')));
} else {
$scope = array(
'scope' => 'email,offline_access,publish_stream,user_birthday,user_location,user_work_history,user_about_me,user_hometown'
);
$data['loginUrl'] = $this->facebook->getLoginUrl($scope);
}
if ($user) {
$logoutUrl=$data['logoutUrl'] ;
$user_info = array(
'name' => $user_profile["name"],
'app_id'=>$appid,
'secret'=>$secret,
'id' =>$user_profile["id"],
'logoutUrl'=> $logoutUrl,
);
$this->load->library('session');
$this->session->set_userdata($user_info);
redirect('user/home') ;
} else {
$this->load->view('frm_login',$data);
}
}
After filling email and passoward user will be redirect to home page and home method will be called
public function home(){
$this->load->library('session');
$user_info=$this->session->all_userdata();
if(isset($user_info['name'])){
$data['name']=$user_info['name'];
if(isset($user_info['logoutUrl']))$data['logoutUrl']=$user_info['logoutUrl'];
$this->load->view("home",$data);
}
else{
redirect("user/login");
}
}
And here is the view for my home page
<html>
<body>
Welcome <?php echo $name;?>
<?php
if(isset($logoutUrl))
{?>
Fb_Logout
<?php }
else
{?>
Logout
<?php
}
?>
</body>
</html>
And here is my logout for destroying the session but the prob is that session is not destroying. I tried everything to destroythe session but still it exists.
And if I call user/loggin in the url then it show my directly the home page with my facebook name displayed on it.If the session is successfully destroyed then it must show the login screen of facebook, but it is not showing that. Please help me out got stucked in this for almost 2 days. Your replies are totally welcome.
public function logout(){
$this->load->library('session');
$this->load->library('facebook', $config);
$this->session->unset_userdata($user_info);
$this->facebook->destroysession();
$this->session->sess_destroy();
redirect("user/login");
}
I do not know in which class do you have your logout method. It is a class right? (otherwise it would be strange to see the usage of $this inside). Do you have a session object in that class? What class does your session object have in your class? Is the class of your session object having a sess_destroy method? If so, is it public? If so, what does it contain? Also, where do you call your logout() method? Is it even executed?
These should have been the questions you should have asked yourself.
This is a reference about how to destroy the session in php.
In my Zend Framework 2 application I am using the zfcUserLoginWidget, a View Helper provided by ZfcUser. This View Helper is meant to embed the login form on another page.
<?php echo $this->zfcUserLoginWidget(); ?>
I use this View Helper in my index.phtml which is controlled by my IndexController. Pressing the "Login" button calls the loginAction function of the UserController. If the entered login data are invalid, the UserController redirects by default to the login page:
class UserController extends AbstractActionController
{
const ROUTE_LOGIN = 'zfcuser/login'; // Leads to 'user/login'
public function loginAction()
{
// ...
if (!$form->isValid()) {
$this->flashMessenger()->setNamespace('zfcuser-login-form')->addMessage($this->failedLoginMessage);
return $this->redirect()->toUrl($this->url()->fromRoute(static::ROUTE_LOGIN).($redirect ? '?redirect='. rawurlencode($redirect) : ''));
}
// ...
}
}
The login.phtml displays by default an error message if the entered login data has been invalid:
<?php echo $this->formElementErrors($form->get('identity')) ?>
In my application I have changed the redirection route back to the index.phtml (to the LoginWidget) controlled by the IndexController instead of the login.phtml controlled by the UserController:
const ROUTE_LOGIN = 'home'; // Leads to 'index/index'
Changing this redirection route causes the loss of error messages: The previously mentioned formElementErrors function is still called, but there are no messages available anymore.
Question:
How can I inform the LoginWidget about the fact that there has been entered invalid login data and that the page has not only been simply reloaded?
I'd like to colorize the input fields red if that is the case...
having the same problem i solved it using use Zend\Session\Container, generating my own message.
Modified:
ZendSkeletonApplication\vendor\zf-commons\zfc-user\src\ZfcUser\Controller\UserController.php
Add
use Zend\Session\Container;
const ROUTE_LOGIN = 'home';
in loginAction of UserController.php added/changed
//open session
$session = new Container('loginmsg');
if (!$form->isValid()) {
//$this->flashMessenger()->setNamespace('zfcuser-login-form')->addMessage($this->failedLoginMessage);
//$this->flashMessenger()->addMessage('not working');
//return $this->redirect()->toUrl($this->url()->fromRoute(static::ROUTE_LOGIN).($redirect ? '?redirect='.$redirect : ''));
$session->loginmsg = 'Username and password do not match.'; //store loginmsg
return $this->redirect()->toRoute('home');
} else {
$session->loginmsg = "";
}
Also modify the authenticateAction
if (!$auth->isValid()) {
$this->flashMessenger()->setNamespace('zfcuser-login-form')->addMessage($this->failedLoginMessage);
$adapter->resetAdapters();
//open session
$session = new Container('loginmsg');
$session->loginmsg = 'Username and password do not match.'; //store loginmsg
return $this->redirect()->toUrl($this->url()->fromRoute(static::ROUTE_LOGIN)
. ($redirect ? '?redirect='.$redirect : ''));
}
In the home Route (indexAction):
$session = new Container('loginmsg');
$loginmsg = strip_tags($session->loginmsg);
$session->getManager()->getStorage()->clear('loginmsg');
$this->layout('layout/index');
return new ViewModel(array(
'loginmsg' => $loginmsg,
));
In the View of the Index
<?php if(!(empty($loginmsg))):?>
<div class="alert alert-danger" role="alert"><?php echo $loginmsg;?></div>
<?php endif; ?>
Worked for me (at first), msg me for further information.
Kind regards,
David
I have a form for the creation of new "groups". I now added a small "go back" image with which the user should be able to go back one step. I don't know why, but when I click this new image, the controller and action used for the form which I want to leave (/admin/creategroup) is called again with HTTP POST set. Therefore, the form validation is done, and I'm stuck at this form with the validation errors displayed.
This is a snippet of the code from my form with both image-buttons. I wan't the "go back"-image to redirect me to the specified controller without validating the form:
$this->addElement('image', 'btnBack', array (
'name' => 'btnBack',
'id' => 'btnBack',
'label' => '',
'title' => 'Go back',
'alt' => 'Go back',
'src' => '/img/undo.png',
'onClick' => "window.location='/admin/groupoverview'"
));
$this->addElement('image', 'btnSave', array (
'name' => 'btnSave',
'id' => 'btnSave',
'label' => '',
'title' => 'Save this new group',
'alt' => 'Save this new group',
'src' => '/img/save.png',
'onClick' => "document.forms[0].submit();"
));
Edit:
I already thought of the possibility to check in /admin/creategroup whether it was called from the 'btnBack'-image or the 'btnSave'-image and skip form validation and redirect correctly if the source was the 'btnBack'-image.
I just think that there should be a nicer solution to directly redirect from the form and circumvent calling /admin/creategroup again.
Edit2:
My view script:
<div id="createGroupMask">
<br/>
Use the form below to create a new group
<?php
$this->form->setAction($this->url());
echo $this->form;
?>
</div>
My action in the controller:
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// Data for new group is valid
...
} else {
// Form data was invalid
// => This is where I land when pressing the 'back' image
// No further code here
}
}
$this->view->form = $form;
}
Now there is something to work with:
The isValid() loop is incorrect, your form will never evaluate as inValid with respect to the elements you've presented, you will never get to the else.
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// Data for new group is valid
...
} else {
/* This is incorrect */
// Form data was invalid
// => This is where I land when pressing the 'back' image
// No further code here
}
}
$this->view->form = $form;
}
My problem is that I'm not sure what is going to be submitted from your form, I'm not really familiar with how your using "onClick" and what I presume is javascript. It looks like element btnBack should redirect on click and element btnSave should POST. However this does not seem to be happening.
I have done this type of thing in PHP and ZF with submit buttons, perhaps the flow of what I did will help:
NOTE: for this type of flow to work you must give the button element a label. The label is used as the submit value.
//psuedoCode
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
//I would probably opt to perform this task with a switch loop
if ($form->getValue('btnBack') === some true value) {
$this->_redirect('new url');
}
if ($form->getValue('btnSave') === some true value) {
//Process and save data
}
} else {
//Display form errors
}
$this->view->form = $form;
}
I think when all is said and done the crux of your problem is that you did not give your button elements a label.
I tried adding labels to my images, but this didn't work.
I also tried to use the isChecked() method on my btnBack-image like this:
if ($form->btnBack->isChecked()) {
// 'Go back' image was clicked so this is no real error, just redirect
}
This didn't work either.
I finally was able to check which image was clicked via the following method as answered in Zend form: image as submit button:
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// Data for new group is valid
...
} else {
// Form data was invalid
if (isset($this->_request->btnBack_x)) {
// 'Go back' image was pressed, so this is no error
// -> redirect to group overview page
$this->_redirect('/admin/groupoverview');
}
}
}
$this->view->form = $form;
}
I guess this doesn't thoroughly answer the original question as the validation is still done and I'm only checking for this 'special case' where the 'Go back' image was clicked, but I'll mark it as answered anyways.
Tim Fountain suggested an even cleaner approach in my somewhat related question:
Zend forms: How to surround an image-element with a hyperlink?