Schedule generator
{% form_theme form 'bootstrap_3_layout.html.twig' %}
{% extends 'AppBundle::Admin/custom_layout.html.twig' %}
{% block stylesheets %}
{{ parent() }}
<style>
.top-buffer-80 { margin-top: 80px; }
.top-buffer-20 { margin-top: 20px; }
.input-group { width: 100%; }
</style>
{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-xs-8 col-md-7 col-md-offset-3">
{{ form_start(form, { 'attr':{'class': 'col-md-8', 'novalidate': 'novalidate'}}) }}
<h2>Brand report schedule</h2>
<p>Define a schedule to configure reports generation</p>
{% if form_errors(form.frequency)|length > 0 %}
<div class="has-error">
{{ form_label(form.frequency) }}
{{ form_widget(form.frequency, {'attr': {'data-sonata-select2':'false'}}) }}
{{ form_errors(form.frequency) }}
</div>
{% else %}
<div>
{{ form_label(form.frequency) }}
{{ form_widget(form.frequency, {'attr': {'data-sonata-select2':'false'}}) }}
{{ form_errors(form.frequency) }}
</div>
{% endif %}
{% if form_errors(form.name)|length > 0 %}
<div class="has-error">
{{ form_label(form.name) }}
{{ form_widget(form.name) }}
{{ form_errors(form.name) }}
</div>
{% else %}
<div>
{{ form_label(form.name) }}
{{ form_widget(form.name) }}
{{ form_errors(form.name) }}
</div>
{% endif %}
{% if form_errors(form.startDate)|length > 0 %}
<div class="has-error">
{{ form_label(form.startDate) }}
{{ form_widget(form.startDate) }}
{{ form_errors(form.startDate) }}
</div>
{% else %}
<div>
{{ form_label(form.startDate) }}
{{ form_widget(form.startDate) }}
{{ form_errors(form.startDate) }}
</div>
{% endif %}
{{ form_widget(form.ok, {'attr': {'class': 'top-buffer-20'}}) }}
{{ form_end(form) }}
</div>
</div>
<div class="row top-buffer-80">
<div class="col-xs-8 col-md-9 col-md-offset-1">
<table class="table table-striped custab">
<thead>
<tr>
<th>Name</th>
<th>Start Date</th>
<th>Frequency</th>
<th class="text-center">Action</th>
</tr>
</thead>
{% for reportCommand in reportCommands %}
<tr>
<td>{{ reportCommand.name }}</td>
{% if reportCommand.startDate is defined %}
<td>{{ reportCommand.startDate|date('Y-m-d H:i:s') }}</td>
{% else %}
<td></td>
{% endif %}
{% if reportCommand.frequency is defined %}
<td>{{ reportCommand.frequency }}</td>
{% else %}
<td></td>
{% endif %}
<td class="text-center">
<a href="{{ path('remove_brand_report_schedule', {'id': reportCommand.id}) }}" class="btn btn-danger btn-xs">
<span class="glyphicon glyphicon-remove"></span> Del
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endblock %}
/**
* Sets up a schedule for BrandReport generation - saves new ScheduleCommand
*
* @Route("/brands/report/schedule", name="brand_report_schedule")
* @Template("AppBundle:Admin/BrandReportAdmin:brand_report_schedule_setting.html.twig")
*/
public function addScheduleReportGeneration(Request $request)
{
$adminPool = $this->get('sonata.admin.pool');
$form = $this->createForm(BrandReportScheduleType::class, []);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$builder = $this->get('app.service.schedule_command_builder');
$scheduledCommand = $builder
->create(CreateBrandReportCommand::NAME)
->withName($form->getData()['name'])
->withSchedule($form->getData()['startDate'], $form->getData()['frequency'])
->build();
$em = $this->getDoctrine()->getEntityManager();
$em->persist($scheduledCommand);
$em->flush();
return $this->redirect($this->generateUrl('admin_app_brand_list'));
}
$reportCommands = $this->getDoctrine()->getRepository(ScheduledCommand::class)->findBy(['command' => CreateBrandReportCommand::NAME]);
/** @var ScheduleCommandViewTransformer $transformer */
$transformer = $this->get('command.view.transformer');
foreach ($reportCommands as &$reportCommand) {
$reportCommand = $transformer->transform($reportCommand);
}
return array(
'admin_pool' => $adminPool,
'form' => $form->createView(),
'reportCommands' => $reportCommands,
);
}
/**
* removes ScheduleCommand for report generation by id
*
* @Route("/brands/report/schedule/remove/{id}", name="remove_brand_report_schedule")
*/
public function removeScheduleReportGeneration($id)
{
$scheduledCommand = $this->getDoctrine()->getRepository(ScheduledCommand::class)->find($id);
if ($scheduledCommand) {
$em = $this->getDoctrine()->getEntityManager();
$em->remove($scheduledCommand);
$em->flush();
}
return $this->redirect($this->generateUrl("brand_report_schedule"));
}
<?php
namespace AppBundle\Service;
use AppBundle\Utils\CronExpressionGenerator;
use JMose\CommandSchedulerBundle\Entity\ScheduledCommand;
class ScheduledCommandBuilder
{
const START_DATE_EXTRA = 'startDate:';
const FREQUENCY_EXTRA = 'frequency:';
const EXTRA_DELIMITER = '%%';
/** @var ScheduledCommand */
private $scheduledCommand;
private $command;
private $name;
private $expression;
private $priority;
private $executeImmediately;
private $disabled;
private $logFile;
public function __construct()
{
$this->name = 'Scheduled command';
$this->expression = '* * * * *';
$this->priority = 10;
$this->executeImmediately = false;
$this->disabled = false;
$this->logFile = '';
}
public function create($command)
{
$this->scheduledCommand = new ScheduledCommand();
$this->command = $command;
return $this;
}
public function build()
{
$this->scheduledCommand->setCommand($this->command);
$this->scheduledCommand->setName($this->name);
$this->scheduledCommand->setCronExpression($this->expression);
$this->scheduledCommand->setPriority($this->priority);
$this->scheduledCommand->setExecuteImmediately($this->executeImmediately);
$this->scheduledCommand->setDisabled($this->disabled);
$this->scheduledCommand->setLogFile($this->logFile);
return $this->scheduledCommand;
}
public function withSchedule(\DateTime $dateTime, $frequency)
{
$expression = CronExpressionGenerator::generateFromDateTime($dateTime, $frequency);
$this->expression = $expression;
$this->name = $this->name. self::EXTRA_DELIMITER
. self::START_DATE_EXTRA. $dateTime->getTimestamp()
. self::EXTRA_DELIMITER;
$this->name = $this->name . self::EXTRA_DELIMITER
. self::FREQUENCY_EXTRA . $frequency
. self::EXTRA_DELIMITER;
return $this;
}
public function __call($method, $arguments)
{
$property = $this->extractPropertyName($method);
if (property_exists($this, $property)) {
$this->{$property} = $arguments[0];
return $this;
}
throw new \Exception($property);
}
private function extractPropertyName($method)
{
return lcfirst(str_replace("with", "", $method));
}
}
<?php
namespace AppBundle\Form\Type;
use AppBundle\Utils\CronExpressionGenerator;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
/**
* Class BrandReportScheduleType
* @package AppBundle\Form\Type
*/
class BrandReportScheduleType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, [
'constraints' => [
new NotBlank()
]
])
->add('frequency', ChoiceType::class, [
'choices' => [
CronExpressionGenerator::MONTHLY_FREQUENCY => CronExpressionGenerator::MONTHLY_FREQUENCY,
CronExpressionGenerator::WEEKLY_FREQUENCY => CronExpressionGenerator::WEEKLY_FREQUENCY,
CronExpressionGenerator::DAILY_FREQUENCY => CronExpressionGenerator::DAILY_FREQUENCY,
],
'label' => 'Frequency',
'empty_value' => '-- Select frequency --',
'constraints' => [
new NotBlank()
]
])
->add('startDate', 'sonata_type_datetime_picker', [
'constraints' => [
new NotBlank()
]
])
->add('ok', SubmitType::class);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => false,
]);
}
/**
* @return string
*/
public function getName()
{
return 'brand_report_schedule';
}
}
<?php
namespace AppBundle\Utils;
class CronExpressionGenerator
{
const MONTHLY_FREQUENCY = 'Monthly';
const WEEKLY_FREQUENCY = 'Weekly';
const DAILY_FREQUENCY = 'Daily';
const BASE_EXPRESSION = '%1$s %2$s %3$s %4$s %5$s';
/**
* Generate a CRON expression
*
* @param \DateTime $dateTime
* @param string $type
* @return string CRON Formatted String.
*/
public static function generateFromDateTime(\DateTime $dateTime, $type)
{
$minutes = intval($dateTime->format("i"));
$hours = intval($dateTime->format("h"));
$dayOfWeek = $dateTime->format("w");
$dayOfMonth = $dateTime->format("d");
switch ($type) {
case self::DAILY_FREQUENCY:
return sprintf(self::BASE_EXPRESSION, $minutes, $hours, '*', '*', '*');
break;
case self::WEEKLY_FREQUENCY:
return sprintf(self::BASE_EXPRESSION, $minutes, $hours, '*', '*', $dayOfWeek);
break;
case self::MONTHLY_FREQUENCY:
return sprintf(self::BASE_EXPRESSION, $minutes, $hours, $dayOfMonth, '*', '*');
break;
default:
return '';
}
}
}