How can I trigger controllerless core Magento modules that watch <controller_action_predispatch> in <frontend> in config.xml from external script - events

For background reference
SEE: Magento: How do I get observers to work in an external script?
I wanted to ask what the preferred method to 'replicate' a frontend controller's action from an external script is. I am creating an external SSO login for Magento EE 1.12.
My code exists as the following in a php file. You can test it by creating test.php and replacing my user (185) with whatever your user ID is. Navigate to the page and then again. You will notice you are logged in and out, however in admin it will not show you as being online. Read on...
<?php
umask(0);
require_once 'app/Mage.php';
Mage::app("default");
// Set the session to frontend according to many suggestions
Mage::getSingleton("core/session", array("name" => "frontend"));
// Alan Storm suggestion to load specific area in Magento (frontend)
Mage::app()->loadArea(Mage_Core_Model_App_Area::AREA_FRONTEND);
// Load My Specific User
$user = Mage::getModel('customer/customer')->load(185)->setWebsiteId(Mage::app()->getStore()->getWebsiteId());
// Get the session object
$session = Mage::getSingleton('customer/session');
// Make it look good for debugging
echo "<PRE>";
// Toggle the customer logged in / logged out upon page load
if ($session->isLoggedIn())
{
try
{
$session->session->setCustomer($user);
echo "LOGGED IN<br>";
var_dump($session->getCustomer()->getIsJustConfirmed());
} catch (Mage_Core_Exception $e) {
$message = $e->getMessage();
var_dump($message);
}
} else {
$session->logout();
}
var_dump($session->getCustomer());
echo $session->isLoggedIn() ? $user->getName().' is online!' : 'not logged in';
?>
This code logs in the user, however none of the Mage_Log, Mage_Persistent, or any other module without a controller that relies on the controller_action_predispatch and controller_action_postdispatch event attached to the frontend area in config.xml will ever fire.
Mage_Log is a perfect example of this situation where it watches customer_login and fires the bindCustomerLogin() function (since I'm using Alan Storm's suggestion above) but the controller dispatch does not fire, resulting in failure of the module to work properly.
How can these other modules ever possibly be triggered from an external script (or a global observer watching the controller_front_init_routers event)?
EDIT: SOLUTION
Here is the final results from the suggestions by benmarks above... I am emulating the Mage_Customer controller. The script below demonstrates how to perform a COMPLETE magento login. It is not extensively tested, but it does show the user as being logged in in the backend. It is the most complete solution i've seen to date.
public function autoMageLogin() {
// Include the controller itself so the object can be used
include ('/var/www/app/code/core/Mage/Customer/controllers/AccountController.php');
// Configure Magento to think its using the frontend
Mage::getSingleton("core/session", array("name" => "frontend"));
Mage::getConfig()->init();
Mage::getConfig()->loadEventObservers('frontend');
Mage::app()->addEventArea('frontend');
Mage::app()->loadArea(Mage_Core_Model_App_Area::AREA_FRONTEND);
// Prepare the request as if it were coming from the specific
// controller (I've chosed Mage_Customer as my chosen controller
// to 'emulate' in php code
$request = Mage::app()->getRequest();
$request->setRouteName('customer');
$request->setControllerModule('Mage_Customer');
$request->setRoutingInfo('');
$request->setModuleName('customer');
$request->setControllerName('account');
$request->setModuleKey('module');
$request->setControllerKey('account');
$request->setActionName('loginPost');
$request->setActionKey('action');
$response = Mage::app()->getResponse();
// Instantiate a new AccountController object using the modified request
// and the modified response (see the include() above)
$accountControl = new Mage_Customer_AccountController($request, $response);
// Dispatch events associated to the controller
Mage::dispatchEvent('controller_action_predispatch', array('controller_action' => $accountControl));
Mage::dispatchEvent('controller_action_predispatch_customer', array('controller_action' => $accountControl));
Mage::dispatchEvent('controller_action_predispatch_customer_account_loginPost', array('controller_action' => $accountControl));
// Load the current user
$user = Mage::getModel('customer/customer')->load(185)->setWebsiteId(Mage::app()->getStore()->getWebsiteId());
// Grab the current session
$session = Mage::getSingleton('customer/session');
// From this point forward, emulate the controller actions
if (!$session->isLoggedIn()){
try{
$session->setCustomerAsLoggedIn($user);
$session->renewSession();
echo "LOGGED IN<br>";
} catch (Mage_Core_Exception $e) {
$message = $e->getMessage();
var_dump($message);
}
} else {
echo "LOGGED OUT<br>";
$session->logout();
}
// Now fire the post controller action events
Mage::dispatchEvent('controller_action_postdispatch_customer_account_loginPost', array('controller_action'=>$accountControl));
Mage::dispatchEvent('controller_action_postdispatch_customer', array('controller_action'=>$accountControl));
Mage::dispatchEvent('controller_action_postdispatch', array('controller_action'=>$accountControl));
// log to the screen and be done
var_dump($session->getCustomer());
echo $session->isLoggedIn() ? $session->getCustomer()->getName().' is online!' : 'not logged in';
die();
}

