linusshops/iddqd

此包已被废弃,不再维护。没有建议的替代包。

使用事件监听器对 Magento 的 XML 配置进行编程控制。

安装: 21

依赖: 0

建议者: 0

安全: 0

星标: 3

关注者: 6

分支: 0

开放问题: 0

类型:magento-module

dev-develop 2015-07-30 20:57 UTC

This package is not auto-updated.

Last update: 2022-04-30 05:21:07 UTC


README

此模块的目的是以编程方式拦截 Magento 操作中所有配置 *.xml 文件合并和解析后的 XML 对象表示,并实时修改它。这具有不可思议的强大效果。

为什么?

Magento 开发中常见的挑战是引入第三方模块。其中大多数都很糟糕。这里就不展开了。这些第三方模块通常争夺扩展核心 Magento 类的权力,但遗憾的是,Magento 并没有提供方便的控制方法。在这种多个模块重写相同类的情况中,只有一个能够幸存,它的名字总是 Zoidberg。

社区帮助论坛中的共识是修改这些模块,直到它们变成一种共生代码的尼斯湖怪物——希望永远不要被严格审查的锐利目光看到——但更常见的说法是一个散发着恶臭的 💩。在 Magento 世界中有很多这样的东西。

另一个更干净的解决方案是创建一种中间件或适配器模块,作为两个模块交互的公共基础。最终,Magento 将无法满足这一要求。虽然这种方法确保了两个模块都可以不受干扰,从而便于它们更新,但仍然需要编写大量冗余的适配器代码。

iddqd 尝试使这一过程变得更加容易。例如,考虑两个修改分层导航的模块。这两个模块重写非常相似或相同的类,但它们各自都有非常具体和上下文相关的需求。一个模块应该只修改标准类别列表上的分层导航,而另一个模块应该只修改搜索结果列表上的分层导航。 iddqd 使这成为可能。

iddqd 使在 Magento 中根据上下文实例化类成为可能。

动力

当试图在 config.xml 文件中的 <rewrite> 节点添加自定义 XML 属性 ifcontroller="someController" 以实现两个重写相同核心类的不同模块的干净集成时,产生了这种解决方案的需求。这似乎不是一项富有成效的事业,但抛出事件在类被命名之前的可能性,似乎为这种魔法提供了良好的机会。

如何?

这是通过简单重写 Mage_Core_Model_Config 类中的 getGroupedClassName 方法实现的。该类负责决定一个类是否被模块重写。如果模块中提供了 <rewrite>,则该方法确定对于给定的组件,如果存在重写的类,则使用重写的类,否则回退到 Magento 默认值。iddqd 重写该方法,在确定类重写是否有效之前立即插入一个事件分发器;整个 XML 表示形式通过引用作为事件数据传递,然后可以在任何其他模块中观察,此时可以无限制地操作 XML 表示形式,最后将其最终传递回原始流程。

重写只是一个简单的例子。对于 Magento 实例化哪些类,iddqd 不会施加任何限制。

安装

应该使用 Composer 进行安装。magento 构建还应包括 Magento Composer Installer。此模块遵循 Firegento 提供的模块结构指南,这将使将其提交到 Firegento Composer Repository 变得非常容易。

警告

Magento 不允许直接重写 Mage_Core_Model_Config 类。这是因为它是 Magento 正确运行的基础,如果重写不当,Magento 将会完全失败。然而,Magento 确实创建了一种修改它的方法,这是一种非常明确的、我知道我在做什么因为我是一名专业人员的类型。如果还不清楚,这是一个实验性模块。如果此模块中应用的技巧看起来像是黑魔法,则不建议安装。这是为高级 Magento 开发准备的。

写到这里,最后一步是修改 Magento 的 index.php 文件,将其最后一行替换为以下内容

Mage::run($mageRunCode, $mageRunType, array('config_model' => 'Linus_Iddqd_Model_Config'));

使用(即有趣的部分)

在新的模块中,例如,在作为多个模块协调方式的适配器模块中,创建观察以下自定义事件的必要模板

before_configxml_rewrite

此事件将通过引用传递一个新的 Varien_Object,其中包含事件有效负载数据,然后可以在将控制流程返回到原始方法之前对其进行操作。阅读源代码以了解传递了哪些数据。

etc/config.xml

<global>
    ...
    <events>
        <before_configxml_rewrite>
            <observers>
                <linus_example>
                    <type>singleton</type>
                    <class>Linus_Example_Model_Observer</class>
                    <method>onBeforeConfigxmlRewrite</method>
                </linus_example>
            </observers>
        </before_configxml_rewrite>
    </events>
    ...
