Задания по расписанию в Symfony 2.0

25 Июн
2012

Все началось с того, что мне потребовалось автоматически обновлять статусы задач в зависимости от текущей даты на выполненные или невыполненные. Система задач написана на Symfony 2, и хотелось обойтись без команды wget в задании cron. Было бы неплохо выполнять обновление статусов и вручную через консоль Symfony 2. Я решил эту задачу, написав пару классов: сервис и команду.

Чтобы добавить свою команду в app/console, необходимо написать класс, расширяющий \Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand. В нем важными методами являются configure(), где происходит инициализация команды в системе и execute(), где происходит исполнение команды.

<?php

namespace Acme\DemoBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class UpdateStateTaskCommand extends ContainerAwareCommand {

    public function configure() {
        $this
            ->setDefinition(array())
            ->setDescription('Update states for tasks for Demo Bundle')
            ->setName('demo:tasks:state:update'); //здесь прописываем имя нашей будущей команды
    }

    protected function execute(InputInterface $input, OutputInterface $output) {
        //получаем сервис, который будет непосредственно обновлять статусы
        $stateUpdater = $this->getContainer()->get('acme_demo.state_updater');
        $stateUpdater->update();
        //записываем событие в лог
        $logger = $this->getContainer()->get('logger');
        $logger->info('Fired update system tasks for disciplines');
    }

}


Далее напишем класс, выполняющий действие обновления записей. Это будет подключаемым через контейнер DI сервисом.

<?php

namespace Acme\DemoBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Сервис для управления состоянием задач
*
*/
class State {

    private $container;

    public function __construct(ContainerInterface $container) {
        $this->container = $container;
    }

    public function update(){
        $em = $this->container
                   ->get('doctrine')
                   ->getEntityManager();

        $currentDate = new \DateTime('now');

        //запрос на все задачи
        $query = $em->createQueryBuilder()
                    ->select('t')
                    ->from('AcmeDemoBundle:Task', 't')
                    ->getQuery()
        ;

        $tasks = $query->getResult();

        if($tasks) {
            foreach($tasks as $task) {
                $diff = $task->getPlan()->getTimestamp() - $currentDate->getTimestamp();
                if($diff > 0 && (($diff / 86400) > 1)) {
                    //если просрочена планируемая дата, то ставим статус Не выполнено
                    $state = $em->getRepository('AcmeDemoBundle:State')->findOneByName('Не выполнено');
                    if($state) {
                        $task->setState($state);
                    }
                } else {
                    $task->setState(null);
                }
            }

            $em->flush();
        }
    }
}


Конструктор данного класса принимает в качестве параметра контейнер DI, из которого мы получаем Doctrine Entity Manager. Прописываем конфигурацию подключения сервиса в services.yml.

services:
       #....
       acme_demo.state_updater:
               class: Acme\DemoBundle\Controller\State
               arguments: ['<hh user=service_container>']


Перейдя в консоль и выполнив команду $ php app/console, мы должны увидеть в списке новоиспеченную команду demo:tasks:state:update. Последнее, что осталось сделать, это добавить задание в cron. Я установил выполнение команды раз в сутки в 00:00.

0  0  *  *  * cd /home/username/site.ru && /usr/bin/php app/console demo:tasks:state:update


При создании данной статьи я пользовался официальной документацией Symfony 2.0.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх