- Magento Front Controller
- Reinstalling Magento Modules
- Clearing the Magento Cache
- Magento’s Class Instantiation Abstraction and Autoload
- Magento Development Environment
- Logging Magento’s Controller Dispatch
- Magento Configuration Lint
- Slides from Magento Developer’s Paradise
- Generated Magento Model Code
- Magento Knowledge Base
- Magento Connect Role Directories
- Magento Base Directories
- PHP Error Handling and Magento Developer Mode
- Magento Compiler Mode
- Magento: Standard OOP Still Applies
- Magento: Debugging with Varien Object
- Generating Google Sitemaps in Magento
- IE9 fix for Magento
- Magento’s Many 404 Pages
- Magento Quickies
- Commerce Bug in Magento CE 1.6
- Welcome to Magento: Pre-Innovate
- Magento’s Global Variable Design Patterns
- Magento 2: Factory Pattern and Class Rewrites
- Magento Block Lifecycle Methods
- Goodnight and Goodluck
- Magento Attribute Migration Generator
- Fixing Magento Flat Collections with Chaos
- Pulse Storm Launcher in Magento Connect
- StackExchange and the Year of the Site Builder
- Scaling Magento at Copious
- Incremental Migration Scripts in Magento
- A Better Magento 404 Page
- Anatomy of the Magento PHP 5.4 Patch
- Validating a Magento Connect Extension
- Magento Cross Area Sessions
- Review of Grokking Magento
- Imagine 2014: Magento 1.9 Infinite Theme Fallback
- Magento Ultimate Module Creator Review
- Magento Imagine 2014: Parent/Child Themes
- Early Magento Session Instantiation is Harmful
- Using Squid for Local Hostnames on iPads
- Magento, Varnish, and Turpentine
Happy spring everyone, today it’s just a quick post about a new Magento module I’ve put up on GitHub enabling cross area sessions. This module allows you to access information about the logged in admin user from Magento’s frontend cart application, or access information about the logged in customer from the backend admin application. This sort of functionality is immensely valuable if you’re building custom workflows for merchants.
Using the Module
One you’ve installed the module, everything’s done using the
pulsestorm_crossareasession/manager service model. You can grab a named area’s session with the following
$data_adminhtml = Mage::getModel('pulsestorm_crossareasession/manager') ->getSessionData('adminhtml'); $data_frontend = Mage::getModel('pulsestorm_crossareasession/manager') ->getSessionData('frontend');
One thing to keep in mind — while this allows you to grab an area’s session data, after calling the
getSessionData method you’re still operating in the context of your original session. That means if there’s an object in the session data that relies on the context of its area, it won’t behave like you might expect it to.
The most obvious example of this is the
Mage_Admin_Model_Acl object stored in the adminhtml session. You can grab it from a frontend page with the above code, but because the methods on the ACL object assume you’re running from the adminhtml area, they won’t work the way you’d like them to. Since this is the most obvious use for this sort of module, the
pulsestorm_crossareasession/manager service model also includes a method for checking backend ACL rules from the frontend.
$can_access_cache = Mage::getModel('pulsestorm_crossareasession/manager') ->checkAdminAclRule('system/cache');
If there’s other, similar “session aware” functionality you think should be exposed, or you run into problems using this, please open an issue via the GitHub issues tracker.
This module is something I’ve though about implementing for a while, but I’ve always dreaded the though of diving deep into Magento’s session handling code. PHP’s session handling is flexible, but the APIs for interacting with it are a little clunky. This means almost every PHP system, Magento included, builds a session abstraction layer on top of the PHP session functions, and every abstraction layer is just different enough to cause headaches.
After discovering the early session bug in Magento and fixing Commerce Bug, I finally had enough innate knowledge about Magento’s session handling to tackle this sort of functionality.
In theory, this sort of thing should be easy. However, like I said, PHP’s session handling code is a little clunky. For starters, PHP stores session data in a custom serialization format — a format that’s different from the standard PHP serialize format. PHP 5.4 introduced the ability to use PHP’s standard serialization format for sessions, but that does us no good here.
Fortunately, PHP provides a
session_decode function that can read this custom serialization format. Unfortunately,
session_decode also automatically populates the
$_SESSION super global with the newly decoded data. Doubly unfortunate,
session_decode is the only (to my knowledge) native way to read this serialization format.
This means you can’t read session data from another session without discarding the current session data, and that’s an unacceptable tradeoff.
Working around this is conceptually simple, but required a lot of careful programming. The biggest problem? A critical error (loss of session data), happens silently, and it’s hard to directly observe. Normally this is the sort of task I’d like slung up in an automated test harness, but because it’s dealing with a core PHP system like sessions, the normal unit testing frameworks weren’t appropriate/suitable. (No sessions on the command line, browser based test harnesses may monkey with the sessions themselves, etc.)
The details are in the
Pulsestorm_Crossareasession_Model_Manager::getSessionData method, but from a high level it meant
- Stashing the original session data in a new variable
- Loading the second area’s session data using
Stashing the newly populated
$_SESSIONdata into a variable for returning
Restoring the original stashed data from step 1 into
Returning the stashed data from step 3
The other tricky thing about this was the actual loading of the session data. By default, PHP stores its sessions to the file system. However, like so many things in PHP, users can set a custom session handler for loading and saving sessions. Unfortunately, there’s no PHP function for loading session data into a variable.
This means the module needs to conditionally check how Magento is saving sessions, and then loading the current named session from the appropriate place. This is a classic opportunity for an abstract factory pattern, and you can see the session loaders in the following folder
ls -1 app/code/community/Pulsestorm/Crossareasession/Model/Loader/ ... Db.php Files.php ...
The module ships with session loaders for the file and database session storage types, and allows you to define a new loader class (that extends
Pulsestorm_Crossareasession_Model_Loader_Abstract) for other session storage methods (redis being the next most popular option, I imagine).
Also of possible interest: It was monkeying around with the database loader and Magento’s
core/resource_session object that led to my discovery of the weird call to
session_write_close in the object/class destructor method, and the accompanying banging-of-my-head-on-the-keyboard until I realized “don’t use
core/resource_session as an instance model” was a rule here.
While the project’s usable as is, I would like to add redis support, as well as other session engines, and get a test harness in place. Happily accepting pull request and/or feedback on those ideas, as well as any other feedback you may have.