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?

Sohan
quelle

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.

Raphael beim digitalen Pianismus
quelle
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.

sebastianwagner
quelle