</global>

Model/Observer.php

public function onBeforeConfigxmlRewrite(Varien_Event_Observer $observer)
{
    // Get event.
    $event = $observer->getEvent();

    // Get Varien_Object event data.
    $config = $event->getConfig();
    
    /** @var Linus_Iddqd_Model_Config $instance */
    $instance = $config->getInstance();
    $class = $config->getClass();
    $group = $config->getGroup();

    /** @var Mage_Core_Model_Config_Element $configXml */
    $configXml = $instance->getXml(); // Custom Linus_Iddqd method.

    // Retrieve ANY path IN ENTIRE UNIVERSE.
    $catalogModel = $configXml->descend('global/models/catalog');

    // Because you disagree with the chosen class path, SET YOUR OWN.
    $configXml->setNode('global/models/catalog/class', 'Linus_CoolerModule_Something_Something');
    // Or this for short.
    $catalogModel->setNode('class', 'Linus_CoolerModule_Something_Something');
    
    // Get all rewrites for provided path, and pass whatever other classes
    // should be instantiated instead.
    $catalogRewrites = $configXml->descend('global/models/catalog/rewrite');
    $catalogRewrites->setNode('layer_filter_attribute' => 'A_Better_Class');
    
    // ...or just obliterate them, causing Magento to use built-in core classes.
    unset($catalogRewrites->layer_filter_attribute);
    unset($catalogRewrites->layer_filter_category);
    unset($catalogRewrites->layer_filter_item);
    
    // Maybe you just want to modify classes and rewrites on a given page.
    if (stripos(Mage::app()->getRequest()->getRequestUri(), 'helmets') !== false) {
        // https://i.imgur.com/Re3Ti2c.jpg
    }
    
    // Custom Linus_Iddqd methods:
    
    // Merge in new config.xml.
    $instance->mergeConfig('path/to/custom/config.xml');
    
    // Rewrite a class, or multiple.
    $instance
        ->rewriteClass('global/models/catalog/rewrite/layer_filter_attribute', 'Linus_Better_Class')
        ->rewriteClass('global/models/catalog/class', 'Linus_CoolerModule_Something_Something');

    // Delete class. It does not need to be a rewrite. It can be any of them.
    $instance->deleteClass('global/models/catalog/rewrite', 'layer_filter_attribute');
}

花点时间。这是你的大脑被震撼的感觉。

##布局注入器还可能需要根据请求上下文注入基于布局的 XML。如上所述,在布局中,当两个模块试图在不同的上下文中修改布局时,这个事件允许你注入上下文布局 XML 以使模块一起工作(同样,在适配器模块的上下文中很有用)。

IDDQD 在构建布局更新 XML 的类中抛出事件,该 XML 包含了你的所有模块。观察此事件允许你在合并 XML 构建之前添加额外的布局更新 XML 文件。可以根据程序规则添加这些额外的文件,从而让你完全控制使用的布局。

###使用方法如上所述,创建观察者模板,观察 before_layoutxml_compile 事件。

etc/config.xml

<global>
    ...
    <events>
        <before_layoutxml_compile>
            <observers>
                <linus_example>
                    <type>singleton</type>
                    <class>Linus_Example_Model_Observer</class>
                    <method>onBeforeLayoutXmlCompile</method>
                </linus_example>
            </observers>
        </before_layoutxml_compile>
    </events>
    ...
</global>

Model/Observer.php

public function onBeforeLayoutXmlCompile(Varien_Event_Observer $observer)
{
	/** @var Linus_Iddqd_Model_Layout_Update $godMode */
	$godMode = $observer->getGodMode();
	//Append the specified layout xml to your layout stack. Since it
	//is processed last, its rules will update everything else.
	if ($someCondition) {
		$godMode->addLayoutUpdate($observer, 'my_contextual_layout.xml');
	} else {
		//Or maybe it's some other context, so we'll use this instead.
		$godMode->addLayoutUpdate($observer, 'different_contextual_layout.xml');
	}
}

待办事项

  • 添加助手以使设置和取消设置类以及重写变得更加容易。

作者

丹·麦克米伦

贡献者

塞缪尔·施密特

名称的起源

iddqd 对90年代在PC上玩游戏的任何人来说都很明显。这是什么意思?这意味着你在使用 上帝模式,没有什么能阻止你。这也是这个模块的作用。

许可协议

此模块由林纳斯·斯霍普斯创建,并热情地向 Magento 社区授予了 MIT 许可协议