按顺序运行多个 Magento DataFlow 配置文件

本文介绍了按顺序运行多个 Magento DataFlow 配置文件的处理方法,对大家解决问题具有一定的参考价值

问题描述

我正在开发一个 Magento 扩展,它允许用户将类别、产品和其他类型的数据从不同的网上商店解决方案导入 Magento.为了实现这一点,我设置了几个负责导入的 DataFlow 高级配置文件.

I am developing a Magento extension that allows users to import categories, products and other kinds of data from a different web shop solution into Magento. In order to accomplish this, I have set up several DataFlow advanced profiles that take care of the imports.

到目前为止,它运行良好,但配置文件需要按适当的顺序运行(首先是类别,然后是产品,等等).为了让非技术用户尽可能轻松并最大限度地减少人为错误的机会,我想按顺序自动运行配置文件.理想情况下,您只需按下一个运行配置文件"按钮,然后在 DataFlow 处理配置文件的同时观察草的生长数小时.

So far it's working fine, but the profiles need to be run in the appropriate order (first categories, then products, etc.). To make it as easy as possible for non-technical users and also to minimize the chances of human error, I would like to automatically run the profiles in sequence. Ideally you would just press one "Run profile" button and then watch the grass growing for a few hours while DataFlow handles the profiles.

我似乎无法做到这一点.我的主要问题是 - 这可能吗?如果是,那么如何?

I cannot seem to accomplish this. My main question is - is this possible? And if yes, then how?

我曾尝试在同一个 XML 文件中组合多个配置文件(实际上只是将 2 个配置文件复制粘贴到一个 XML 中),但这没有用.输入文件被解析,但不知何故负责实际导入的适配器类没有运行.

I have tried to combine multiple profiles in the same XML file (literally just copy-pasting 2 profiles in one XML) but this didn't work. The input files were parsed, but somehow the Adapter classes that were responsible for the actual import weren't being run.

有没有办法告诉配置文件在完成后开始另一个配置文件(例如通过完成"方法)?或者我应该写一个小的控制面板,您可以在其中单击运行"按钮,然后控制面板通过一些 AJAX 巫术来处理序列?

Is there maybe a way to tell a profile to begin another profile when it's done (through the "finish" method for example)? Or perhaps I should write a small control panel where you can click on the "Run" button and then the control panel handles the sequence through some AJAX voodoo?

不幸的是,使用命令行脚本不是一种选择,使用 Magmi 也不是.

Using a command-line script is not an option, unfortunately, and neither is using Magmi.

为了完整起见,我必须提到所有配置文件包括:

For completeness, I must mention that all the profiles consist of:

  • 读取 CSV 文件的 IO 适配器
  • 自定义 CSV 解析器(从默认的 DataFlow CSV 解析器复制,并进行了一些调整以解决输入文件中的怪癖)
  • 执行导入的自定义适配器

推荐答案

这就是我将单个配置文件作为更大的 cron 作业的一部分运行的方式.让它运行多个配置文件应该很容易.而且您应该能够通过按下按钮使其运行.这个脚本伪造一个管理员用户登录到后端并按下一些按钮.看起来有点复杂,但这是在其他一些无法正常工作后唯一可行的方法,因为脚本作为 cron 作业运行.

This is how I run a single profile as part of a bigger cron job. It should be easy to make it run several profiles. And you should be able to make it run from pressing a button. This script fakes an admin user being logged into the backend and pressing some buttons. It looks a bit complicated, but this was the only working method after some others did not work properly because the script was running as a cron job.

将两个脚本文件放在 magento 根目录下的 shell 文件夹中:

Place both script files in the shell folder in magento's root dir:

mag_import.php:

mag_import.php:

<?php

/**
 * Path to the root of your magento installation
 */
$root = '/absolute/path/to/your/magento/root/';

/**
 * Url to your magento shop.
 */
$url = 'http://www.mygreatwebshop.url/';

/**
 * relative path from the magento root to the login file.
 */
$login = 'shell/mag_login.php';

/**
 * name of the logfile, will be places in magentoroot/var/log/
 */
$logFileName = 'import.log';

/**
 * how many products will be parsed at each post. Usually 10-50.
 */
$atOnce = 25;

/**
 * Dataflow profile id
 */    
$profileId = 8;

/**
 * DO NOT EDIT BELOW THIS LINE
 */
function convert($size) {
    $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
    return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i];
}

set_time_limit(0);

