Magento How can i change request parameters on the fly? - magento

I tried to write an Observer like controller_action_predispatch and like for the default sort in Magento: store.com/category.html?dir=asc&order=name
in the observer i tried to manipulate the parameters but no succes. I tried for examples always for DESC order so i did like this: Mage::app()->getRequest()->setParam('dir', 'desc');
But after render the pruduct list it dont work... I sense i have no power on request parameters or is there a way to change them before loading a page and using a Magento event?

if you have an issue in product sorting then i will suggest to use Observer "catalog_block_product_list_collection" on this event and then observer class you can use
$observer->getEvent()->getCollection()->addAttributeToSort('price', 'ASC');
Thanks

Related

Magento website popup from a observer

I have an observer listening to the controller_action_predispatch event. This is because I'm doing some geo ip related logic for each page customers are visiting.
I want to show a light-box popup to get customer's input as a part of the logic.
Part of the issue that I'm facing here is at this stage layouts are not loaded. :(
Is this possible to do? If so whats the best efficient way of doing it?
Look at
Mage_Core_Controller_Varien_Action::renderLayout()
Mage::dispatchEvent('controller_action_layout_render_before');
Mage::dispatchEvent('controller_action_layout_render_before_'.$this->getFullActionName());
That event might work better
So I had to go with a different event to access the layouts from my Observer. Best one for me was listening to controller_action_layout_generate_blocks_after event. Then I grab a block,
$myblock = $observer->getLayout()->getblock('myblock');
$myblock->setMyvar('PassMyValue');
And then use that value to popup my light box to get the user input.

In Magento, what is an observer exactly? What does it do?

I'm an extremely novice programmer who finds himself tasked with learning how to program for Magento. So please forgive me for such a rudimentary question but there don't seem to be a ton of beginning level content on Google regarding Mage.
Can someone explain to me what exactly an observer is? What does it do? What can it be used for?
If someone can give me a super 101 explanation (not assuming much prior knowledge) you'll be my new hero. Thanks.
You can consider Event observer as a trigger.
Once you have set an event observer, for example you can set observer before or after an event, i.e., You can add a event which would execute right after user adds a product to cart or before the add product to cart.
In this event observer, you can write code to customize the data which is either passed to the occuring event (before) or is the output of occured event (after)
Reference : http://www.magentocommerce.com/wiki/5_-_modules_and_development/0_-_module_development_in_magento/customizing_magento_using_event-observer_method
Event :
In Magento you may consider a Controller Action as an event, for example addAction in CartController is an event.
Observer :
As mentioned in name, the observer observes when this action occurs (in our case addAction in CartController) and calls a function either before or after this addAction is called.
You may add your custom code in this obeserver for customization.
An Observer is the piece of code you'll need to write if you implement an Event.
Your question is : what is an event ?
See an event as a "broadcast action" that you can intercept in order to add your specific code to a specific action.
There are events fired all over magento key functionnalities.. For example, you can intercept:
- after or before saving a product
- product added to the cart
- etc
It's just an open-door leaved by magento core developers for you to plug-in..
In magento you have several ways to modify the behavior of the standard fucntionnality :
- you can rewrite classes ( tags in config.xml)
- and you can use the events when an event is available for the functionnality you want to modify
To understand, dive in the code and search "dispatchEvent" in app/code/core ...

How to call a certain method in each action method of all controller classes in Magento?

For a Magento shop I'm working on I have to check certain session variables on each load of a page. When the variables don't have the expected values I need to redirect to certain page.
No I wonder how I could implement such a behavior. Normally I would do the check in action methods of each controller, but I don't want to rewrite each controller or all their base classes.
Is there a easier way?
Magento's event architecture to the rescue! Observe the controller_action_predispatch method.
Edit: Note that this event is dispatched in both adminhtml and frontend, so Sergy's answer is important - configure the event observer under the appropriate area.
Yes,
you can always use magento events in this case:
1. controller_action_postdispatch.
2. controller_action_predispatch .
Be careful: same events are used in admin area also.

Magento read-only and hidden product attributes

