Create a Scheduled Task Plugin for Shopware

You need quite a few files just to create a scheduled task in Shopware, and getting it right can be a challenging undertaking to new developers. In this tutorial, I tried to simplify the process.

124 views
d

By. Jacob

Edited: 2023-11-11 23:43

To create a scheduled task, you ought to read the official documentation, and if needed, supplement it by looking at existing code in Shopware's core. And, of course, you may also refer to this short tutorial.

Although some of the required files form the basis of any plugin, the number of things you need to memorize just to add a scheduled task, or more or less do anything as a Shopware developer, is still quite overwhelming at first. In my humble opinion, much of this abstraction is just unnecessary.

One of the most confusing things is the way Shopware is seemingly mixing lowercase with uppercase letters, and some places uses dashes "-" to refer to something that is written using camel case elsewere. It create numerous points of confusion, cognitive friction, and ultimately head scratching "file or class not found" issues that nobody find remotely interesting to debug. But, creating a scheduled task is actually among one of the easier things to do in Shopware.

On the positive side, you should at least be able to use the plugin as a base for your future plugins simply by renaming the plugin and its namespace to fit your organisation and/or your own desires. If something is not working afterwards, then you will know the most likely cause is a mistake in the namespace.

Required files and directories

This assumes you create a plugin and place it in custom/plugins (E.g. custom/plugins/NewPlugin) – you can at any time move it to vendor/mycompany/myplugin if you later want to install your plugin from a git repository using composer.

The final directory tree you need to make will look like this:

.
├── composer.json
└── src
    ├── TestNewPlugin.php
    ├── Resources
    │   └── config
    │       └── services.xml
    └── Service
        └── ScheduledTask
            ├── ExampleTask.php
            └── ExampleTaskHandler.php

TestNewPlugin/composer.json:

{
    "name": "test/new-plugin",
    "description": "This example plugin for scheduled tasks will write a message to var/log/plugin-dev.log every 10min when activated.",
    "version": "1.0.0",
    "type": "shopware-platform-plugin",
    "license": "MIT",
    "authors": [
        {
            "name": "JacobSeated"
        }
    ],
    "require": {
        "shopware/core": "6.4.*"
    },
    "extra": {
        "shopware-plugin-class": "Test\\NewPlugin\\testNewPlugin",
        "label": {
            "en-GB": "Scheduled task example plugin"
        },
        "description": {
            "en-GB": "This example plugin for scheduled tasks will write a message to var/log/plugin-dev.log every 10min when activated."
        }
    },
    "autoload": {
        "psr-4": {
            "Test\\NewPlugin\\": "src/"
        }
    }
}

The composer.json file contains things like the autoload path for your plugin classes and the name of your plugin.

TestNewPlugin/src/TestNewPlugin.php:

<?php declare(strict_types=1);

namespace Test\NewPlugin;

use Shopware\Core\Framework\Plugin;

class TestNewPlugin extends Plugin
{
}

TestNewPlugin/src/Service/ScheduledTask/ExampleTask.php:

<?php declare(strict_types=1);

namespace Test\NewPlugin\Service\ScheduledTask;

use Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTask;

class ExampleTask extends ScheduledTask
{
    public static function getTaskName(): string
    {
        return 'test.example_task';
    }

    public static function getDefaultInterval(): int
    {
        return 600; // 10 minutes
    }
}

TestNewPlugin/src/Service/ScheduledTask/ExampleTaskHandler.php:

<?php declare(strict_types=1);

namespace Test\NewPlugin\Service\ScheduledTask;

use Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTaskHandler;

class ExampleTaskHandler extends ScheduledTaskHandler
{
    public static function getHandledMessages(): iterable
    {
        return [ ExampleTask::class ];
    }

    public function run(): void
    {
        file_put_contents('/var/www/shopware/var/log/plugin-dev.log', time(). ':it is working', FILE_APPEND);
    }
}

Then you should glue everything together by registering the relevant PHP classes in your plugin's service file. Note, this is also where you can provide other classes as a "service" to your ScheduledTask handler via dependency injection.

TestNewPlugin/src/Resources/config/services.xml

<xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="Test\NewPlugin\Service\ScheduledTask\ExampleTask">
            <tag name="shopware.scheduled.task" />
        </service>

        <service id="Test\NewPlugin\Service\ScheduledTask\ExampleTaskHandler">
            <argument type="service" id="scheduled_task.repository" />
            <tag name="messenger.message_handler" />
        </service>
    </services>
</container>

How scheduled tasks work

It is important to note, this plugin is totally dependent on a functioning queue system. You will need to correctly configure your messenger:consume workers with either Systemd or Supervisor – it is not recommended to use cron, because it can be difficult to ensure your workers are restarted and make sure only a specific number of workers are running.

Here is a example of a supervisor .conf file for starting a couple of messenger:consume workers.

messenger-consume.conf

[program:messenger-consume]
command=php /var/www/shopware/bin/console messenger:consume async --time-limit=1800 --memory-limit=1024M
user=www-data
numprocs=2
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d

These files should be placed in /etc/supervisor/conf.d/.

Supervisor is also commonly used inside a Docker container to run various services required by the web application. E.g. PHP-FPM and the Apache HTTP server.

You will also need a single process register the scheduled tasks in Shopware.

scheduled-task-run.conf:

[program:scheduled-task-run]
command=php /var/www/shopware/bin/console scheduled-task:run -n --memory-limit=512M
user=www-data
numprocs=1
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d

Links

  1. Add Scheduled Task - developer.shopware.com

Tell us what you think:

  1. Sometimes we may to manually clear cached Shopware files to fix namespace issues.
  2. How to obtain the currently selected API language from Shopware vue components.
  3. How to access file system paths from storefront twig files in Shopware.
  4. How to get or change the currently selected sales channel in an Shopware sw-sales-channel-switch component.
  5. In this tutorial you will learn how to work with Shopware entities in a generic way from PHP, without having to specifically inject the repository in your services.xml file.

More in: Shopware