1

您好,我想弄清楚我什么时候可以让我的产品在预定日期上线,然后以禁用状态关闭。基本上我每天都会列出一种产品。我想要一个更简单的解决方案,而不是每天熬夜。

我被告知要创建一个日期属性“发布日期”,然后放置一个 cron 作业来更新产品。我不知道如何开发一个 cron 工作新手。请帮忙!一步一步的指导......这对许多 Magento 用户来说将是一个很大的帮助。

4

2 回答 2

4

来自www.ecomdev.org(页面已不存在)

简介 本文将帮助您了解目录产品的基本自定义以及在 Magento 中执行自定义 cron 作业。

功能 在开始开发之前,您应该想象它的作用并选择适合所有需求的功能。

该模块的要求如下:

  • 它应该允许管理员用户指定产品的激活和到期日期。

  • 它应该检查指定日期的产品并根据日期类型执行以下操作:

    • 如果激活日期成真,则激活产品
    • 如果到期日期成真,则激活产品

所以模块开发应该遵循以下步骤:

  1. 创建自定义属性后端模型以允许存储日期时间属性的日期(Magento 本机 eav 实现从日期时间字符串中删除时间部分)

  2. 为产品创建两个属性,这可能通过激活和到期日期来实现,并为其分配自定义属性后端模型产品的激活和到期日期以及启用/禁用它们

基本结构

现在您知道它应该如何工作了,因此您可以创建一个基本的模块结构。

模块的结构应包含以下内容:

  • 模块引导程序和主要配置文件
  • 用于属性添加和设置模型的 SQL 升级脚本
  • 也将包含 cron 作业的事件观察者类
  • 自定义属性后端模型

您应该在创建结构之前命名模块。模块名称由模块名称空间和内部模块名称组成,由下划线符号分隔。所以这个模块的名称将是“EcomDev_ScheduledProduct”,其中“EcomDev”是我的扩展命名空间。

首先,您应该创建模块引导配置文件以启用您的模块。位于“app/etc/modules”文件夹中的引导文件。文件名应与模块名相同。因此,您应该创建文件“EcomDev_ScheduledProduct.xml”,文件结构应包含模块名称、其代码池、活动状态和用于指定所需模块的依赖节点。所以它应该如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <EcomDev_ScheduledProduct>
            <active>true</active> <!-- the module activity state -->
            <codePool>community</codePool> <!-- the module code pool -->
            <depends>
                <Mage_Catalog />  <!-- the module depends on Mage_Catalog module, so it mentioned here -->
            </depends>
        </EcomDev_ScheduledProduct>
    </modules>
</config>

该模块指定放置在社区代码池中,因此应放置在“app/code/community”文件夹中,其路径应为“app/code/community/EcomDev/ScheduledProduct”。

现在您应该创建模块配置文件,您将在其中指定模型命名空间和设置脚本初始化语句。

让我们创建它:“app/code/community/EcomDev/ScheduledProduct/etc/config.xml”</p>

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <EcomDev_ScheduledProduct>
            <version>1.0.0</version>
        </EcomDev_ScheduledProduct>
    </modules>
    <global>
        <models>
            <ecomdev_scheduledproduct>
            <!-- specification of model name space,
                 so we can call models like Mage::getModel('ecomdev_scheduledproduct/somemodelname') -->
                <class>EcomDev_ScheduledProduct_Model</class>
            </ecomdev_scheduledproduct>
        </models>
        <resources>
            <!-- specifying of setup model and setup script path in sql folder -->
            <ecomdev_scheduledproduct_setup>
                <setup>
                    <module>EcomDev_ScheduledProduct</module>
                    <class>EcomDev_ScheduledProduct_Model_Mysql4_Setup</class>
                </setup>
                <connection>
                    <!-- use catalog connection to modify products -->
                    <use>catalog_setup</use>
                </connection>
            </ecomdev_scheduledproduct_setup>
        </resources>
    </global>
</config>

属性后端模型 在创建设置脚本之前,您需要处理日期时间属性后端模型以在设置中指定它。在模块“模型”文件夹中创建它。在此模块中,您应该将其命名为“EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime”,路径“Attribute_Backend_Datetime”解释了模型的作用。在其中你应该重写“beforeSave($object)”、“afterLoad($object)”和“formatDate($date)”方法来改变你的属性存储逻辑。您可能还想添加“compareDateToCurrent($date)”方法来检查产品保存之前的激活或到期日期是否正确。该模型应从“Mage_Eav_Model_Entity_Attribute_Backend_Datetime”扩展而来。“app/code/community/EcomDev/ScheduledProduct/Model/Attribute/Backend/Datetime.php”</p>

