I've finally reached the "rendering" phase of my second Magento module, but I'm stuck again. The module is now almost complete, it has a Controller and two blocks, one of which is called by the first (one is a dashboard block, which uses the second one to populate sub-sections).
What I need to do now it add this new dashboard to Customer Account Dashboard. I was told to use layout files, and I've read about them on Magento Design Guide. I then created the layout file and added the declaration of my block in it. However, the dashboard is not modified and my data is not displayed. If I call the extension method manually (i.e. myserver/customerstats/index) I get back the snippet of HTML that I'd like to display on Customer Account page.
At first I thought that my layout file was not loaded, but I now have the proof that it's processed correctly (at least, part of it). Here's the layout file:
<layout version="0.1.0">
<customer_account_index translate="label">
<label>My Custom Dashboard</label>
<reference name="customer_account_dashboard">
<!-- The action is processed correctly, the template is overridden -->
<action method="setTemplate"><template>customerstats/customer/account/dashboard.phtml</template></action>
<block type="customerstats/index" name="customerstats_dashboard" as="customerstats.dashboard" template="customerstats/customerstatsdashboard.phtml" />
</reference>
</customer_account_index>
</layout>
I added the setTemplate action to the layout file because one of the requirements is that the new dashboard is split in two parts vertically. This means I had to modify the original customer/account/dashboard.phtml and change the structure of the page, adding two sections that will be styled as required. I'm not sure this is the correct way of doing it, but I couldn't figure out how to add my additional in a specific part of the page, without touching the .phtml file.
I modified the new dashboard.phtml, to make sure it was loaded, and I can see the Customer Account page showing my changes when I enable the action. However, the block that should be rendered by my extension doesn't appear on the page and, based on my simple "trap" (a simple "die()", to prove the code is executed), the extension method doesn't even seem to be called.
Here's the Controller I'm trying to call from the block, with the irrelevant parts removed.
class MyCompany_CustomerStats_IndexController extends Mage_Core_Controller_Front_Action {
// The loaded block is setting its own template in the _construct() phase
$Block = &$this->getLayout()->createBlock('customerstats/customerstatsdashboard');
// Some data is loaded elsewhere and passed to the Block
$this->getResponse()->setBody(
$Block->toHtml()
);
}
The Controller is fired properly if I call it manually (myserver /customerstats/index) and it returns fully rendered HTML, but, as mentioned in the beginning, it doesn't seem to run when the layout file comes into play.
To summarize, here are my questions:
- Am I on the right track regarding the override of Customer Account Dashboard?
- Do I have to specify a template attribute in the layout for the extension? All the blocks I implemented load their template via code (there's a logic for choosing which one to use), and I don't see the use in having the template indicated in the xml file as well.
- Once I add a block to the XML file, do I have to alter the dashboard.phtml file to render it somewhere? I'm asking because I saw the original dashboard template, and it contains various calls to getChildHtml('alias name of a block')
. This leads me to think that blocks don't have to just be "exposed" in the layout file, but also manually called in the .phtml files. However, this is a speculation, since I don't have a clear understanding of the mechanism. Note: I also tried to call getChildHtml('customerstats.dashboard)
inside my new dashboard.phtml, but nothing changed.
Thanks in advance for all the answers.
Update 1 - 2012/07/28
This is the code for the Block that is not rendered.
class MyCompany_CustomerStats_Block_UserStatsDashboard extends Mage_Core_Block_Template {
const _TEMPLATE = 'customerStats/userstatsdashboard.phtml';
public function _construct() {
$this->setTemplate(self::_TEMPLATE);
}
}
Also, I made an experiment with the Controller itself. I changed it as follows:
class MyCompany_CustomerStats_IndexController extends Mage_Core_Controller_Front_Action {
die('Controller called successfully.');
}
Here are the results: - If I call "myserver/customerstats/index" from the browser, I get the message "Controller called successfully.". - If I load the dashboard page which I modified, I can see the new layout (which means that my dashboard is loaded), but not the message. To me, this means that the Controller didn't even get called.
Content of Config.xml
<?xml version="1.0"?>
<config>
<modules>
<MyCompany_CustomerStats>
<version>0.1.0</version>
</MyCompany_CustomerStats>
</modules>
<global>
<helpers>
<CustomerStats>
<class>MyCompany_CustomerStats_Helper</class>
</CustomerStats>
</helpers>
<models>
<CustomerStats>
<class>MyCompany_CustomerStats_Model</class>
</CustomerStats>
</models>
<blocks>
<CustomerStats>
<class>MyCompany_CustomerStats_Block</class>
</CustomerStats>
</blocks>
</global>
<frontend>
<routers>
<CustomerStats>
<use>standard</use>
<args>
<module>MyCompany_CustomerStats</module>
<frontName>userstats</frontName>
</args>
</CustomerStats>
</routers>
<layout>
<updates>
<CustomerStats>
<file>customerstats.xml</file>
</CustomerStats>
</updates>
</layout>
</frontend>
</config>
Update 2 - 2012/07/28
I made an experiment that, I admit, makes absolutely no sense to me from an MVC perspective. I changed the layout and specified block type as customerstats/userstatsdashboard. I then modified the Block class MyCompany_CustomerStats_Block_UserStatsDashboard
as follows:
public function _construct() {
echo "Block rendered.";
}
Surprisingly, now something appears in the new layout, exactly where I would expect it! But this means that the Controller hasn't been called at all, which, in turn, means there's no data available for the blocks.
This really perplexes me, I've never seen an MVC model where Views manage themselves... What's the purpose of the extension's controller, then?