Magento router: How can I catch parameters in all URLs? - session

Think of a small and basic affiliate system. I want an URL like
www.myshop.com/mynewproduct.html?afid=123
Every time afid is found in the URL, a method should be called (basically to save "afid" in the session and when the customer buys stuff, I want to track it).

You don't need a router for this. You'll want to setup an event listener that fires for every page load, and then access the variables in the request collection. The controller_front_init_routers event should do.
So, setup your module's config with the following
<global>
<events>
<controller_front_init_routers>
<observers>
<packagename_modulename_observer>
<type>singleton</type>
<class>Packagename_Modulename_Model_Observer</class>
<method>interceptMethod</method>
</packagename_modulename_observer>
</observers>
</controller_front_init_routers>
</events>
</global>
And then create the following class
app/code/local/Packagename/Modulename/Model/Observer.php
class Packagename_Modulename_Model_Observer {
public function interceptMethod($observer) {
$request = $observer->getEvent()->getData('front')->getRequest();
$afid = $request->afid;
//do whatever you want with your variable here
}
}
The interceptMethod can be named whatever you want.

I know this is a very old answer, but it is valid to mention we shouldn't use the controller_front_init_routers event if we intend to store those parameters in session, which is the scenario for the original question. For example, if you instantiate customer/session at this point you won't be able to perform a customer login anymore. Alan pointed this himself in http://alanstorm.com/magento_sessions_early. BTW, thanks Alan for this great article.

Related

Perform Some Action after Customer successful Login : Magento

I am creating a module in which I want to check some condition after customer successfully login, if condition is true then customer login otherwise not.
I know two ways of doing this :
Overriding AccountController
With Magento event.
My query are:
which is the best way?
Is there any event with which I can full fill my requirement?
Or if there is other best way of doing this, please recommend.
You need to use customer_login
On the Mage_Customer_Model_Session model's method setCustomerAsLoggedIn() the event customer_login is dispatched.
config.xml
<customer_login>
<observers>
<yourobservername>
<type>model</type>
<class>yourmodule/path_to_class</class>
<method>customerLogin</method>
</yourobservername>
</observers>
</customer_login>
and your Observer
class YourCompany_YourModule_Model_Observer
{
public function customerLogin($observer)
{
$customer = $observer->getCustomer();
}
}
Whenever a user is sucessfully logged in, the event customer_login will be fired and you have observed the method customerLogin() on that event, so your method from the observer will execute whenever a customer is successfully logged in.
Here you can check your conditions as per requirements.
I think the best way to use magento event if possible. But in your case you have to check the condition before customer logins am i right? If so i don't think there is any events for that.So the best way is to override the controller.

mage registry key "_singleton/" already exists

