So legen Sie den dynamischen Zeitplan für Cronjobs in der Datenbank in Magento 2 fest


7

Ich arbeite an einem benutzerdefinierten Modul für Magento 2. Ich habe dort crontab eingerichtet und es funktioniert gut mit statischem Zeitplan.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../app/code/Magento/Cron/etc/crontab.xsd">
    <group id="default">
        <job name="tm-feed-job" instance="TM\Feed\Model\Cron" method="export">
            <schedule>* * * * * *</schedule>
        </job>
    </group>
</config>

Aber ich brauche die <schedule>* * * * * *</schedule>Dynamik aus meiner Datenbank gespeicherten Wert. Hier muss ich 3 Zeitplan verwendenDaily Weekly Monthly

Häufigkeit bereits in der Datenbank gespeichert Geben Sie hier die Bildbeschreibung ein

Wie kann ich dort einen dynamischen Zeitplan hinzufügen?

Antworten:


10

Nicht so einfach wie ich erwartet hatte.

Zuerst müssen Sie Ihre aktualisieren, crontab.xmlum den Konfigurationspfad auf Ihre Frequenz einzurichten:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../app/code/Magento/Cron/etc/crontab.xsd">
    <group id="default">
        <job name="tm-feed-job" instance="TM\Feed\Model\Cron" method="export">
            <config_path>crontab/default/jobs/tm_feed_job/schedule/cron_expr</config_path>
        </job>
    </group>
</config>

Jetzt müssen Sie der Konfiguration ein Feld hinzufügen, um die Frequenz wie folgt auswählen zu können adminhtml/system.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="vendor">
            <group id="module" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                <label>Cron Settings</label>
                <field id="frequency" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Frequency</label>
                    <source_model>Magento\Cron\Model\Config\Source\Frequency</source_model>
                    <backend_model>Vendor\Module\Model\Config\Backend\Frequency</backend_model>
                </field>
                <field id="time" translate="label" type="time" sortOrder="2" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Start Time</label>
                </field>
            </group>
        </section>
    </system>
</config>

Jetzt müssen wir Vendor\Module\Model\Config\Backend\Frequencyfür das Frequenz-Backend-Modell Folgendes erstellen :

<?php

namespace Vendor\Module\Model\Config\Backend;

class Frequency extends \Magento\Framework\App\Config\Value
{
    /**
     * Cron string path
     */
    const CRON_STRING_PATH = 'crontab/default/jobs/tm_feed_job/schedule/cron_expr';

    /**
     * Cron model path
     */
    const CRON_MODEL_PATH = 'crontab/default/jobs/tm_feed_job/run/model';

    /**
     * @var \Magento\Framework\App\Config\ValueFactory
     */
    protected $_configValueFactory;

    /**
     * @var string
     */
    protected $_runModelPath = '';

    /**
     * @param \Magento\Framework\Model\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
     * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
     * @param \Magento\Framework\App\Config\ValueFactory $configValueFactory
     * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
     * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
     * @param string $runModelPath
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\App\Config\ScopeConfigInterface $config,
        \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
        \Magento\Framework\App\Config\ValueFactory $configValueFactory,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        $runModelPath = '',
        array $data = []
    ) {
        $this->_runModelPath = $runModelPath;
        $this->_configValueFactory = $configValueFactory;
        parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
    }

    /**
     * {@inheritdoc}
     *
     * @return $this
     * @throws \Exception
     */
    public function afterSave()
    {
        $time = $this->getData('groups/module/fields/time/value');
        $frequency = $this->getData('groups/module/fields/frequency/value');

        $cronExprArray = [
            intval($time[1]), //Minute
            intval($time[0]), //Hour
            $frequency == \Magento\Cron\Model\Config\Source\Frequency::CRON_MONTHLY ? '1' : '*', //Day of the Month
            '*', //Month of the Year
            $frequency == \Magento\Cron\Model\Config\Source\Frequency::CRON_WEEKLY ? '1' : '*', //Day of the Week
        ];

        $cronExprString = join(' ', $cronExprArray);

        try {
            $this->_configValueFactory->create()->load(
                self::CRON_STRING_PATH,
                'path'
            )->setValue(
                $cronExprString
            )->setPath(
                self::CRON_STRING_PATH
            )->save();
            $this->_configValueFactory->create()->load(
                self::CRON_MODEL_PATH,
                'path'
            )->setValue(
                $this->_runModelPath
            )->setPath(
                self::CRON_MODEL_PATH
            )->save();
        } catch (\Exception $e) {
            throw new \Exception(__('We can\'t save the cron expression.'));
        }

        return parent::afterSave();
    }
}

Dieser Code sieht auf den ersten Blick schwierig aus, generiert jedoch im Grunde den crontab/default/jobs/tm_feed_job/schedule/cron_exprKonfigurationspfad basierend auf dem, was Sie in der Frequenz-Dropdown-Liste ausgewählt haben.

Interessante Randnotiz: Dies wird nativ für einige Module in M2 implementiert, darunter Währung, Produktwarnungen, Backups und Sitemaps. Das Interessante ist, wo das Backend-Modell für einige dieser Module definiert ist:

  • Produktwarnung: Magento\Cron\Model\Config\Backend\Product\Alert
  • Seitenverzeichnis: Magento\Cron\Model\Config\Backend\Sitemap

Also ja, du hast es richtig gelesen. Diese Backend-Modelle befinden sich nicht im entsprechenden Modulordner, sondern im Magento\CronModulordner.


Vielen Dank für den Hinweis - wollte aber fragen, was runModel hier macht. Pelase erklären
— Abid Malik

Sie finden immer eine gute Lösung. +1 :)
— Shoaib Munir

Was nützt das runModelPath? Ist es erforderlich, dies hinzuzufügen?
— DJ Dev

Es funktioniert nicht in Magento 2.3.3. cron läuft nicht gemäß der in der Konfiguration festgelegten Zeit. Mein Cron läuft jeden Tag um 00:01 Uhr, aber ich habe die Zeit 10:30 Uhr und die Frequenz "Täglich" eingestellt.
— nil108

0

Bei der Betrachtung \Magento\Cron\Observer\ProcessCronQueueObserver::_generateJobswürde es ausreichen, einen Varchar-Eingang am angegebenen Konfigurationsschlüssel <config_path>zu erstellen, aus dem Ihr jeweiliger Wert gelesen werden kann core_config_data.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.