if (!isset($profileId)) {
    exit("
Please specify a profile id. You can find it in the admin panel->Import/Export->Profiles.
Usage: 
		 php -f $argv[0] PROFILE_ID
	 example: php -f $argv[0] 7
");
}

$recordCount = 0;

require_once $root . 'app/Mage.php';
ob_implicit_flush();
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

//starting the import
Mage::log("

", null, $logFileName);
Mage::log(convert(memory_get_usage()) . " - " . "STARTING IMPORT", null, $logFileName);

$profile = Mage::getModel('dataflow/profile');
$userModel = Mage::getModel('admin/user');
$userModel->setUserId(0);

Mage::getSingleton('admin/session')->setUser($userModel);

if ($profileId) {
    $profile->load($profileId);
    if (!$profile->getId()) {
        Mage::getSingleton('adminhtml/session')->addError('ERROR: Could not load profile');
    }
}

/**
 * get the login information.
 */
exec("/usr/bin/php -f {$root}{$login}", $result);

$loginInformation = json_decode($result[0]);
$sessionId = $loginInformation->sessionId;
$formKey = $loginInformation->formKey;

//clean dataflow_batch_import table so it doesn't get amazingly big.
$db = Mage::getSingleton('core/resource')->getConnection('core_write');
$db->query("TRUNCATE TABLE `dataflow_batch_import`");
Mage::log(convert(memory_get_usage()) . " - " . "Table dataflow_batch_import cleaned", null, $logFileName);

//load profile
if ($profileId) {
    $profile->load($profileId);
    if (!$profile->getId()) {
        Mage::getSingleton('adminhtml/session')->addError('ERROR: Could not load profile');
    }
}
Mage::register('current_convert_profile', $profile);

//run the profile
Mage::log(convert(memory_get_usage()) . " - " . "Preparing profile...", null, $logFileName);
$profile->run();
Mage::log(convert(memory_get_usage()) . " - " . "...Done", null, $logFileName);

//get to work
$batchModel = Mage::getSingleton('dataflow/batch');
if ($batchModel->getId()) {
    //echo "getId ok
";
    if ($batchModel->getAdapter()) {

        //echo "getAdapter ok
";

        $batchId = $batchModel->getId();
        Mage::log(convert(memory_get_usage()) . " - " . "Loaded batch id $batchId", null, $logFileName);

        $batchImportModel   = $batchModel->getBatchImportModel();
        $importIds          = $batchImportModel->getIdCollection();
        $batchModel         = Mage::getModel('dataflow/batch')->load($batchId);
        $adapter            = Mage::getModel($batchModel->getAdapter());
        $postdata           = array();
        $postnum            = 0;
        $totalproducts      = count($importIds);

        Mage::log(convert(memory_get_usage()) . " - 0/{$totalproducts}", null, $logFileName);
        foreach ($importIds as $importId) {
            //echo "importing $importId
";
            $recordCount++;
            $postdata[] = "rows[]=$importId";
            //echo "$importId ";
            if ($recordCount % $atOnce == 0 || $recordCount == $totalproducts) {
                $postnum++;
                $postdata[] = "batch_id=$batchId";
                $postdata[] = "form_key=$formKey";
                $postdatastring = implode('&', $postdata);
                $postdata = array();
                //print_r($postdatastring);
                Mage::log(convert(memory_get_usage()) . " - Start cURL request #$postnum", null, $logFileName);
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url . "index.php/admin/system_convert_profile/batchRun/?isAjax=true");
                curl_setopt($ch, CURLOPT_TIMEOUT, 200);
                curl_setopt($ch, CURLOPT_COOKIE, "adminhtml=$sessionId");
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postdatastring);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                $buffer = curl_exec($ch);
                if (empty($buffer)) {
                    Mage::log(convert(memory_get_usage()) . " - {$recordCount}/{$totalproducts} - Response is empty - ERROR" . curl_error($ch), null, $logFileName);
                } else {
                    $result = json_decode($buffer);
                    Mage::log(convert(memory_get_usage()) . " - {$recordCount}/{$totalproducts} [$buffer]", null, $logFileName);
                    if (@count($result->errors)) {
                        foreach ($result->errors as $error) {
                            Mage::log(convert(memory_get_usage()) . " - ERROR: $error", null, $logFileName);
                        }
                    }
                }
                curl_close($ch);
            }
        }

        foreach ($profile->getExceptions() as $e) {
            Mage::log(convert(memory_get_usage()) . " - " . $e->getMessage(), null, $logFileName);
        }
    }
}

Mage::log(convert(memory_get_usage()) . " - " . "Completed!", null, $logFileName);
?>

mag_login.php:

mag_login.php:

<?php

/**
 * Path to the root of your magento installation.
 * include traing slash.
 */
$root = '/absolute/path/to/your/magento/root/'

/**
 * Backend username that has the rights to import products.
 */
$username = "username";

/**
 * Password
 */
$password = "password";

 /**
  * DO NOT EDIT BELOW THIS LINE
  */

require_once $root.'app/Mage.php';
umask(0);
Mage::app();

$user = Mage::getModel('admin/user');
if ($user->authenticate($username, $password)) 
{    
    Mage::getSingleton('admin/session')->setUser($user);

    if ($user->getId())
    {
        if (Mage::getSingleton('adminhtml/url')->useSecretKey()) {
            Mage::getSingleton('adminhtml/url')->renewSecretUrls();
        }
        $session = Mage::getSingleton("admin/session");

        //Change the owner of the session file on root/var/session/ to the user that runs the webserver
        //exec("chown nobody:nobody {$root}var/session/sess_".$session->getEncryptedSessionId());

        echo json_encode(array('sessionId' => $session->getEncryptedSessionId(), 'formKey' => Mage::getSingleton('core/session')->getFormKey()));
    }
}
?>

