Magento: call a custom block in CMS

戏子无情 提交于 2019-12-25 03:42:25

问题


I’m trying to create my own module for Magento 1.9.1. In my module, I am trying to call a block in CMS content like this:

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

The myModulOutput.phtml template contains a collection from my own controller:

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

The module seems to be active and shows up in Magento backend with this configuration:

<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>

The block class is defined in the file app/code/local/myNamespace/myModulname/Blocks/Index.php.

Is this a valid configuration? I am getting an error on the frontend: Fatal error: Call to a member function getCollection() on a non-object.

EDIT

SOLVED

By explanation from @b.enoit.be I tried the following setting ... it's run ;-)

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-Call

{{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() ?>

Many thanks for so detailed and meaningful explanation :-)


回答1:


If those myNamespace_myModulname are really what you have in your actual code, please first have a look at @fantasticrice answer

Then, if we consider your code with the right naming convention (see note in the end of this post), to start up with, this is not a valid block class :

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

If, like you say it later on, your file is located in

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

then the valid block class is

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

Because class name in Magento should always follow the exact same architecture as your path to file (except for controllers, but we are not talking about controllers at all with the code you gave us here) =>

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

(see how I just replaced underscore with slashes and postfixed this with a .php extension ?).

Then what you actually want is your your view mynamespace/mymoduleoutput.phtml to use your own module block.
For this, you have to specify the right type for your block.

The type is defined by a combinaison of your handle defined in config.xml and from the path to your block file.

1. The handle

When you define a config.xml for a module, you have to be aware that some part are "fixed" and some parts are "handles".
Meaning that some parts are expected by Magento to be in a limited number of possibilities e.g. frontend or adminhtml or global, blocks, models, helpers, ... there is more here and some are just name to alias your module and to call it or handle as we call that under Magento.

Here you say in your config.xml that for the <global> config (means for both frontend and backend (= admin)) -- fixed -- you want to add to the list of existing <blocks> -- fixed -- of Magento the blocks of your module that would be referenced by the -- handle -- <mynamespace_mymodulename> which will then map to files in which the classes will all begin with Mynamespace_Mymodulename_Block.

That is the first part of the type you want for your own module block.
mynamespace_mymodulename would be equivalent for Magento to Mynamespace_Mymodulename_Block

2. The right block

Then you just have to indicate the right path from the root folder of your Blocks to Magento, which will be the exact same as your folders/files architecture, once again : so in your case, just index.
So as you may now understand, Magento will lookup to a class Mynamespace_Mymodulename_Block_Index (handle + '_' + specified block) in the file Mynamespace/Mymodulename/Block/Index.php as seen earlier.
But if your file was under app/code/local/Mynamespace/Mymodulename/Block/Path/To/File.php you would have path_to_file => class Mynamespace_Mymodulename_Block_Path_To_File, file Mynamespace/Mymodulename/Block/Path/To/File.php

Now that we have the second part of our type we just have to assemble them with a slash : mynamespace_mymodulename/index

So you have to change your call in your cms to :

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

And hopefully, with this, it would work.

NOTE 1/3 : As pointed out by @fantasticrice, I would also suggest you to follow the naming convention of class:

Zend Framework standardizes on a class naming convention whereby the names of the classes directly map to the directories in which they are stored. (...)

Class names may only contain alphanumeric characters. Numbers are permitted in class names but are discouraged in most cases. Underscores are only permitted in place of the path separator; the filename "Zend/Db/Table.php" must map to the class name "Zend_Db_Table".

If a class name is comprised of more than one word, the first letter of each new word must be capitalized. Successive capitalized letters are not allowed, e.g. a class "Zend_PDF" is not allowed while "Zend_Pdf" is acceptable.

These conventions define a pseudo-namespace mechanism for Zend Framework. Zend Framework will adopt the PHP namespace feature when it becomes available and is feasible for our developers to use in their applications.

See the class names in the standard and extras libraries for examples of this classname convention.

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

NOTE 2/3 : that per convention again, only class are going to have a capitalised file name / folder structure. So, your template folders and files should not have capital in it at all.

NOTE 3/3 : In Magento, again, per convention we do not use capitals in handles.


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 content

{{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; ?>



回答2:


There are a couple issues here that I notice, so I will just try to address the ones that can be seen by what you have posted in your question, although what you are trying to accomplish is not totally clear, and you would probably benefit most from reading a guide about Magento’s layout, blocks, and templates:

  1. Your current class names do not follow the Magento autoloader naming conventions, which you’ll notice use ucwords() on each path element. Your class name should be something like: Mynamespace_Mymodulename_Block_Myblockname, which would map to the file app/code/.../Mynamespace/Mymodulename/Block/Myblockname.php. Your config XML should be updated to match.

  2. Your CMS directive currently doesn’t make use of your new block type since it is set to type="core/template" when it should be type="Mynamespace_Mymodulename/Myblockname" if you wish to make use of your block’s custom logic in your template. Your template’s code is not shown, but this is likely why calling getCollection() in your template isn’t working.

If you show more of your work, we might be able to help more.



来源:https://stackoverflow.com/questions/30582169/magento-call-a-custom-block-in-cms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!