I know there are lot of posts with this problem, but I guess each of them is with different roots of it (at least from what I checked - nothing helped me).
I am trying to fire the event upon click on a button from the user, but I get the upper mentioned exception in a browser alert Mage registry key "_singleton/" already exists.
The part of the config.xml:
.....
<models>
<packagecustomernumber>
<class>Package_CustomerNumber_Model</class>
</packagecustomernumber>
</models>
</global>
<frontend>
<events>
<checkout_type_onepage_save_order>
<observers>
<type>singleton</type>
<class>packageName/customernumber/observer</class>
<method>setCustomerNumber</method>
</observers>
</checkout_type_onepage_save_order>
</events>
</frontend>
And the class itself:
class Package_CustomerNumber_Model_Observer
{
public function setCutomerNumber($observer)
{
die('setCutomerNumber');
}
}
The button which should fire the even it checking out/saving the order, so the event should be correct.
Any suggestions ?
The first thing that pops out is this
<class>packageName/customernumber/observer</class>
That's invalid. This is the node where you're telling Magento what class to use for your observer. As such, the <class/> node should be either the full PHP class name of your observer
<class>Package_CustomerNumber_Model_Observer</class>
Or a class aliases for the model
<class>packagecustomernumber/observer</class>
Also, before running your observer, it helps to make sure you can instantiate your model class. Try running the following code in a Magento loaded environment (script, controller action, phtml template, etc.)
$model = new Package_CustomerNumber_Model_Observer;
var_dump(get_class($model));
$model = Mage::getModel('packagecustomernumber/observer');
var_dump(get_class($model));
If you can't instantiate the class, then Magento won't be able to either (and it's easier to test this first before running through some steps to trigger your observer).
Yes, the "packageName/customernumber/observer" is the source of the problem.
while this class reference is completely incorrect in its structure, the problem actually comes up when your class reference does not match up with your global/models/modulename definition. even when the reference "looks" correct.
The config :
<config>
<global>
<models>
<mymodule>
<class>My_Module_Model</class>
</mymodule>
</models>
<events>
<some_event_tag>
<observers>
<my_event_observer_method>
<class>my_module/observer</class>
<method>myEventObserverMethod</method>
</my_event_observer_method>
</observers>
</some_event_tag>
</events>
</global>
</config>
Will have the same result because "my_module/observer" is not found, since the "my_module" class group node is not configured. The correct use for this sample would have been "mymodule/observer".
So if you run across this error, re-read your config.xml.
Make sure that your config.xml models section contains
<!-- This says that string 'company_module' corresponds to Company_Module_Model pseudo-namespace in getModel() and getSingleton() calls. -->
<company_module>
<class>Company_Module_Model</class>
</company_module>
Otherwise you won't be able to make new model instance.

Magento newsletter_subscriber change_status_at

I've been looking for a while at other threads, several have been close to what I need but not quite.
When a guest or customer sign up for our newsletter the field change_status_at populates with a timestamp.
However, if the guest or customer unsubscribe, we would like the the change_status_at field to pickup the current timestamp.
This is important to use because we do not use the newsletter "feature" of Magento 1.7.0.2 CE. Rather we export the newletter_subscriber list to a company to send an email.
Thank you,
Dan
I just ran into this too. A customer wanted to know the date when a subscribe/unsubscribe action occurred. Looking around the internets I've found a few others who have run into this and some claim that it used to work in very old version of Magento.
I think what happened is that the field definition for change_status_at used to be setup to auto update as a default timestamp (i.e. ON UPDATE CURRENT_TIMESTAMP), but that was lost in some update. So there's no Magento code that writes to the field, because MySql is supposed to magically maintain it.
You could try updating the table definition to add the ON UPDATE CURRENT_TIMESTAMP back in (but I'm not in favor changing default model tables) or adding another field to be the default timestamp field.
Or a better solution would be to create a module with an observer to just add the date in when the subscription changes. Here's that might look like (warning - this code is just an example, there may be some syntax errors due to expunging my module's info) -
app/code/local/Myco/MyMod/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<Myco_MyMod>
<version>1.0.0</version>
</Myco_MyMod>>
</modules>
<global>
<models>
<myco>
<class>Myco_MyMod_Model</class>
</myco>
</models>
<events>
<newsletter_subscriber_save_before>
<observers>
<mycomymod_observer_subscriber>
<type>singleton</type>
<class>Myco_MyMod_Model_Observer</class>
<method>setUpdateDate</method>
</mycomymod_observer_subscriber>
</observers>
</newsletter_subscriber_save_before>
</events>
</global>
</config>
===========
in app/code/local/Myco/MyMod/Modules/Observer.php
<?php
class Myco_MyMod_Model_Observer
{
public function setUpdateDate(Varien_Event_Observer $observer) {
$subscriber = $observer->getSubscriber();
$subscriber['change_status_at'] = (date("Y-m-d H:i:s", time()));
}
}

Magento Multi-store E-mail Templates

I've got a multistore setup (shop A and B) with shared e-mail templates. In these templates, I reference custom variables that are differentiated over A and B.
Shop A ==\ /==> Custom Var (version A)
>==> E-mail Template X ==<
Shop B ==/ \==> Custom Var (version B)
This works pretty well, except for 1 issue: when I create an account through the admin for shop B, I cannot get the password reminder to be of shop B. Sending this user a new password will always send out as shop A.
Mind that the welcome mail that gets sent, is the correct one (B) but I guess only because you select the sending shop from the Create Account screen.
I do realize that the account is marked as having been created by Admin instead of Shop B as opposed to when one would have registered through Shop B. I can imagine this could contribute to the problem, but still, I'd really like to find a way to:
Create an account for Shop B through the admin
Have the password reminders sent in Shop B-style
Edit: the following question is related in the sense that is talks about associating a user with a shop from the admin: How can I change a customer store_id in Magento or set the "created_from" attribute when creating a new customer
It seems that by default, it's just impossible to create an account from the admin that's linked to a specific store. I did find a way though, by listening to adminhtml_customer_prepare_save and abusing the "send from" in the Account creation form.
Here's a module that I whipped up for it:
etc\config.xml:
<config>
<modules>
<Company_AccountPerStore>
<version>1.0</version>
</Company_AccountPerStore>
</modules>
<global>
<models>
<accountperstore>
<class>Company_AccountPerStore_Model</class>
</accountperstore>
</models>
</global>
<adminhtml>
<events>
<adminhtml_customer_prepare_save>
<observers>
<accountperstore_observer>
<class>Company_AccountPerStore_Model_Observer</class>
<method>customerPrepareSave</method>
</accountperstore_observer>
</observers>
</adminhtml_customer_prepare_save>
</events>
</adminhtml>
</config>
Model\Observer.php:
class Company_AccountPerStore_Model_Observer extends Varien_Object
{
public function customerPrepareSave($observer)
{
$customer = $observer->getEvent()->getCustomer();
if (!$customer->hasStoreId() && $customer->hasData('sendemail_store_id')) {
$customer->setStoreId($customer->getData('sendemail_store_id'));
}
}
}
Note that you won't be able to detect that the account was created with the admin anymore.

Magento backend_model - do I need to specify for each config field?

If I want to do something extra when a particular configuration field for my custom module is saved (over and above saving to the Magento core config table), I can just specify a backend_model for that field in my system.xml, and have that backend model class extend Mage_Core_Model_Config_Data, override _afterSave, and put my extra stuff in that method.
But what if I have several fields I want to do this for. I don't want the behaviour to be to save field1 and call my afterSave for that field, save field2 and call my afterSave for that field, etc. I'd rather that all the fields were saved to the Magento core config table, and then I do my extra stuff.
Is that possible? I thought I might be able to achieve that using event/observer. So in my config.xml, <adminhtml> section, I added an observer as follows:
<events>
<admin_system_config_changed_mysection>
<observers>
<mypfx_admin_system_config_changed_mysection>
<class>mymodule/adminhtml_system_config_backend_configSaveObserver</class>
<method>myConfigSaved</method
</mypfx_admin_system_config_changed_mysection>
</observers>
</admin_system_config_changed_mysection>
</events>
but my observer method is not called when the config is saved. Maybe I have the wrong event name? The "mysection" bit on the end of the event name I was guessing had to match the section from system.xml:
<sections>
<mysection translate="label" module="mymodule">
...
<groups>
...
</groups>
</mysection>
</sections>
Thanks.
The event you're trying to listen for doesn't exist. Here's what you want to do, and some tips for picking the right event in the future.
First, every event is fired in Magento by the Mage::dispatchEvent method. Search the core code for these calls and you'll always know the name of the event you want to listen for.
$ ack 'admin_system_config_changed_'
Adminhtml/controllers/System/ConfigController.php
136: Mage::dispatchEvent("admin_system_config_changed_section_{$section}",
From the above, you can see the name of the event vs. what you thought it was
admin_system_config_changed_section_{$section}
admin_system_config_changed_mysection
So, it looks like you're missing the section before your own section name.
Second, while working on a development box, the best way to find the event you're looking for is to log things at the source. Temporarily add some debugging code to the dispatchEvent function.
#File: app/Mage.php
public static function dispatchEvent($name, array $data = array())
{
//either one of the lines below should do it. One uses Magento's
//built in logging, the other uses something more crude
#Mage::Log($name);
#file_put_contents('/tmp/test.log',"$name\n",FILE_APPEND);
Varien_Profiler::start('DISPATCH EVENT:'.$name);
$result = self::app()->dispatchEvent($name, $data);
#$result = self::registry('events')->dispatch($name, $data);
Varien_Profiler::stop('DISPATCH EVENT:'.$name);
return $result;
}
This will dump a huge list of event names out to your log. I typically use OS X's Console.app to view the log file during the request, copy the lines out, sort and remove duplicates, and then end up with a list like this
admin_system_config_changed_section_commercebug
admin_user_load_after
admin_user_load_before
adminhtml_block_html_before
adminhtml_controller_action_predispatch_start
application_clean_cache
controller_action_layout_generate_blocks_after
controller_action_layout_generate_blocks_before
controller_action_layout_generate_xml_before
controller_action_layout_load_before
controller_action_layout_render_before
controller_action_layout_render_before_adminhtml_system_config_edit
controller_action_postdispatch
controller_action_postdispatch_adminhtml
controller_action_postdispatch_adminhtml_system_config_edit
controller_action_postdispatch_adminhtml_system_config_save
controller_action_predispatch
controller_action_predispatch_adminhtml
controller_action_predispatch_adminhtml_system_config_edit
controller_action_predispatch_adminhtml_system_config_save
controller_front_init_before
controller_front_init_routers
controller_front_send_response_after
controller_front_send_response_before
core_abstract_load_after
core_abstract_load_before
core_block_abstract_prepare_layout_after
core_block_abstract_prepare_layout_before
core_block_abstract_to_html_after
core_block_abstract_to_html_before
core_collection_abstract_load_after
core_collection_abstract_load_before
core_config_data_load_after
core_config_data_save_after
core_config_data_save_before
core_config_data_save_commit_after
core_layout_block_create_after
core_locale_set_locale
core_session_abstract_add_message
core_session_abstract_clear_messages
http_response_send_before
model_load_after
model_load_before
model_save_after
model_save_before
model_save_commit_after
resource_get_tablename
store_load_after
store_load_before
You still need to use some intelligence guessing to figure out which event you want, but they're named intuitively enough that you can usually find what you're looking for.
You need to tie your observer method to a specific Magento event (you can add your own, but need to find when you want it to be fired and add your own dispatchEvent call). If Magento has an event built in, use that event name in the config.
There's a pdf of the built in event lists on the web - google for it & you'll find it.

Resources