<?php
/**
 * Expiry and Activation dates custom backend model
 *
 */
class EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime extends Mage_Eav_Model_Entity_Attribute_Backend_Datetime
{
    /**
     * Activation date attribute code
     *
     * @var string
     */
    const ATTRIBUTE_ACTIVATION_DATE = 'ecomdev_activation_date';
    /**
     * Expiry date attribute code
     *
     * @var string
     */
    const ATTRIBUTE_EXPIRY_DATE = 'ecomdev_expiry_date';
    /**
     * Status attribute code
     *
     * @var string
     */
    const ATTRIBUTE_STATUS = 'status';
    /**
     * Checks date to update product status
     * on the save in the admin panel
     *
     * @param Mage_Catalog_Model_Product $object
     * @return EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime
     */
    public function beforeSave($object)
    {
        parent::beforeSave($object);
        $code = $this->getAttribute()->getAttributeCode();
        $compareResult = $this->compareDateToCurrent($object->getData($code));
        if ($compareResult !== false) {
            // If the date is set
            if (($compareResult < 0 && $code == self::ATTRIBUTE_ACTIVATION_DATE) ||
                ($compareResult >= 0 && $code == self::ATTRIBUTE_EXPIRY_DATE)) {
                // If the date is in the past and it's activation date
                // or the date is in the future and it's expiry date,
                // so the product should be deactivated
                $object->setData(
                    self::ATTRIBUTE_STATUS,
                    Mage_Catalog_Model_Product_Status::STATUS_DISABLED
                );
            }
        }
        return $this;
    }
    /**
     * Magento native function doesn't save
     * the time part of date so the logic of retrieving is changed
     *
     * @param   string|int $date
     * @return  string|null
     */
    public function formatDate($date)
    {
        if (empty($date)) {
            return null;
        } elseif (!($date instanceof Zend_Date)) {
            // Parse locale representation of the date, eg. parse user input from date field
            $dateString = $date;
            $usedDateFormat = Mage::app()->getLocale()->getDateTimeFormat(
                Mage_Core_Model_Locale::FORMAT_TYPE_SHORT
            );
            // Instantiate date object in current locale
            $date = Mage::app()->getLocale()->date();
            $date->set($dateString, $usedDateFormat);
        }
        // Set system timezone for date object
        $date->setTimezone(Mage_Core_Model_Locale::DEFAULT_TIMEZONE);
        return $date->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
    }
    /**
     * Compare date to current date
     *
     * Returns -1 if the date is in the past, and 1 if it's in the future,
     * returns 0 if the dates are equal.
     *
     * @param string $date
     * @return int
     */
    public function compareDateToCurrent($date)
    {
        if (empty($date)) {
            return false;
        }
        $compareDate = Mage::app()->getLocale()->date($date, Varien_Date::DATETIME_INTERNAL_FORMAT);
        $currentDate = Mage::app()->getLocale()->date();
        return $currentDate->compare($compareDate);
    }
    /**
     * Converts timezone after object load, fixes issue in the core form element
     *
     * @param Mage_Core_Model_Abstract $object
     * @return EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime
     */
    public function afterLoad($object)
    {
        $code = $this->getAttribute()->getAttributeCode();
        if ($object->getData($code) && !($object->getData($code) instanceof Zend_Date)) {
            $date = Mage::app()->getLocale()->date();
            $dateString = $object->getData($code);
            $currentTimezone = $date->getTimezone();
            $date->setTimezone(Mage_Core_Model_Locale::DEFAULT_TIMEZONE);
            $date->set($dateString, Varien_Date::DATETIME_INTERNAL_FORMAT);
            $date->setTimezone($currentTimezone);
            $object->setData($code, $date);
        }
        return parent::afterLoad($object);
    }
}

设置 现在您需要创建设置模型和设置脚本。在配置文件中,设置模型类名称为“EcomDev_ScheduledProduct_Model_Mysql4_Setup”。该模块扩展了目录功能,因此模块设置模型扩展了目录设置模型。“app/code/community/EcomDev/ScheduledProduct/Model/Mysql4/Setup.php”</p>

<?php
/**
 * Setup model for scheduled product module, extended from catalog module setup
 */
class EcomDev_ScheduledProduct_Model_Mysql4_Setup extends Mage_Catalog_Model_Resource_Eav_Mysql4_Setup
{
}

您需要在“sql/ecomdev_scheduledproduct_setup”文件夹中创建安装脚本。模块版本是 1.0.0,实际上是第一个版本,所以需要命名为“mysql4-install-1.0.0.php”。此脚本应包含将属性添加到 EAV。同样对于这个模块,我们应该在“catalog_product_entity”表中添加列,因为它会加快产品批量状态更新过程。“app/code/community/EcomDev/ScheduledProduct/sql/ecomdev_scheduledproduct_setup/mysql4-install-1.0.0.php”</p>

<?php
/* @var $this EcomDev_ScheduledProduct_Model_Mysql4_Setup */
$this->startSetup();
// For performance reasons we should add this fields to main entity table
// Activation date column adding to product entity table
$this->getConnection()->addColumn(
    $this->getTable('catalog/product'),
    EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
    'DATETIME DEFAULT NULL'
);
// Expiry date column adding to product entity table
$this->getConnection()->addColumn(
    $this->getTable('catalog/product'),
    EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
    'DATETIME DEFAULT NULL'
);
// Activation date attribute information adding to the product entity
$this->addAttribute(
    'catalog_product',
    EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
    array(
        'type'      => 'static',
        'input'     => 'date',
        'label'     => 'Activation Date',
        'global'    => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
        'backend'   => 'ecomdev_scheduledproduct/attribute_backend_datetime',
        'visible'   => 1,
        'required'  => 0,
        'position'  => 10,
        'group'     => 'Schedule Settings'
    )
);
// Expiry date attribute information adding to the product entity
$this->addAttribute(
    'catalog_product',
    EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
    array(
        'type'      => 'static',
        'input'     => 'date',
        'label'     => 'Expiry Date',
        'global'    => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
        'backend'   => 'ecomdev_scheduledproduct/attribute_backend_datetime',
        'visible'   => 1,
        'required'  => 0,
        'position'  => 20,
        'group'     => 'Schedule Settings'
    )
);
$this->endSetup();

事件观察 器 创建设置脚本和后端模型后,您需要注意属性的输入字段渲染,这就是为什么您需要观察“adminhtml_catalog_product_edit_prepare_form”事件的原因。因此,您应该使用“observeProductEditFortInitialization(Varien_Event_Observer $observer)”方法创建“EcomDev_ScheduledProduct_Model_Observer”类。它应该检查具有日期属性代码的元素的表单对象,如果发现任何元素,则向它们添加日期时间格式。

<?php
/**
 * Observer for core events handling
 *
 */
class EcomDev_ScheduledProduct_Model_Observer
{
    /**
     * Observes event 'adminhtml_catalog_product_edit_prepare_form'
     * and adds custom format for date input
     *
     * @param Varien_Event_Observer $observer
     * @return void
     */
    public function observeProductEditFortInitialization(Varien_Event_Observer $observer)
    {
        $form = $observer->getEvent()->getForm();
        $elementsToCheck = array(
            EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
            EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE
        );
        foreach ($elementsToCheck as $elementCode) {
            $element = $form->getElement($elementCode);
            if (!$element) {
                continue;
            }
            $element->setFormat(
                Mage::app()->getLocale()->getDateTimeFormat(
                    Mage_Core_Model_Locale::FORMAT_TYPE_SHORT
                )
            );
            $element->setTime(true);
        }
    }
}

您还需要在模块配置文件 (config.xml) 中定义事件观察器:

<config>
    <!-- here goes the code you've created before
          ...
          ...
      -->
    <adminhtml>
        <events>
            <adminhtml_catalog_product_edit_prepare_form>
                <observers>
                    <ecomdev_scheduledproduct>
                        <type>singleton</type>
                        <model>ecomdev_scheduledproduct/observer</model>
                        <method>observeProductEditFortInitialization</method>
                    </ecomdev_scheduledproduct>
                </observers>
            </adminhtml_catalog_product_edit_prepare_form>
        </events>
    </adminhtml>
</config>

