在Magento中,块如何从模型中获取数据?

16

有人可以解释一下这个吗?

让我告诉你我所知道的。如果前三点没问题,请解释第四点。

  1. 请求发送到控制器。
  2. 在控制器动作中,我们启动模型。
  3. 模型通过连接数据库等方式收集或生成所有所需的信息。

之后会发生什么?

  1. 模型如何将数据传输到块中,或者块是从模型获取数据的吗?

  2. 模板获取准备好的数据并显示在屏幕上

    • 此外,请求是否会再次返回控制器?

请解释。我在几个地方感到困惑。

3个回答

39

没有将数据传输到块中。当一个控制器操作完成其模型交互后,它负责:

  1. 加载一个布局对象(间接地,加载并创建块对象)

  2. 告诉该布局对象渲染页面。

大多数 Magento 控制器操作在控制器操作的结尾使用两个调用来完成此操作。

$this->loadLayout();
$this->renderLayout();

在Magento中,视图不会设置数据,而是视图(即块对象)向系统请求数据。您可以在Mage_Tag_Block_Customer_View块类中看到此示例。
#File: app/code/core/Mage/Tag/Block/Customer/View.php    
...
public function getTagInfo()
{
    if (is_null($this->_tagInfo)) {
        $this->_tagInfo = Mage::getModel('tag/tag')
            ->load($this->getTagId());
    }
    return $this->_tagInfo;
}    
...

这里,该块的getTagInfo方法直接向模型请求信息。这样,前端模板开发人员就可以访问到该信息。
$this->getTagInfo();

方法。我还得到了可靠的消息,一个块的_prepareLayout方法是把大部分甚至所有数据获取代码放在块中的完美位置。

你会看到使用的第二个模式是Magento注册表模式。这是Magento系统,允许您设置系统范围内(但不是PHP)的全局变量。

Mage::register('foo', 'some value');
echo Mage::registry('foo');

有时候,Magento开发人员会使用注册表在控制器操作中设置一个变量,然后在区块中取回它。例如,在管理控制台的发票控制器中。
#File: app/code/core/Mage/Adminhtml/controllers/Sales/Order/InvoiceController.php
protected function _initInvoice()
{
    ...
    $invoice = Mage::register('current_invoice', $invoice);
    return $invoice;
}    

然后一个块将稍后引用它。
#File: app/code/core/Mage/Sales/Block/Order/Print/Invoice.php
public function getInvoice()
{
    return Mage::registry('current_invoice');
}

我不是很喜欢注册表模式,但它被核心团队使用,所以可能是合适的。
最后,如果你想要模仿大多数PHP MVC框架中使用的“愚蠢视图”模式,请尝试类似于这样的东西。
$this->loadLayout();
$block = $this->getLayout()->getBlock('block_name');
$block->setSomeData('My Data');
$block->setData('alternate_syntax', 'Some other data');
$this->renderLayout();

然后在区块和/或模板文件中。

echo $this->getSomeData();
echo $this->getData('some_data');

echo $this->getAlternateSyntax();
echo $this->getData('alternate_syntax');

在调用loadLayout之后,Magento将创建所有块对象。您上面所做的是获取对特定块对象的引用,然后设置其数据。
根据Vinai在下面的评论中提到的,还需要考虑块的assign方法。
类似于setData,在调用loadLayout(或从块的_prepareLayout方法)之后,您可以执行以下操作:
$this->loadLayout();
$block = $this->getLayout()->getBlock('block_name');
$block->assign('my_view_var','Something for the view');
$this->renderLayout();

然后在您块的phtml文件中,您将能够输出该视图变量

echo $my_view_var;

1
Alan,我们应该开始协调了。你的回复是最好的,因为它回答了OP隐含的问题,也就是“Magento,Y U NO RENDER LIKE MOST PHP MVC?” 这是我们所有人都问过的问题... :-D - benmarks
1
谢谢Alan,你总结得很好!我能想到的唯一要补充的是模板块的assign()方法。虽然很少使用,但有些人更喜欢它而不是setData(),因为它符合经典的“分配模板变量”的方法。 - Vinai
谢谢Alan。非常好的解释,解决了我大部分的疑惑。 - Ricky Sharma
Alan:非常感谢你。每当我有疑问时,谷歌搜索总是能带我找到你的答案。 :) - zamil

3
  1. 正确,通过前端控制器和路由器实现
  2. 不完全正确。Magento的ViewModel实现部分得益于视图(块)自己实例化其模型。
  3. 是的,通过资源模型实现。

当块通过典型的$this->loadLayout()->renderLayout()流在动作控制器中呈现时,如果它们使用模板,则这些模板将在呈现时include()

renderLayout()调用后,执行仍在我们分派到的控制器操作范围内,因此您可以通过获取请求对象来访问已呈现的响应。

关键情节:

  1. index.php调用Mage::run()
  2. Mage::run调用Mage_Core_Model_App::run()
  3. App::run()调用Mage_Core_Controller_Varien_Front,首先是其init()方法,该方法收集并设置路由器,然后是dispatch(),它执行以下操作:

    a. 数据库URL重写

    b. 配置重写(已弃用)

    c. 通过路由器匹配正确的控制器操作。执行从前端控制器跳转到动作控制器。使用布局或手动调用块将执行传递给块类、模型和模板,然后(通常)返回到控制器操作。

    d. 发送响应对象(假设已被动作控制器修改)。

如果您查看Mage_Core_Controller_Varien_Front::dispatch();,您将看到对$this->getResponse()->sendResponse();的调用,该调用将刷新输出,并在之前触发一个事件(controller_front_send_response_before),该事件可用作挂钩以添加或操作任何与响应相关的内容。


1

不是的,它离开控制器(控制请求的那个)然后移动到视图中进行渲染。一旦视图(块)已经渲染完毕,请求基本上就结束了(除了大多数URL助手之外,在视图呈现后有时会在控制器中处理,但没有逻辑可言)。除非你之后触发了某种钩子。

我使用这个流程图这个系列(Alan Storm是专家)来学习Magento请求路由。


1
从技术上讲,Typical request到渲染工作流使用renderLayout(),之后执行继续在控制器操作中。一般情况下,不太可能在renderLayout()之后的控制器操作中改变响应对象,因此下一行通常是该方法的结束,并因此返回到前端控制器。/hairsplit - benmarks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接