Symfony Bundle
Available versions:
Installation
composer require aeon-php/symfony-bundle
Configuration
Register Bundle
<?php
// AppKernel.php or bundles.php
$bundles = [
new Aeon\Symfony\AeonBundle\AeonBundle(),
];
Configure Bundle
# config/packages/aeon.yaml
aeon:
calendar_timezone: 'UTC'
calendar_holidays_factory_service: 'calendar.holidays.factory.google'
ui_timezone: 'America/Los_Angeles'
ui_datetime_format: 'Y-m-d H:i:s'
ui_date_format: 'Y-m-d'
ui_time_format: 'H:i:s'
Aeon Symfony Form Types
Aeon\Symfony\AeonBundle\Form\Type\AeonDayType
Aeon\Symfony\AeonBundle\Form\Type\AeonDateTimeType
Aeon\Symfony\AeonBundle\Form\Type\AeonTime
Aeon\Symfony\AeonBundle\Form\Type\AeonTimeZone
Aeon Symfony Validators
Aeon\Symfony\AeonBundle\Validator\Constraints\After
Aeon\Symfony\AeonBundle\Validator\Constraints\AfterOrEqual
Aeon\Symfony\AeonBundle\Validator\Constraints\Before
Aeon\Symfony\AeonBundle\Validator\Constraints\BeforeOrEqual
Aeon\Symfony\AeonBundle\Validator\Constraints\Equal
Aeon\Symfony\AeonBundle\Validator\Constraints\Holiday
Aeon\Symfony\AeonBundle\Validator\Constraints\NotHoliday
How to get current time in Symfony
The easiest, cleanest and most reliable way to get current DateTime in Symfony is to use Calendar. For example in order to get current time in Symfony Controller use following code (AeonBundle register Calendar as Autowired service).
Controller
<?php
namespace App\Controller;
use Aeon\Calendar\Gregorian\Calendar;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class AeonCalendarController extends AbstractController
{
private Calendar $calendar;
public function __construct(Calendar $calendar)
{
$this->calendar = $calendar;
}
/**
* @Route("/aeon/calendar", name="aeon_calendar")
*/
public function index(): Response
{
return $this->render('aeon_calendar/index.html.twig', [
'calendar' => $this->calendar
]);
}
}
Twig
How to test features that depends on time in Symfony
AeonBundle automatically replace GregorianCalendar with GregorianCalendarStub instance
in test
environment.
Knowing that we must just get the GregorianCalendarStub::class class from the service container (GregorianCalendarStub::class is an alias for Calendar::class) and use setNow
method.
<?php
namespace App\Tests;
use Aeon\Calendar\Gregorian\DateTime;
use Aeon\Calendar\Gregorian\GregorianCalendarStub;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class AeonCalendarControllerTest extends WebTestCase
{
public function testSomething()
{
$client = static::createClient();
$client->getContainer()->get(GregorianCalendarStub::class)->setNow(DateTime::fromString('2020-01-01 00:00:00 America/Los_Angeles'));
$client->request('GET', '/aeon/calendar');
$this->assertResponseIsSuccessful();
$this->assertSelectorTextContains('code#calendar-year', '2020');
$this->assertSelectorTextContains('code#calendar-month', '2020-01');
$this->assertSelectorTextContains('code#calendar-day', '2020-01-01');
$this->assertSelectorTextContains('code#calendar-datetime', '2020-01-01T00:00:00-08:00');
}
}
How to check in Symfony Form if a given date is a holiday
Aeon Symfony Bundle provides two Symfony Validators.
Aeon\Symfony\AeonBundle\Validator\Constraints\Holiday
Aeon\Symfony\AeonBundle\Validator\Constraints\NoyHoliday
Example usage:
<?php
declare(strict_types=1);
namespace App\Form;
use Aeon\Symfony\AeonBundle\Validator\Constraints\Holiday;
use Aeon\Symfony\AeonBundle\Validator\Constraints\NotHoliday;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class AeonFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options) : void
{
$builder->add('datetime', AeonDateTimeType::class, [
'widget' => 'single_text',
'input' => 'string',
'data' => $options['calendar']->now()->format('Y-m-d H:i:s'),
]);
$builder->add('submit', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver) : void
{
parent::configureOptions($resolver);
$resolver->setRequired('calendar');
$resolver->setAllowedTypes('calendar', Calendar::class);
}
}
How to set current date in Symfony Form field
The bast practice is to always take the current date and time from one Calendar instance registered in Symfony Service Container, because it can be also mocked in the tests making them predictable and stable. In order to use Calendar in the form first it needs to be configured as an required option.
<?php
declare(strict_types=1);
namespace App\Form;
use Aeon\Symfony\AeonBundle\Validator\Constraints\Holiday;
use Aeon\Symfony\AeonBundle\Validator\Constraints\NotHoliday;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class AeonFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options) : void
{
$builder->add('holiday', AeonDayType::class, [
'constraints' => [new Holiday(['countryCode' => 'US'])]
]);
$builder->add('not_holiday', AeonDayType::class, [
'constraints' => [new NotHoliday(['countryCode' => 'US'])]
]);
$builder->add('submit', SubmitType::class);
}
}
Later when creating form this option is required:
<?php
declare(strict_types=1);
namespace App\Controller;
use Aeon\Calendar\Gregorian\Calendar;
use App\Form\AeonFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class AeonCalendarController extends AbstractController
{
private Calendar $calendar;
public function __construct(Calendar $calendar)
{
$this->calendar = $calendar;
}
/**
* @Route("/aeon/form", name="aeon_form")
*/
public function form(Request $request) : Response
{
$form = $this->createForm(AeonFormType::class, null, ['calendar' => $this->calendar]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
}
return $this->render('aeon_calendar/form.html.twig', [
'form' => $form->createView(),
]);
}
}
How to compare two Symfony DateTime fields
In order to compare two symfony fields when not using object as a form model in order
to compare one field with another we need to use constraint propertyPath
option
and select other field through current field parent
(form)
<?php
declare(strict_types=1);
namespace App\Form;
use Aeon\Symfony\AeonBundle\Validator\Constraints\Holiday;
use Aeon\Symfony\AeonBundle\Validator\Constraints\NotHoliday;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class AeonFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options) : void
{
$builder->add('datetime_compare_1', AeonDateTimeType::class, [
'widget' => 'single_text',
'input' => 'string',
'data' => $options['calendar']->now()->sub(TimeUnit::second())->format('Y-m-d H:i:s'),
'constraints' => [
new Before(['propertyPath' => 'parent.all[datetime_compare_2].data']),
],
]);
$builder->add('datetime_compare_2', AeonDateTimeType::class, [
'widget' => 'single_text',
'input' => 'string',
'data' => $options['calendar']->now()->format('Y-m-d H:i:s'),
]);
$builder->add('submit', SubmitType::class);
}
}
How to use Yasumi holidays provider
By default symfony bundle registers calendar.holidays.factory.google
service as a holiday provide however Yasumi is much more reliable and precise.
It's also recommended holidays provider, in order to use it first install:
composer require aeon-php/calendar-holidays-yasumi
And then configure the bundle
# config/packages/aeon.yaml
aeon:
calendar_holidays_factory_service: 'calendar.holidays.factory.yasumi'