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

Posted

技术标签:

【中文标题】在 Magento 中,块如何从模型中获取数据?【英文标题】:In Magento, how do Blocks Grab Data from Models? 【发布时间】:2012-03-19 01:03:52 【问题描述】:

有人可以解释一下吗?

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

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

之后会发生什么?

    模型如何向 Blocks 传输数据,或者 Blocks 如何从模型中获取数据?

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

    另外,请求是否会再次返回到控制器?

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

【问题讨论】:

【参考方案1】:

没有任何东西将数据传输到块。在控制器动作完成其模型交互后,它负责

    加载布局对象(间接加载和创建块对象)

    告诉该布局对象呈现一个页面。

大多数 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();

方法。我还在good authority 上指出,块的_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;
    

然后一个 Block 稍后会引用它。

#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 的 cmets,还有一个块的 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;

【讨论】:

艾伦,我们应该开始协调了。您的回答是最好的,因为它回答了 OP 的隐含问题,即“Magento,你不会像大多数 PHP MVC 一样渲染?”,这是我们都问过的问题...... :-D 谢谢艾伦,你总结得很好!我能想到的唯一要添加的是模板块的assign() 方法。很少使用,但有些人更喜欢它而不是 setData(),因为它与经典的“分配模板变量”方法相匹配。 谢谢艾伦。很好的解释,消除了我的大部分疑虑。 艾伦:我非常感谢你。当我有疑问时,谷歌搜索会带我得到你的答案。 :)【参考方案2】:
    正确,通过前端控制器和路由器 不完全是。 Magento 的 ViewModel 实现部分是通过让视图(块)实例化它们自己的模型来促进的。 是的,通过资源模型。

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

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

关键情节点:

    index.php 调用Mage::run() Mage::run 致电Mage_Core_Model_App::run()

    App::run() 调用Mage_Core_Controller_Varien_Front,首先它的init() 方法收集和设置路由器,然后dispatch() 执行以下操作:

    一个。数据库 URL 重写

    b.配置重写(已弃用)

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

    d。发送响应对象(假设它已被操作控制器更改)。

如果您查看Mage_Core_Controller_Varien_Front::dispatch(); you'll see the call to$this->getResponse()->sendResponse();`,它将刷新输出,前面是一个事件 (controller_front_send_response_before),该事件可用作添加或操作任何响应的钩子-相关。

【讨论】:

【参考方案3】:

不,它会离开控制器(控制请求的控制器),然后移动到视图,并在那里呈现它。一旦视图(块 [s])呈现,请求基本上就结束了(除了大多数 url 助手,它们没有逻辑可言,但有时在视图呈现后在控制器中处理。)除非你有某种之后触发钩子。

我使用 this flowchart 和 this series(Alan Storm 是 家伙)来了解 Magento 请求路由。

【讨论】:

技术上,渲染工作流的典型请求使用renderLayout(),之后在控制器操作中继续执行。在renderLayout() 之后的控制器操作中更改响应对象的情况并不常见,因此下一行通常是方法的结尾,因此返回到前端控制器。 /头发分裂

以上是关于在 Magento 中,块如何从模型中获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

php Magento 2:从phtml上的块获取当前URL

如何从产品页面中删除“标签”块?

了解 Magento 块和块类型

如何在 Magento 中重新加载块?

如何在magento管理站点块中翻译变量

如何在类别产品列表底部的 magento 2.1.8 中移动静态块