简体   繁体   English

覆盖Prestashop模块控制器:哪里放置php文件?

[英]Override Prestashop Module Controller: Where to place php file?

I am attempting to override a module in Prestashop. 我试图覆盖Prestashop中的模块。 I have successfully overridden the modules' templates but I cannot successfully overwrite the modules' controller. 我已经成功覆盖了模块的模板,但是无法成功覆盖模块的控制器。

Where should the new controller class file be placed? 新的控制器类文件应放在何处?

I have tried the following locations but they dont add new behaviour (change anything): 我尝试了以下位置,但它们未添加新行为(更改任何内容):

~/overrides/modules/blockwishlist/controllers/front/mywishlist.php 〜/ overrides / modules / blockwishlist / controllers / front / mywishlist.php
~/themes/MY_THEME/modules/blockwishlist/controllers/front/mywishlist.php 〜/ themes / MY_THEME / modules / blockwishlist / controllers / front / mywishlist.php

According to my previous question I could do it by editing core classes (suggested kindly by u/Sergii P) but I am sure there is a standard way to do this that doesn't involve editing core classes? 根据我之前的问题,我可以通过编辑核心类(由u / Sergii P推荐)来做到这一点,但是我确定有一种标准方法可以实现,而无需编辑核心类?

For reference; 以供参考; here is the contents of mywishlist.php : 这是mywishlist.php的内容:

<?php

if (!defined('_CAN_LOAD_FILES_'))
    exit;

//class BlockWishListMyWishListModuleFrontController extends BlockWishListMyWishListModuleFrontControllerCore // extends ModuleFrontController
class BlockWishListMyWishListModuleFrontControllerOverride extends BlockWishListMyWishListModuleFrontController
{

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Assign wishlist template
     */
    public function assign()
    {
        $errors = array();

        ....

        $this->setTemplate('mywishlist.tpl');
    }

}

EDIT: I have a possible workaround for not being able to override the ModuleFrontController class. 编辑:我有一个可能的解决方法,无法覆盖ModuleFrontController类。 The objective is to add an 'Export to CSV' button to the My Wishlists page, when the button is clicked the server will generate a CSV file containing all products in that wishlist. 目的是在“我的愿望清单”页面上添加一个“导出到CSV”按钮,单击该按钮时,服务器将生成一个包含该愿望清单中所有产品的CSV文件。 Before I do all the work, can you provide advice on whether this is possible... 在我完成所有工作之前,您能否提供关于是否可行的建议?

  • Place hook in template file that will call a custom hook and be linked to a custom module {hook h='displayExportToCsvColumn' mod='myCustomModule'} 将挂钩放置在将调用定制挂钩并链接到定制模块的模板文件中{hook h='displayExportToCsvColumn' mod='myCustomModule'}
  • Create a custom module that registers the new hook, has a method that renders the table column and button and has a method that generates the CSV file. 创建一个注册新钩子的自定义模块,创建一个呈现表列和按钮的方法,并生成一个CSV文件。
  • Big Question: can you have a module inside a module? 大问题:您可以在模块内部有一个模块吗? The template file I am editting is inside the module BlockWishlist ( ~/themes/MY_THEME/modules/blockwishlist/controllers/front/mywishlist.php ) and then my hook will call my custom module. 我正在编辑的模板文件位于模块BlockWishlist〜/ themes / MY_THEME / modules / blockwishlist / controllers / front / mywishlist.php ),然后我的钩子将调用我的自定义模块。 Is this possible? 这可能吗?

As far as I could work out, you can't override ModuleFrontController at the moment (sorry to say). 据我ModuleFrontController ,您目前无法覆盖ModuleFrontController (对不起)。 The clues lie within Dispatcher::dispatch() : 线索位于Dispatcher::dispatch()

    case self::FC_MODULE :
        $module_name = Validate::isModuleName(Tools::getValue('module')) ? Tools::getValue('module') : '';
        $module = Module::getInstanceByName($module_name);
        $controller_class = 'PageNotFoundController';
        if (Validate::isLoadedObject($module) && $module->active) {
            $controllers = Dispatcher::getControllers(_PS_MODULE_DIR_.$module_name.'/controllers/front/');
            if (isset($controllers[strtolower($this->controller)])) {
                include_once(_PS_MODULE_DIR_.$module_name.'/controllers/front/'.$this->controller.'.php');
                $controller_class = $module_name.$this->controller.'ModuleFrontController';
            }
        }
        $params_hook_action_dispatcher = array('controller_type' => self::FC_FRONT, 'controller_class' => $controller_class, 'is_module' => 1);
    break;

