Cron in Magento is fairly
easy to configure. A few lines in config.xml, a method and it’s done. But what
happens if you want to spice it up a bit and create a schedule-configurable
cron? Fortunately for us, Magento has that already included in the system and
it’s pretty easy to implement.
Cron
itself is more or less straightforward. As seen in the code below, it is
defined in a config.xml file with two main parts: schedule and a method to be
ran. A sample below shows a cron job named “my_cron” that runs “doSomething”
method inside the observer file every five minutes. If you’re not familiar with
the cron schedule format, there’s a bunch of the articles and cron generators
on the internet.
<config>
<crontab>
<jobs>
<my_cron>
<schedule>
<cron_expr>*/5
* * * *</cron_expr>
</schedule>
<run>
<model>mymodule/observer::doSomething</model>
</run>
</my_cron>
</jobs>
</crontab>
</config>
The thing about this is that the schedule
cannot be configured…yet. Inside the Mage_Cron_Model_Observer class, which
generates cron jobs, there’s a “generate” method that also checks for the
values inside core_config_data table in the same way as it does for config.xml
files. Having that in mind, we could save the path to the cron schedule and set
any (valid) value we want. So let’s get to work!
Admin configuration
As we want to have schedule-configurable
cron we have to have an admin configuration for that. As you can make it
whatever and however you want, I’m not going to do the miracles here but I’ll
use what Magento already offers to us.
Inside the system.xml will be time (hour,
minute and second) and frequency selectors (daily, weekly and monthly) that
already come packed within Magento. All the coding that has to be done is to
create our own backend model that will format and save the values to path we
want. In this case it’s will be in the
mymodule/adminhtml_system_config_backend_mymodel_cron.
<config>
<sections>
<catalog>
<groups>
<configurable_cron translate="label">
<label>Cron
Schedule</label>
<sort_order>100</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
<fields>
<time translate="label">
<label>Start
Time</label>
<frontend_type>time</frontend_type>
<sort_order>10</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
</time>
<frequency translate="label">
<label>Frequency</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_cron_frequency</source_model>
<backend_model>mymodule/adminhtml_system_config_backend_mymodel_cron</backend_model>
<sort_order>20</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
</frequency>
</fields>
</configurable_cron>
</groups>
</catalog>
</sections>
</config>
Backend
model
The frontend types in the admin
configuration don’t save the inputs in the way the cron generator can read
them. Because of that we have to have a backend model that fill format those
inputs the way we want.
From the sample code above on how the
regular cron job is set in the config.xml, the same paths should be used in the
core_config_data table that we’re going to deal with. From the code above, the
path to our schedule would be “crontab/jobs/my_cron/schedule/cron_expr”. The
code below formats the inputs and saves the value to the table.
class Inchoo_MyModule_Model_Adminhtml_System_Config_Backend_MyModel_Cron
extends Mage_Core_Model_Config_Data
{
const CRON_STRING_PATH = ‘crontab/jobs/my_cron/schedule/cron_expr';
protected function _afterSave()
{
$time = $this->getData('groups/configurable_cron/fields/time/value');
$frequencyDaily = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_DAILY;
$frequencyWeekly = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_WEEKLY;
$frequencyMonthly =
Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_MONTHLY;
$cronDayOfWeek = date('N');
$cronExprArray = array(
intval($time[1]),
# Minute
intval($time[0]),
# Hour
(frequency
== $frequencyMonthly) ? '1'
:
'*', # Day of the Month
'*',
# Month of the Year
(frequency
== $frequencyWeekly) ? '1' : '*', #
Day of the Week
);
$cronExprString = join(' ', $cronExprArray);
try {
Mage::getModel('core/config_data')
->load(self::CRON_STRING_PATH,
'path')
->setValue($cronExprString)
->setPath(self::CRON_STRING_PATH)
->save();
}
catch (Exception $e) {
throw new Exception(Mage::helper('cron')->__('Unable to
save the cron expression.'));
}
}
}
Cron generator goes through the cron jobs
and takes only the ones with the schedule defined. To have the schedule read
from the config table, the schedule node has to be removed from the config.xml
and only have the model defined, as shown below.
<config>
<crontab>
<jobs>
<my_cron>
<run>
<model>mymodule/observer::doSomething</model>
</run>
</my_cron>
</jobs>
</crontab>
</config>
What happens in the background? Cron generator runs through the
config.xml files and config table, looks for the cron schedules and populates
the cron schedule table. At this point models are irrelevant. All the cron jobs
that have no schedule defined will be skipped. Another method, Cron dispatch,
reads the cron jobs from the cron schedule table, collects the methods from
both config.xml files and the config table and runs them.
Observer
In the observer will be the method that will be ran by the cron.
What code comes here is up to you.
class Inchoo_MyModule_Model_Observer
{
public function doSomething()
{
// do
something
}
}
No comments:
Post a Comment