You will need to manually dispatch the events with the original params e.g.
Mage::dispatchEvent(
'controller_action_predispatch',
array('controller_action',Mage::app()->getRequest()
);
See Mage_Core_Controller_Varien_Action::preDispatch() (link) for more info. Note that the pre- and post-dispatch methods dispatch dynamic events based on routename params which may or may not be a concern.

If you rewrite the external script as a custom controller and action then all the events will fire naturally. However, you must have a reason for making it external in the first place.

Related

Session data not saved in plugin controller October CMS

In October CMS on the next request the session does not contain data previously set.
What I did is:
I am trying to use an action method of a plugin controller in October CMS to put data in the session.
\Session::put('name', 'Test Name');
\Session::keep(['name']);
var_dump(\Session::get('name'));
After that I redirect to a specific page of my application
return \Redirect::to('/created');
In this page a component is loaded which is supposed to display data.
However when I try to access the session data in the back-end of this component
var_dump(\Session::get('name')); echo '<br>';
the session does not contain the data I'd put previously at all.
I already
Checked whether the '/storage/framework/sessions' folder is writable.
Whether the session has started.
Checked whether there are no other requests between the controller action and the next page (component).
Set a longer session lifetime.
Checked whether it is 'the correct' session and it is since it contains data set by middleware.
Also tried to add flash messages with both:
session()->flash("message", "Registered successfully");
or
\Flash::success('Settings successfully saved!');
or
return \Redirect::to('/created')->with('message', 'Registered successfully');
I have my controller class in the following folder structure:
Plugin controller
And the action method looks as following:
public function create(\HttpRequest $request)
{
// When robot
if($request->input("recaptcha") != "success") {
// Sets a successful message
session()->flash("message", "Registered successfully");
session()->flash("status", "Success");
session()->flash("alert-class", "alert-success");
\Session::put('name', 'Test Name');
}
return \Redirect::to('/created');
}
Can anybody help?
I know this response is late, but I had the exact same issue and after many attempts, I found out the issue. You have to group your routes inside web middleware as follows:
Route::group(['middleware' => ['web']], function () {
// your routes here
});

CodeIgniter, set_flashdata not working after redirect

set_flashdata is not working directly after redirect with only one redirect.
I am using one controller in this process - Profilers' Controller. It handles the member confirmation process and also displays the login page on the redirect. The process is as follows:
this session set_flashdata ('topic', 'newmember')
redirect ('login')
route ['login'] = 'profilers/signIn'
topic = $this session flashdata ('topic')
I have turned off all database session configuration for cleaner debugging and even though session library is turned on in configs, I have started calling it anyways which doesn't seem to work either.
Here is my code. As you can see, I am sending path info to a log file path.log:
in controller Profilers, function confirmMember:
public function confirmMember()
{
//use_ssl();
$this->form_validation->set_rules('handle', 'Unique Member Name', 'trim|xss_clean|required|min_length[5]|max_length[30]');
$this->form_validation->set_rules('confirmation', 'Confirmation Code', 'trim|xss_clean|required|min_length[20]|max_length[20]|alpha_numeric');
if ($this->form_validation->run() === FALSE) {echo "here";exit;
$data['handle']=$this->input->post('handle');
$data['confirmation']=$this->input->post('confirmation');
$this->load->view('signing/defaults/header',$data);
$this->load->view('defaults/heading',$data);
$this->load->view('defaults/banner');
$this->load->view('defaults/banner_right');
$this->load->view('member/temp/index',$data);
$this->load->view('defaults/footer',$data);
} else {
$post = $this->input->post(NULL,TRUE);
$data['member'] = $this->Signing_model->model_confirmMember($post);
if ($data['member']['confirmed']!==FALSE) {
/* PATH CHECK */
error_log("member confirmation not false\n",3, LOG_DIR.'path.log');
unset($post);
$this->session->sess_destroy();
$this->session->set_flashdata('topic', 'newmember');
// $this->session->keep_flashdata('topic');
redirect('login','refresh');
} else {
/* PATH CHECK */
error_log("member confirmation IS FALSE\n",3, LOG_DIR.'path.log');
$this->load->view('member/temp/index',$data);
}
My log file shows that the path is using the correct path and showing "member confirmation not false".
I have tried with keep_flash data on (which I assumed wouldn't work since there are no other redirects) and off.
I have also tried redirect without 'refresh'.
In config/routes.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$route['join'] = 'profilers/joinUp';
$route['login'] = 'profilers/signIn';
...
Login page uses Profilers Controller, signIn function as show above:
public function signIn()
{
$topic = $this->session->flashdata('topic');
if (isset($topic)) {
$message = "topic is set. topic = ".$topic."\n";
if ($topic!==FALSE) {
error_log("flash var topic is not false\n", 3, LOG_DIR.'path.log');
} else {
error_log("flash var topic is FALSE\n", 3, LOG_DIR.'path.log');
}
} else {
$message = "topic is NOT set\n";
}
error_log($message,3,LOG_DIR.'path.log');
exit;
...
...
}
log file is showing that topic is set but is false.
"flash var topic is FALSE"
"topic is set. topic = "
Of course topic var not set since it is FALSE.
As you can see, I have moved the get flash data function to the beginning of my controller function to bypass anything that may be corrupting data.
You may need to start the session again after you have destroyed it.
Try adding this after your call to sess_destory():
$this->session->sess_create()
Alternatively you could avoid destroying the session, and unset() the values you wish to get rid of.

Magento - Redirect on Login via Observer

I am trying to redirect specific users in Magento to the products.html page after logging in. Most every way I attempt to do this (setRedirect, header) results in a loop due to too many redirects.
Currently, I am trying to use an observer to setParam('return_url', "$customerRedirectUrl") as described in this rather popular post - Magento - Redirect Customer from Observer Method. The variable $customerRedirectUrl represents logic that together reliably creates the url I know I want the page to be. My relevant code looks like this.
public function redirect(Varien_Event_Observer $observer)
{
$helper = Mage::helper('personal_order');
$isPersonalOrderStore = $helper->isPersonalOrderStore(null);
$session = Mage::getSingleton('customer/session');
if ($isPersonalorderStore){
if(!$session->isLoggedIn()) {
$targetUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB).'customer/account/login';
Mage::app()->getResponse()->setRedirect($targetUrl);
} else {
$baseUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
$storeName = strtolower(Mage::app()->getStore()->getName());
$storeName = str_replace(' ', '', $storeName);
$customerRedirectUrl = "$baseUrl$storeName/products.html";
$observer->getRequest()->setParam('return_url',"$customerRedirectUrl");
}
}
The important part for my purposes now is the else statement, the rest of the function works fine. However, the call to setParam results in the following error:
Fatal error: Call to a member function setParam() on a non-object...
What about the Magento - Redirect Customer from Observer Method post am I not getting (there is a good chance I'm just oblivious to something due to being a fairly new user)? The observer is laid out in the relative config file under controller_action_postdispatch and is in an observer model. What is the context for getting setParam to operate correctly?
Thanks to any and all for your help!
I know this post is a bit old but I see have it worked out for a module of my own.
I run the redirect on 2 different events. When the customer registers or when a customer logs in.
<customer_register_success>
<observers>
<redirectAfterRegister>
<class>businessdirectory/profile_observer</class>
<method>redirectAfterRegister</method>
</redirectAfterRegister>
</observers>
</customer_register_success>
<customer_login>
<observers>
<redirectAfterLogin>
<class>businessdirectory/profile_observer</class>
<method>redirectAfterLogin</method>
</redirectAfterLogin>
</observers>
</customer_login>
I edited this answer because after testing I realized that two separate observers are needed for the two events. The good news is that you do not need to override files or rewrite controllers.
For the customer_register_success event, all you need to do is set the success_url param to whatever you want the url to be.
For the customer_login event, you will notice in your controller customer/account/_loginPostRedirect that the redirect URLs are being set on the customer session. As you can see in the second observer method below, all you need to do is grab the customer session and set the URL. For my purposes, I set the BeforeAuthUrl and AfterAuthUrl.
public function redirectAfterRegister($observer)
{
if(Mage::app()->getRequest()->getParam('listing_id') || Mage::app()->getRequest()->getParam('directory_id')){
$_session = Mage::getSingleton('customer/session');
$action = $_session->getDirectoryAction();
if(Mage::app()->getRequest()->getParam('listing_id')){
$listingId = Mage::app()->getRequest()->getParam('listing_id');
Mage::app()->getRequest()->setParam('success_url',Mage::getUrl($action,array('listing_id'=>$listingId)));
}elseif(Mage::app()->getRequest()->getParam('directory_id')){
$directoryId = Mage::app()->getRequest()->getParam('directory_id');
Mage::app()->getRequest()->setParam('success_url',Mage::getUrl($action,array('directory_id'=>$directoryId)));
}
}
}
public function redirectAfterLogin($observer)
{
if(Mage::app()->getRequest()->getParam('listing_id') || Mage::app()->getRequest()->getParam('directory_id')){
$_session = Mage::getSingleton('customer/session');
$action = $_session->getDirectoryAction();
if(Mage::app()->getRequest()->getParam('listing_id')){
$listingId = Mage::app()->getRequest()->getParam('listing_id');
$url = Mage::getUrl($action,array('listing_id'=>$listingId));
$_session->setBeforeAuthUrl($url);
$_session->setAfterAuthUrl($url);
}elseif(Mage::app()->getRequest()->getParam('directory_id')){
$directoryId = Mage::app()->getRequest()->getParam('directory_id');
$url = Mage::getUrl($action,array('directory_id'=>$directoryId));
$_session->setBeforeAuthUrl($url);
$_session->setAfterAuthUrl($url);
}
}
}
When you have a problem instantiating an object with $observer->getRequest(), try using $observer->getEvent()->getFront()->getResponse() instead. I believe this differs depending on what event the observer is listening to.

Magento losing messages after redirect

I have problem with magento messages. I am building custom module which in theory should be able to restrict access to some parts of the store. I have created an observer which hook into controller_action_predispatch event and checks if current request can be accessed by the user. If the action cannot be accessed the observer redirects user and sets the error info. I want to set the redirect url to the page the customer is coming from in order to avoid clicking through entire shop. I am looking at the HTTP_REFERER and use it if it is set, otherwise I redirect customer to homepage. The problem is that in the later case (homepage redirect) everything works great but when I set url based on the referer I do not see error message in message box.
The code from the observer ($name variable is a string):
Mage::getSingleton('core/session')->addError('Acces to '.$name.' section is denied');
$url = Mage::helper('core/http')->getHttpReferer() ? Mage::helper('core/http')->getHttpReferer() : Mage::getUrl();
Mage::app()->getResponse()->setRedirect($url);
What I found interesting is that if I do any change in the observer file and save it, then the next request which fails and gets redirected to referer url shows the error information but any subsequent loses the messages.
I was thinking that the problem is in the full url and my local instalation (I am using .local domain) but so I tried adding
$url = str_replace(Mage::getBaseUrl(), '/', $url);
but this did not helped.
I also tried redirect using php header() function without any result as well.
All cache is disabled. The workflow which triggers the problem is as follows:
I'm going to any accessible page (for example /customer/account)
Click on cart link (cart for this account is disabled)
Return to /customer/account and the error message is displayed
Click on cart link again
Return to /customer/account but no error message
Any hint on where to look will be appreciated.
//A Success Message
Mage::getSingleton('core/session')->addSuccess("Some success message");
//A Error Message
Mage::getSingleton('core/session')->addError("Some error message");
//A Info Message (See link below)
Mage::getSingleton('core/session')->addNotice("This is just a FYI message...");
//These lines are required to get it to work
session_write_close(); //THIS LINE IS VERY IMPORTANT!
$this->_redirect('module/controller/action');
// or
$url = 'path/to/your/page';
$this->_redirectUrl($url);
This will work in a controller, but if you're trying to redirect after output has already been sent, then you can only do that through javascript:
<script language=”javascript” type=”text/javascript”>
window.location.href=”module/controller/action/getparam1/value1/etc";
</script>
Your messages get lost because you use an unfavorably way for a redirect in controller_action_predispatch. Your solution causes on the one hand the "message lost" and on the other hand, it wastes processing power of your server.
When you take a look at Mage_Core_Controller_Varien_Action::dispatch(), you'll see that your solution doesn't stop the execution of the current action, but it should do that with a redirect. Instead Magento executes the current action to its end, including the rendering of the message you had added before. So no wonder why the message gets lost with the next client request, Magento had it already rendered before, with the server response which includes your redirect.
Further you'll see in Mage_Core_Controller_Varien_Action::dispatch() only one possibility to stop the execution of the current action and skip directly to the redirect, which is in line 428 catch (Mage_Core_Controller_Varien_Exception $e) [...]. So you have to use Mage_Core_Controller_Varien_Exception which is quite unpopular, but the only right solution for your purpose. The only problem is, this class has a bug since it was introduced in Magento 1.3.2. But this can be easily fixed.
Just create your own class which is derived from Mage_Core_Controller_Varien_Exception:
/**
* Controller exception that can fork different actions,
* cause forward or redirect
*/
class Your_Module_Controller_Varien_Exception
extends Mage_Core_Controller_Varien_Exception
{
/**
* Bugfix
*
* #see Mage_Core_Controller_Varien_Exception::prepareRedirect()
*/
public function prepareRedirect($path, $arguments = array())
{
$this->_resultCallback = self::RESULT_REDIRECT;
$this->_resultCallbackParams = array($path, $arguments);
return $this;
}
}
So you can now implement your solution realy clean with that:
/**
* Your observer
*/
class Your_Module_Model_Observer
{
/**
* Called before frontend action dispatch
* (controller_action_predispatch)
*
* #param Varien_Event_Observer $observer
*/
public function onFrontendActionDispatch($observer)
{
// [...]
/* #var $action Mage_Core_Model_Session */
$session = Mage::getSingleton('core/session');
/* #var $helper Mage_Core_Helper_Http */
$helper = Mage::helper('core/http');
// puts your message in the session
$session->addError('Your message');
// prepares the redirect url
$params = array();
$params['_direct'] = $helper->getHttpReferer()
? $helper->getHttpReferer() : Mage::getHomeUrl();
// force the redirect
$exception = new Your_Module_Controller_Varien_Exception();
$exception->prepareRedirect('', $params);
throw $exception;
}
}
this will work , so try it:
$url = 'path/to/your/page';
$this->_redirectUrl($url);
return false;
This means you are not allowing again to execute anything else.

Anyway to redirect to previous URL after registration in Joomla?

I am developing a component that required login at some level, then if user is not logged in, I placed a login link, that take user to login page with following in query string.
return=<?php echo base64_encode($_SERVER['REQUEST_URI']);?>
After login, it comes back to that page, but is there some way to tackle this if user is not registered and user starts registering? Is there some way to do this without changing some thing in Joomla it self? like by just setting some thing in cookie e.t.c. Or I will need to change some thing in Joomla Registration component or module. Or is there some plugin for that?
Any response will be appreciated, please tell what ever way you know so that it may give me some better clue.
In your component you could try to store the referrer in the Joomla! session - I don't believe the session changes or is replaced during login. I haven't had time to try this but it should work.
To Save:
$session = JFactory::getSession();
$session->set('theReferrer', $_SERVER['HTTP_REFERER'], 'mycomponentname');
To Retrieve:
$session = JFactory::getSession();
$redirectTo = $session->get('theReferrer', '', 'mycomponentname');
Then you can just use a setRedirect before you return.
$this->setRedirect($redirectTo);
You can achieve this with a plugin (at least in Joomla 3.x - not sure how far back this will work off-hand). Key here is the onUserAfterSave event, which tells you whether the user is new or existing.
I wrote the code below some time ago, so can't recall the exact reason the redirect could not be done from within the onUserAfterSave event handler, but I think the redirect is subsequently overridden elsewhere in the core Joomla user management code if you try to do it from there, hence saving a flag in the session and checking it in a later event handler.
class PlgUserSignupRedirect extends JPlugin
{
public function onUserAfterSave($user, $isnew, $success, $msg)
{
$app = JFactory::getApplication();
// If the user isn't new we don't act
if (!$isnew) {
return false;
}
$session = JFactory::getSession();
$session->set('signupRedirect', 1);
return true;
}
function onAfterRender() {
$session = JFactory::getSession();
if ($session->get('signupRedirect')) {
JFactory::getApplication()->redirect($_SERVER['HTTP_REFERER']);
$session->clear('signupRedirect');
}
}
}

Resources