views:

76

answers:

4

Really quick and simple question but I can't find a decent answer to this - What is the best way to pass data from a controller to a block in Magento.

Incase it makes a difference, I am loading the layout as follows:

 $this->loadLayout(array('default', 'myModule_default'));

    $this->_initLayoutMessages('customer/session')
         ->_initLayoutMessages('catalog/session')
         ->renderLayout();

I should add, that I have been using the registry as follows:

In the controller:

Mage::register('data', $data);

In the block:

$data = Mage::registry('data');

Not sure if this is the best way to do it though.

+2  A: 

You're on the right track using the Mage::registry() approach. The other option is to use automatic getters and setters, e.g. $this->setRandomVariableName($data) in the controller and then in the block use $this->getRandomVariableName(). I haven't investigated whether they end up in the same location in the stack (I assume in the session as they are request-specific), but they achieve the same aim in the code.

Using the getters and setters can occasionally get confusing as it may look like you are accessing the data through the ORM rather than a "temporary" session variable, so you might make a coding-style consistency decision to use Mage::registry for those types of variables. Your choice really.

Jonathan Day
I have tried this previously, assuming that there would be magic getters and setters - I always get an undefined method error though.
Drew
Hmm, perhaps you need an instantiated Model to perform the auto-magic get/set on. It might not work on $this in a controller context. If your controller already has an object created by `Mage::getModel('module/model'), then you should be able to use that. It probably also gives the variable more context which is a good thing...
Jonathan Day
Magic getPropName and setPropName only work on objects that inherit from Varien_Object.
Alan Storm
@Alan thanks, that makes perfect sense. Would you say that in some situations having a model would add more un-needed complexity and that using the registry as described previously would suffice. Or, would you always advocate to stick to the pattern and always use a model for any data, regardless.
Drew
@Drew That's one of those arbitrary things I have a hard time having too much of an opinion on. I think of the registry like global variables, "last resort if there's no other way". Two random things to consider "What happens if your view/block gets used in a context where your registry variable hasn't been set. Second, it's worth noting that, at the moment, Magneto's getSingleton is implemented by caching the initial object instantiation to the registry. So I stick with the Model approach because I have a larger philosophy of "do things like the core team does".
Alan Storm
A: 

What has worked for me in the is to set the variable in the controller by doing:

Mage::register('variable', 'value');

And then in the view you would retrieve the value using the following code:

$variable = $this->getVariable();
Josh Pennington
+3  A: 

You don't.

In Magento's MVC approach, it's not the responsibility of the controller to set variables for the view (in Magento's case, the view is Layout and blocks). Controllers set values on Models, and then Blocks read from those same models. In Magento's view of the world, having a Block relying on the controller doing a specific thing is tight coupling, and should be avoided.

Your controller's job is to do certain things to Models, and then tell the system it's layout rendering time. That's it. It's your Layout/Blocks job to display an HTML page in a certain way depending on the state of the system's Models.

So, if I wanted to emulate traditional PHP MVC behaviors I'd

  1. Create a simple Model class the inherits from Varien_Object

  2. In the controller, instantiate that object using the Mage::getSingleton('foo/bar')

  3. Set values on the Model using the magic getter/setters (you get these in objects that inherit from Varien_Object), or setData, etc.

  4. In the Blocks, instantiate the Model again with a Mage::getSingleton('foo/bar') and read the values back.

When you instantiate a Model with Mage::getSingleton(...) Magento will instantiate the object as a singleton. So, if you re-instantiate an object (again with Mage::getSingleton('foo/bar')) you're getting back the same object.

Alan Storm
A: 

If you are using blocks that inherit Mage_Core_Block_Template (i.e. that use a template to display) you can assign data using the assign() method, once the blocks have been instanciated by loadLayout()

$this->loadLayout(array('default', 'myModule_default'));

$this->getLayout()->getBlock('your.block.name.in.the.layout')->assign('data', $data);

Then, in the .phtml template, you can simply use

<?php echo $data ?>

This is not used very often in magento, but since it's implemented as public methods and thus declared stable, I believe it's fine do so. Thats also the reason for the convention to start variables declared in a template with an underscore (e.g. $_product = $this->getProduct()), so they can be distinguished from assigned variables.

Vinai