我前段时间发现了这些脚本,并根据自己的需要修改了它们.

I found these scripts some time ago and altered them for my own needs.

这篇关于按顺序运行多个 Magento DataFlow 配置文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2

admin_action_{$_REQUEST[‘action’]}

do_action( "admin_action_{$_REQUEST[‘action’]}" )动作钩子::在发送“Action”请求变量时激发。Action Hook: Fires when an ‘action’ request variable is sent.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$_REQUEST['action']引用从GET或POST请求派生的操作。源码(Source)更新版本源码位置使用被使用2.6.0 wp-admin/admin.php:...

日期:2020-09-02 17:44:16 浏览:1127

admin_footer-{$GLOBALS[‘hook_suffix’]}

do_action( "admin_footer-{$GLOBALS[‘hook_suffix’]}", string $hook_suffix )操作挂钩:在默认页脚脚本之后打印脚本或数据。Action Hook: Print scripts or data after the default footer scripts.目录锚点:#说明#参数#源码说明(Description)钩子名的动态部分,$GLOBALS['hook_suffix']引用当前页的全局钩子后缀。参数(Parameters)参数类...

日期:2020-09-02 17:44:20 浏览:1033

customize_save_{$this->id_data[‘base’]}

do_action( "customize_save_{$this-&gt;id_data[‘base’]}", WP_Customize_Setting $this )动作钩子::在调用WP_Customize_Setting::save()方法时激发。Action Hook: Fires when the WP_Customize_Setting::save() method is called.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_data...

日期:2020-08-15 15:47:24 浏览:775

customize_value_{$this->id_data[‘base’]}

apply_filters( "customize_value_{$this-&gt;id_data[‘base’]}", mixed $default )过滤器::过滤未作为主题模式或选项处理的自定义设置值。Filter Hook: Filter a Customize setting value not handled as a theme_mod or option.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_date['base'],指的是设置...

日期:2020-08-15 15:47:24 浏览:866

get_comment_author_url

过滤钩子:过滤评论作者的URL。Filter Hook: Filters the comment author’s URL.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/comment-template.php:32610...

日期:2020-08-10 23:06:14 浏览:903

network_admin_edit_{$_GET[‘action’]}

do_action( "network_admin_edit_{$_GET[‘action’]}" )操作挂钩:启动请求的处理程序操作。Action Hook: Fires the requested handler action.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$u GET['action']引用请求的操作的名称。源码(Source)更新版本源码位置使用被使用3.1.0 wp-admin/network/edit.php:3600...

日期:2020-08-02 09:56:09 浏览:848

network_sites_updated_message_{$_GET[‘updated’]}

apply_filters( "network_sites_updated_message_{$_GET[‘updated’]}", string $msg )筛选器挂钩:在网络管理中筛选特定的非默认站点更新消息。Filter Hook: Filters a specific, non-default site-updated message in the Network admin.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分$_GET['updated']引用了非默认的...

日期:2020-08-02 09:56:03 浏览:834

pre_wp_is_site_initialized

过滤器::过滤在访问数据库之前是否初始化站点的检查。Filter Hook: Filters the check for whether a site is initialized before the database is accessed.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/ms-site.php:93910...

日期:2020-07-29 10:15:38 浏览:809

WordPress 的SEO 教学:如何在网站中加入关键字(Meta Keywords)与Meta 描述(Meta Description)?

你想在WordPress 中添加关键字和meta 描述吗?关键字和meta 描述使你能够提高网站的SEO。在本文中,我们将向你展示如何在WordPress 中正确添加关键字和meta 描述。为什么要在WordPress 中添加关键字和Meta 描述?关键字和说明让搜寻引擎更了解您的帖子和页面的内容。关键词是人们寻找您发布的内容时,可能会搜索的重要词语或片语。而Meta Description则是对你的页面和文章的简要描述。如果你想要了解更多关于中继标签的资讯,可以参考Google的说明。Meta 关键字和描...

日期:2020-10-03 21:18:25 浏览:1621

谷歌的SEO是什么

SEO (Search Engine Optimization)中文是搜寻引擎最佳化,意思近于「关键字自然排序」、「网站排名优化」。简言之,SEO是以搜索引擎(如Google、Bing)为曝光媒体的行销手法。例如搜寻「wordpress教学」,会看到本站的「WordPress教学:12个课程…」排行Google第一:关键字:wordpress教学、wordpress课程…若搜寻「网站架设」,则会看到另一个网页排名第1:关键字:网站架设、架站…以上两个网页,每月从搜寻引擎导入自然流量,达2万4千:每月「有机搜...

日期:2020-10-30 17:23:57 浏览:1264