It only checks the /modules/?/controllers/ directory. 它仅检查/modules/?/controllers/目录。 You can't override the ModuleFrontController classes, but if you're smart enough, you can override Dispatcher class and make it scan for overrides of ModuleFrontController . 您不能覆盖ModuleFrontController类,但是如果您足够聪明,则可以覆盖Dispatcher类并使它扫描ModuleFrontController覆盖。

Usually there is a way to alter things you want with hooks, worst case scenario - inject javascript via hook and alter content. 通常,在最坏的情况下,有一种方法可以用钩子来更改所需的东西-通过钩子注入javascript并更改内容。

Hey I've struggled with this issue aswell. 嘿,我也在这个问题上苦苦挣扎。 I ended up spotting a solution on the prestashop forums : https://www.prestashop.com/forums/topic/480523-override-front-controller-of-modules/ 我最终在prestashop论坛上发现了一个解决方案: https : //www.prestashop.com/forums/topic/480523-override-front-controller-of-modules/

The user Alex has created a override for the Dispatcher that will check for any module controller overrides. 用户Alex已为Dispatcher创建一个替代,它将检查是否有任何模块控制器替代。

The file does not seem to be available on the forum anymore you can however still find it here along with some explanations on how it works : http://nemops.com/overriding-modules-controllers-in-prestashop-1-6/#.XDR7HHX0muU 该文件似乎不再在论坛上可用,但是您仍然可以在这里找到它,以及有关其工作原理的一些解释: http : //nemops.com/overriding-modules-controllers-in-prestashop-1-6/ #.XDR7HHX0muU

In case none of those work anymore here is the code : 如果这些都不起作用,则代码如下:

    <?php

if (!defined('_PS_VERSION_')) {
    exit;
}

class Dispatcher extends DispatcherCore
{