I would like to have some Magento product attributes that are not editable from the admin interface and some that are not visible at all in that interface (as a method of storing some persistent information about a product that should not be viewed by human users.. it's the only way of doing this that i can think of, any other suggestions are welcome).
So my question is: Do all Magento attributes have to be visible and editable from the admin interface? If not, how can they be made read-only or hidden?
I noticed that in the admin interface there are some read-only fields, so it must be possible to do this one way or another. After searching stackoverflow for this I found a possible solution involving JavaScript, but I would like to not go down that path if it's at all possible.
OK, it looks like it can be done after all. After adding an observer for the catalog_product_load_after event, the lockAttribute method of the Mage_Catalog_Model_Abstract class may be used to make a product attribute read-only. Here is the code for the observer method:
public function lockAttributes($observer) {
$event = $observer->getEvent();
$product = $event->getProduct();
$product->lockAttribute('attribute_code');
}
Since the catalog_product_load_after event is dispatched for every product load, the attributes supplied in the lock_attributes method are locked after every product load. This could have unexpected results: it is not possible to change the value of the attributes in the lock_attributes method without explicitly unlocking them.
Instead of using the catalog_product_load_after event, it suffices to add an observer for the catalog_product_edit_action event: this event is dispatched only when editing a product in the admin interface.
I think Aad Mathijssen and Epicurus combined have the best answer to the question, with a little clarification. As Aad points out, catalog_product_load_after is called after every product load and that means on the FrontEnd as well!
If we are looking to protect attribute fields only in the admin panels, catalog_product_edit_action is the more appropriate choice.
Your etc/config.xml will then be something like this:
<catalog_product_edit_action>
<observers>
<lock_attributes>
<class>yourmodule/observers</class>
<method>lockAttributes</method>
</lock_attributes>
</observers>
</catalog_product_edit_action>
No i guess its not possible from the attribute manager.
A easy quick and dirty solution would be to use css to hide the input and label.
I have developed exactly such extension that works for products, categories and CMS pages. You just have to define some rules and choose which attributes you want to show as read-only.
Extension URL: https://www.bubbleshop.net/magento-admin-readonly.html
Using this thread and some more digging around; the lockAttribute method is from an abstract class which means that it's possible to also be used on category attributes as well. I caught the 'catalog_category_load_after' observer and used it to lock my desired category attributes:
public function lockCategoryAttributes($observer) {
$event = $observer->getEvent();
$c = $event->getCategory();
$c->lockAttribute('attribute_code');
}
I'm not sure if that's the right observer to use but it works.
So yes it is possible to lock category attributes or make them readonly.
etc\adminhtml\events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="catalog_product_load_after">
<observer name="product_lock_attributes" instance="Vendor\Module\Observer\Lock"/>
</event>
</config>
Observer\Lock.php
namespace Vendor\Module\Observer;
class Lock implements \Magento\Framework\Event\ObserverInterface
{
public function execute(\Magento\Framework\Event\Observer $observer)
{
$event = $observer->getEvent();
$product = $event->getProduct();
$product->lockAttribute('attribute_code');
}
}

Dynamic layouts in CakePHP

Sorry about the question title, but I couldn't find a more appropriate way to phrase this.
I am currently building a CakePHP powered website and I'm not quite sure how to approach the following issue. The website looks something like the follwing mockup:
.
The greyed out areas are part of the layout, because their content does not change between views. In the sidebar, I have a collection of ads who are linked to several models. I need controller logic to determine the picture associated with an ad. Also, the ad list needs to be dynamic. Where should I put the logic for building the sidebar?
I've thought about:
putting the logic into the AppController (beforeFilter / afterFilter) - the problem is I can't use the controller logic I need (the other controllers inherit from AppController, I'm not sure how to use them there).
making a component - is it okay to build components that rely on controllers?
replicating the sidebar code in all controllers that render views - this seems kind of stupid to me.
What is the Cake way for this?
Update
After some reading and experimenting, I've gotten to refactoring most of it.
I obtained the best performance by moving the logic for building my ads in the model (eliminating the component that retrieved the pictures) and not using requestAction. It's almost three times faster and the code looks much better.
I've done something similar for data-driven navigation. I put my logic in AppController::beforeRender and haven't had any problems. I'm not sure I understand your concern related to controller inheritance. I retrieve my menus via:
$menus = $this->NavMenuItem->groupByMenu();
$this->set( compact( 'menus' ) );
I then created an element that renders the menu. It's executed by the layout via:
<?php echo $this->element( 'navigation', array( 'id' => 'secondary', 'menu' => $menus['SECONDARY'] ) ) ?>
If that doesn't help, maybe you can further explain your issue with controller inheritance in a comment.
I guess the answer is requestAction in case the results are cachable:
http://book.cakephp.org/view/434/requestAction
It can be done in this way:
Create an element that will help in layout of the Ad Block
Create one or more controller that will generate the data required for rendering of the block
Use requestAction for getting the data out of the models and into the element.
Check the cake book, there is an example of an element where data from Post Model is used to display top/latest 5 posts. Your requirement, I feel, is very similar to it.
Alex,
you're getting a SQL error because the build() function has to be in the Sidebar model, not controller. Also, you don't necessarily need to use $user = array('Sidebar'); you could calling Sidebar in all of your models with this:
$Sidebar = ClassRegistry::init('Sidebar'); and then $Sidebar->find();, $Sidebar->build(); etc.
Or, if you only need to call the build() function from the Sidebar model, you could do this:
$sidebar = ClassRegistry::init('Sidebar')->build();
$this->set('sidebar', $sidebar);
Cheers.

Resources