Cron 作业 当您为属性设置管理界面后,您需要创建一个自动激活/停用产品的 cron 作业。您可以将逻辑放在“EcomDev_ScheduledProduct_Model_Observer”类中,因为 cron 作业处理调用的实现类似于事件处理,只是不会获取 $observer 参数。

<?php
/**
 * Observer for core events handling and cron jobs processing
 *
 */
class EcomDev_ScheduledProduct_Model_Observer
{
    /*
     * here goes the code you've created before
     * ............
     * ............
     */
    /**
     * Cron job for processing of scheduled products
     *
     * @return void
     */
    public function cronProcessScheduledProducts()
    {
        $currentDate = Mage::app()->getLocale()->date()->toString(
            Varien_Date::DATETIME_INTERNAL_FORMAT
        );
        $productModel = Mage::getModel('catalog/product');
        /* @var $expiredProductsCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
        // Prepare collection of scheduled for expiry but haven't yet deactivated products
        $expiredProductsCollection = $productModel->getCollection()
            // Add filter for expired but products haven't yet deactivated
            ->addFieldToFilter(
                EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
                array(
                    'nnull' => 1,  // Specifies that date shouldn't be empty
                    'lteq' => $currentDate // And lower than current date
                )
            )
            ->addFieldToFilter(
                EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_STATUS,
                Mage_Catalog_Model_Product_Status::STATUS_ENABLED
            );
        // Retrieve product ids for deactivation
        $expiredProductIds = $expiredProductsCollection->getAllIds();
        unset($expiredProductsCollection);
        if ($expiredProductIds) {
            Mage::getSingleton('catalog/product_action')
                ->updateAttributes(
                         $expiredProductIds,
                         array('status' => Mage_Catalog_Model_Product_Status::STATUS_DISABLED),
                         Mage_Core_Model_App::ADMIN_STORE_ID
                );
        }
        /* @var $expiredProductsCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
        // Prepare collection of scheduled for activation but haven't yet activated products
        $activatedProductsCollection = $productModel->getCollection()
            ->addFieldToFilter(
                EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
                array(
                    'nnull' => 1, // Specifies that date shouldn't be empty
                    'lteq' => $currentDate // And lower than current date
                )
            )
            // Exclude expired products
            ->addFieldToFilter(
                EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
                array(
                    array('null' => 1), // Specifies that date shouldn't be empty
                    array('gt' => $currentDate) // And greater than current date
                )
            )
            ->addFieldToFilter(
                EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_STATUS,
                Mage_Catalog_Model_Product_Status::STATUS_DISABLED
            );
        // Retrieve product ids for activation
        $activatedProductIds = $activatedProductsCollection->getAllIds();
        unset($activatedProductsCollection);
        if ($activatedProductIds) {
            Mage::getSingleton('catalog/product_action')
                ->updateAttributes(
                         $activatedProductIds,
                         array('status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED),
                         Mage_Core_Model_App::ADMIN_STORE_ID
                );
        }
    }
}

当然,您应该在配置文件 (config.xml) 中定义您的 cron 作业:

<config>
    <!-- here goes the code you've created before
          ...
          ...
      -->
    <crontab>
        <jobs>
            <ecomdev_scheduledproduct_process_schedule>
                <schedule>
                    <!-- Schedule for every 5 minutes -->
                    <cron_expr>*/5 * * * *</cron_expr>
                </schedule>
                <run>
                    <model>ecomdev_scheduledproduct/observer::cronProcessScheduledProducts</model>
                </run>
            </ecomdev_scheduledproduct_process_schedule>
        </jobs>
    </crontab>
</config>

结果 现在您应该登录到管理面板,导航“系统 -> 缓存管理 -> 刷新 Magento 缓存”以启用您的扩展。您可以在“计划设置”选项卡的“目录 -> 管理产品 -> 编辑/添加产品”页面中找到您创建的字段。并且不要忘记在您的系统 crontab 中设置 Magento cron。

结论 现在您知道了如何使用 Magento 中的 cron 作业为目录创建简单的自定义。Magento Connect 上提供的模块可作为免费社区扩展:预定产品

于 2014-10-14T16:20:46.857 回答
0

我认为Product Scheduler最适合您的要求。它有助于

  • 设置产品启用/禁用日期
  • 商店产品可用性的时间跨度
  • 设置新产品发布日期
于 2020-11-11T17:14:42.940 回答