Как стать автором
Обновить

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

Все началось с того, что мне потребовалось автоматически обновлять статусы задач в зависимости от текущей даты на выполненные или невыполненные. Система задач написана на 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: ['@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.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.