Magento 2 – Passing Variables from Controller Action to View

factorylayoutmagento2phtml

In Magento 1, if you want to pass data from your Controller action to the "View" (i.e. a block in your layout, you can)

  1. Add a value/object to the global registry via Mage::register

  2. Directly fetch a block object and set data properties on the fetched block object after running loadLayout

  3. Call methods on block objects in phtml files, and have the block objects use the model/database layer to read data previously saved in the controller action

Using block object methods to read from the database still appears to work in Magento 2 — which is appropriate for certain sorts of operations. However,

  1. There's no longer a global registry in Magento 2 (or is there?)

  2. The layout system now works by creating a page object via a factory, and you can't grab block references the same way you can in Magento 1

Is it possible in Magento 2 to pass data directly from a controller action down to a view? Or is this too direct a pattern for Magento's brave new Design Pattern™ world? If this is too direct a pattern, what should be doing if there's some calculated information we want to display in a template, but don't want to store that information into a stateful system (i.e. we don't want to save it to the database)

I can think of a few different way to hack this together myself — but I'm interested in how Magento 2 wants you to do it.

Note: I realize it's possible to fetch a block instance in a controller action using something like this

$resultPage = $this->resultPageFactory->create();    
$block = $resultPage->getLayout()->getBlock('catalog.wysiwyg.js');        

var_dump(spl_object_hash($block));

The Magento 2 core code does this often. However — the block object fetched in the controller object seems to be a different object than is available in a phtml template via either $this or $block (the former ($this) appears to be the object that actually renders the template, whereas the later ($block) appears to be an instance of the Magento Block type).

#File: path/to/template.phtml
var_dump(spl_object_hash($block));
var_dump(spl_object_hash($this));

I say "appears to be" because if I set data in the controller action method, it's not available in the phtml template — and if I compare the spl_object_hash results above, I get three different hashes. However, I'm new enough to all this that the above might be some other error I've made — so if you've been able to set data on blocks and fetch it in a template I'd love to hear about it!

Best Answer

Regarding #1, the registry does still exist, very similar to what you know from Magento 1. It's just moved. See: \Magento\Framework\Registry

Add it to your constructor via dependency injection, and then you can use your familiar $registry->register($key, $value) and $registry->registry($key) methods to store/access data.

I'd recommend poking around the \Magento\Framework namespace if you haven't already. A lot of what was accessible from Mage or App before is still there, just split out.

As far as best practices, I can't answer that, but I expect the answer would be to keep as much logic out of the controller as possible. Looking at the core is probably your best bet. For instance, see the customer address edit page: Basic controller; extensive block--including pulling the address ID and loading, if necessary. They handle that directly in the block; they don't do it in the controller and then pass it around.

Related Topic