【问题标题】:Magento: call a custom block in CMSMagento:在 CMS 中调用自定义块
【发布时间】:2015-08-15 10:11:10
【问题描述】:

我正在尝试为 Magento 1.9.1 创建自己的模块。在我的模块中,我试图在 CMS 内容中调用一个块,如下所示:

{{block type="core/template" template="myNamespace/myModulOutput.phtml"}}

myModulOutput.phtml 模板包含来自我自己的控制器的集合:

class myNamespace_myModelname_Block extends Mage_Core_Block_Template
{
    public function getCollection()
    {
       // some code
        return $collection;
    }
}

该模块似乎处于活动状态,并使用此配置显示在 Magento 后端:

<config>
    <modules>
        <myNamespace_myModulname>
            <version>0.1.0</version>
        </myNamespace_myModulname>
    </modules>
    <global>
        <blocks>
            <myNamespace_myModulname> 
                <class>myNamespace_myModulname_Block</class>
            </myNamespace_myModulname>
        </blocks>
    </global>
</config>

块类在文件app/code/local/myNamespace/myModulname/Blocks/Index.php中定义。

这是一个有效的配置吗?我在前端遇到错误:Fatal error: Call to a member function getCollection() on a non-object。

编辑

已解决

通过@b.enoit.be 的解释,我尝试了以下设置...它运行了 ;-)

app/etc/modules/Mynamespace_Mymodulname.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <Mynamespace_Mymodulname>
            <active>true</active>
            <codePool>local</codePool>
            <depends/>
        </Mynamespace_Mymodulname>
    </modules>
</config>

app/code/local/Mynamespace/Mymodulname/Block/Index.php:

    <?php
    class Mynamespace_Mymodulname_Block_Index extends Mage_Core_Block_Template
    {
        public function getTest()
        {
           // some code
            return "mymodul:test";
        }
    }
    ?>

app/code/local/Mynamespace/Mymodulname/etc/config.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <Mynamespace_Mymodulname>
            <version>0.1.0</version>
        </Mynamespace_Mymodulname >
    </modules>
    <global>
        <blocks>
            <mynamespace_mymodulname> 
                <class>Mynamespace_Mymodulname_Block</class>
            </mynamespace_mymodulname >
        </blocks>
    </global>
</config>

CMS 调用

{{block type="mynamespace_mymodulname/index" template="mynamespace/myoutput.phtml"}}

app/design/frontend/myTheme/default/mynamespace/myoutput.phtml:

<?php /** @var $this Mynamespace_Mymodulname_Block_Index */ ?>
<?php echo $this->getTest() ?>

非常感谢您提供如此详细而有意义的解释:-)

【问题讨论】:

  • 看起来你正在混淆控制器和块

标签: php magento module magento-layout-xml


【解决方案1】:

如果那些myNamespace_myModulname 真的是你实际代码中的内容,请先看看@fantasticrice answer

然后,如果我们认为您的代码具有正确的命名约定(请参阅本文末尾的注释),首先,这不是一个有效的块类:

class Mynamespace_Mymodulename_Block extends Mage_Core_Block_Template{ /* ... */ }

如果像您稍后所说的那样,您的文件位于

app/code/local/Mynamespace/Mymodulename/Block/Index.php

那么有效的块类是

class Mynamespace_Mymodulename_Block_Index extends Mage_Core_Block_Template{ /* ... */ }

因为 Magento 中的类名应该始终遵循与文件路径完全相同的体系结构(控制器除外,但我们在这里提供的代码根本不是在谈论控制器)= >

class Mynamespace_Mymodulename_Block_Index === Mynamespace/Mymodulename/Block/Index.php

(看看我是如何用斜杠替换下划线并用.php 扩展后缀的?)。

那么你真正想要的是你的观点mynamespace/mymoduleoutput.phtml 使用你自己的模块块。
为此,您必须为您的块指定正确的 type。

类型由 config.xml 中定义的句柄和块文件的路径的组合定义。

1。手柄

当您为模块定义 config.xml 时,您必须注意有些部分是“固定”,而有些部分是“句柄”。
这意味着 Magento 期望某些部分具有有限的可能性,例如frontend or adminhtml or global、blocks, models, helpers, ... there is more here 和一些只是为您的模块命名并在 Magento 下调用或处理模块的名称。

您在 config.xml 中说,对于 &lt;global&gt; 配置(前端和后端(= 管理员)的意思)--已修复--您想添加到现有的&lt;blocks&gt; -- fixed -- Magento 的模块块将被 -- handle -- &lt;mynamespace_mymodulename&gt; 然后将映射到所有类都以Mynamespace_Mymodulename_Block 开头的文件。

这是您自己的模块块所需的 type 的第一部分。
mynamespace_mymodulename 在 Magento 中等同于 Mynamespace_Mymodulename_Block

2。右块

然后您只需指出从 Blocks 的根文件夹到 Magento 的正确路径,这将再次与您的文件夹/文件架构完全相同:所以在您的情况下,只需 index。
正如您现在可能理解的那样,Magento 将在文件Mynamespace/Mymodulename/Block/Index.php 中查找类Mynamespace_Mymodulename_Block_Index(句柄+'_'+指定块),如前所述。
但是,如果您的文件在app/code/local/Mynamespace/Mymodulename/Block/Path/To/File.php 下,您将拥有path_to_file => 类Mynamespace_Mymodulename_Block_Path_To_File,文件Mynamespace/Mymodulename/Block/Path/To/File.php

现在我们有了 type 的第二部分,我们只需要用斜线将它们组合起来:mynamespace_mymodulename/index

因此,您必须将您的 cms 中的呼叫更改为:

{{block type="mynamespace_mymodulename/index" template="mynamespace/mymoduleoutput.phtml"}}

希望有了这个,它会起作用。

注意 1/3: 正如 @fantasticrice 所指出的,我还建议您遵循类的命名约定:

Zend 框架标准化了一个类命名约定,其中 类的名称直接映射到它们所在的目录 存储。 (...)

类名只能包含字母数字字符。编号是 在类名中允许,但在大多数情况下不鼓励。 下划线只能代替路径分隔符;这 文件名“Zend/Db/Table.php”必须映射到类名 “Zend_Db_Table”。

如果类名由多个单词组成,则第一个字母 每个生词必须大写。连续大写字母 不允许,例如一个类“Zend_PDF”是不允许的,而 “Zend_Pdf”是可以接受的。

这些约定为 Zend 定义了一个伪命名空间机制 框架。 Zend Framework 将采用 PHP 命名空间特性 变得可用并且对我们的开发人员来说是可行的 应用程序。

查看标准库和附加库中的类名以获取示例 这个类名约定。

来源:http://framework.zend.com/manual/1.12/en/coding-standard.naming-conventions.html

注意 2/3: 再次按照惯例,只有类将具有大写的文件名/文件夹结构。所以,你的模板文件夹和文件根本不应该有大写。

注意 3/3 :在 Magento 中,再次按照惯例,我们不在句柄中使用大写字母。


TL;DR

app/code/local/Mynamespace/Mymodulename/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Mynamespace_Mymodulename>
            <version>0.1.0</version>
        </Mynamespace_Mymodulename>
    </modules>
    <global>
        <blocks>
            <mynamespace_mymodulename> 
                <class>Mynamespace_Mymodulename_Block</class>
            </mynamespace_mymodulename>
        </blocks>
    </global>
</config>

app/code/local/Mynamespace/Mymodulename/Block/Index.php

<?php
class Mynamespace_Mymodulename_Block_Index extends Mage_Core_Block_Template
{
    public function getCollection()
    {
       // some code
        return $collection;
    }
}

CMS 内容

{{block type="mynamespace_mymodulename/index" template="mynamespace/mymoduleoutput.phtml"}}

app/etc/modules/Mynamespace_Mymodulename.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Mynamespace_Mymodulename>
            <active>true</active>
            <codePool>local</codePool>
            <depends/>
        </Mynamespace_Mymodulename>
    </modules>
</config>

app/design/frontend/base/default/template/mynamespace/mymoduleoutput.phtml

<?php /** @var $this Mynamespace_Mymodulename_Block_Index */ ?>
<?php foreach($this->getCollection() as $item): ?>
    <?php //do something ?>
<?php endforeach; ?>

【讨论】:

  • 很好的答案,但我认为你是must use uppercase names on the path due to ucwords() in the autoloader。因此,类名的约定通常匹配,Begin_Each_Part 为大写。
  • @fantasticrice 我肯定会完全支持你,因为这是从 Zend Framework 继承的命名约定,并且作为约定,它应该始终被遵循。但可悲的是,class name are insensitive in php 等等,这不是 OP 问题的一部分。
  • 是的,我知道类名不区分大小写,这就是为什么类命名只是一种约定而不是强制性的原因。正如我所提到的, path (可能)区分大小写。请参阅我发布的链接中的自动加载器代码,其中子目录名称使用ucwords() 解析。因此,虽然类可能是 camelCase_moduleName,但目录将呈现为 CamelCase/ModuleName。
  • 很好看。但是那些myNamespace 和myModulname 真的看起来像是改头换面的,我在回答时倾向于不涉及它们,因为大多数人会隐藏他们实际拥有的真正的companyName / customerName。您的观点仍然有效。
  • @fantasticrice 很好,当我读回该代码时,如果不遵守约定,我不禁会发现它很丑陋。所以我自己清理了一下,现在我觉得看起来不错。 :)
【解决方案2】:

我注意到这里有几个问题,所以我将尝试解决您在问题中发布的内容可以看到的问题,尽管您要完成的工作并不完全清楚,您会阅读guide about Magento’s layout, blocks, and templates 可能受益最大:

  1. 您当前的类名不遵循Magento autoloader naming conventions,您会注意到在每个路径元素上使用ucwords()。你的类名应该是这样的:Mynamespace_Mymodulename_Block_Myblockname,它会映射到文件app/code/.../Mynamespace/Mymodulename/Block/Myblockname.php。您的配置 XML 应更新以匹配。

  2. 您的 CMS 指令目前没有使用您的新块类型,因为如果您希望在模板中使用块的自定义逻辑,它应该设置为 type="core/template",而它应该是 type="Mynamespace_Mymodulename/Myblockname"。您的模板代码未显示,但这可能是在您的模板中调用 getCollection() 不起作用的原因。

如果您展示更多作品,我们或许可以提供更多帮助。

【讨论】:

    猜你喜欢
    • 2010-11-26
    • 2016-06-23
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多