How can I trigger controllerless core Magento modu

2020-07-27 03:43发布

问题:

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();

        }

回答1:

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.



回答2:

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.