    public function dispatch()
    {
        $controller_class = '';

        // Get current controller
        $this->getController();
        if (!$this->controller) {
            $this->controller = $this->useDefaultController();
        }
        // Dispatch with right front controller
        switch ($this->front_controller) {
            // Dispatch front office controller
            case self::FC_FRONT :
                $controllers = Dispatcher::getControllers(
                    array(_PS_FRONT_CONTROLLER_DIR_, _PS_OVERRIDE_DIR_.'controllers/front/')
                );
                $controllers['index'] = 'IndexController';
                if (isset($controllers['auth'])) {
                    $controllers['authentication'] = $controllers['auth'];
                }
                if (isset($controllers['compare'])) {
                    $controllers['productscomparison'] = $controllers['compare'];
                }
                if (isset($controllers['contact'])) {
                    $controllers['contactform'] = $controllers['contact'];
                }

                if (!isset($controllers[strtolower($this->controller)])) {
                    $this->controller = $this->controller_not_found;
                }
                $controller_class = $controllers[strtolower($this->controller)];
                $params_hook_action_dispatcher = array(
                    'controller_type' => self::FC_FRONT,
                    'controller_class' => $controller_class,
                    'is_module' => 0,
                );
                break;

            // Dispatch module controller for front office
            case self::FC_MODULE :
                $module_name = Validate::isModuleName(Tools::getValue('module')) ? Tools::getValue('module') : '';
                $module = Module::getInstanceByName($module_name);
                $controller_class = 'PageNotFoundController';
                if (Validate::isLoadedObject($module) && $module->active) {
                    $controllers = Dispatcher::getControllers(_PS_MODULE_DIR_.$module_name.'/controllers/front/');

                    if (isset($controllers[strtolower($this->controller)])) {
                        include_once(_PS_MODULE_DIR_.$module_name.'/controllers/front/'.$this->controller.'.php');

                        if (file_exists(
                            _PS_OVERRIDE_DIR_.'modules/'.$module_name.'/controllers/front/'.$this->controller.'.php'
                        )) {
                            include_once(_PS_OVERRIDE_DIR_.'modules/'.$module_name.'/controllers/front/'.$this->controller.'.php');
                            $controller_class = $module_name.$this->controller.'ModuleFrontControllerOverride';
                        } else {

                            $controller_class = $module_name.$this->controller.'ModuleFrontController';
                        }
                    }
                }
                $params_hook_action_dispatcher = array(
                    'controller_type' => self::FC_FRONT,
                    'controller_class' => $controller_class,
                    'is_module' => 1,
                );
                break;

            // Dispatch back office controller + module back office controller
            case self::FC_ADMIN :
                if ($this->use_default_controller && !Tools::getValue('token') && Validate::isLoadedObject(
                        Context::getContext()->employee
                    ) && Context::getContext()->employee->isLoggedBack()) {
                    Tools::redirectAdmin(
                        'index.php?controller='.$this->controller.'&token='.Tools::getAdminTokenLite($this->controller)
                    );
                }

                $tab = Tab::getInstanceFromClassName($this->controller, Configuration::get('PS_LANG_DEFAULT'));
                $retrocompatibility_admin_tab = null;

                if ($tab->module) {
                    if (file_exists(_PS_MODULE_DIR_.$tab->module.'/'.$tab->class_name.'.php')) {
                        $retrocompatibility_admin_tab = _PS_MODULE_DIR_.$tab->module.'/'.$tab->class_name.'.php';
                    } else {
                        $controllers = Dispatcher::getControllers(_PS_MODULE_DIR_.$tab->module.'/controllers/admin/');
                        if (!isset($controllers[strtolower($this->controller)])) {
                            $this->controller = $this->controller_not_found;
                            $controller_class = 'AdminNotFoundController';
                        } else {
                            // Controllers in modules can be named AdminXXX.php or AdminXXXController.php
                            include_once(_PS_MODULE_DIR_.$tab->module.'/controllers/admin/'.$controllers[strtolower(
                                    $this->controller
                                )].'.php');
                            $controller_class = $controllers[strtolower($this->controller)].(strpos(
                                    $controllers[strtolower($this->controller)],
                                    'Controller'
                                ) ? '' : 'Controller');
                        }
                    }
                    $params_hook_action_dispatcher = array(
                        'controller_type' => self::FC_ADMIN,
                        'controller_class' => $controller_class,
                        'is_module' => 1,
                    );
                } else {
                    $controllers = Dispatcher::getControllers(
                        array(
                            _PS_ADMIN_DIR_.'/tabs/',
                            _PS_ADMIN_CONTROLLER_DIR_,
                            _PS_OVERRIDE_DIR_.'controllers/admin/',
                        )
                    );
                    if (!isset($controllers[strtolower($this->controller)])) {
                        // If this is a parent tab, load the first child
                        if (Validate::isLoadedObject($tab) && $tab->id_parent == 0 && ($tabs = Tab::getTabs(
                                Context::getContext()->language->id,
                                $tab->id
                            )) && isset($tabs[0])) {
                            Tools::redirectAdmin(Context::getContext()->link->getAdminLink($tabs[0]['class_name']));
                        }
                        $this->controller = $this->controller_not_found;
                    }

                    $controller_class = $controllers[strtolower($this->controller)];
                    $params_hook_action_dispatcher = array(
                        'controller_type' => self::FC_ADMIN,
                        'controller_class' => $controller_class,
                        'is_module' => 0,
                    );

                    if (file_exists(_PS_ADMIN_DIR_.'/tabs/'.$controller_class.'.php')) {
                        $retrocompatibility_admin_tab = _PS_ADMIN_DIR_.'/tabs/'.$controller_class.'.php';
                    }
                }

                // @retrocompatibility with admin/tabs/ old system
                if ($retrocompatibility_admin_tab) {
                    include_once($retrocompatibility_admin_tab);
                    include_once(_PS_ADMIN_DIR_.'/functions.php');
                    runAdminTab($this->controller, !empty($_REQUEST['ajaxMode']));

                    return;
                }
                break;

            default :
                throw new PrestaShopException('Bad front controller chosen');
        }

        // Instantiate controller
        try {
            // Loading controller
            $controller = Controller::getController($controller_class);

            // Execute hook dispatcher
            if (isset($params_hook_action_dispatcher)) {
                Hook::exec('actionDispatcher', $params_hook_action_dispatcher);
            }

            // Running controller
            $controller->run();
        } catch (PrestaShopException $e) {
            $e->displayMessage();
        }
    }

}
  • Add this file to override/classes directory 将此文件添加到override / classes目录
  • Delete the cache/class_index.php file 删除cache / class_index.php文件

After this it is possible to override module controllers by putting the override file in : 此后,可以通过将替代文件放入以下位置来替代模块控制器:

override/modules/{moduleName}/controllers/{front/admin}/{filename}.php

In this file you have to define a class with the exact same name as the class you want to override and append "Override" at the end of the classname. 在此文件中,您必须定义一个名称与要覆盖的类完全相同的类,并在类名的末尾附加“ Override”。

I hope this helps 我希望这有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM