Skip to content

Commit

Permalink
Incorporate spaze/netxten datetime helpers into DateTimeFormatter
Browse files Browse the repository at this point in the history
Stopped using Latte\Engine::addFilterLoader() because filters loaded with it can only be lowercased (e.g. `|foobar`, not `|fooBar`) - which still might be a bug on either side.
  • Loading branch information
spaze committed May 14, 2022
1 parent efb7acf commit 98f0dbe
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 29 deletions.
9 changes: 3 additions & 6 deletions site/app/Admin/Presenters/TrainingsPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace MichalSpacekCz\Admin\Presenters;

use DateTime;
use MichalSpacekCz\DateTime\DateTimeFormatter;
use MichalSpacekCz\Form\DeletePersonalDataFormFactory;
use MichalSpacekCz\Form\TrainingApplicationAdminFactory;
use MichalSpacekCz\Form\TrainingApplicationMultiple;
Expand All @@ -26,7 +27,6 @@
use Nette\Forms\Form;
use Nette\Utils\ArrayHash;
use Nette\Utils\Html;
use Netxten\Templating\Helpers;

class TrainingsPresenter extends BasePresenter
{
Expand All @@ -47,8 +47,6 @@ class TrainingsPresenter extends BasePresenter

private TrainingControlsFactory $trainingControlsFactory;

private Helpers $netxtenHelpers;

private DeletePersonalDataFormFactory $deletePersonalDataFormFactory;

private TrainingApplicationAdminFactory $trainingApplicationAdminFactory;
Expand Down Expand Up @@ -84,7 +82,7 @@ public function __construct(
TrainingFiles $trainingFiles,
Reviews $trainingReviews,
TrainingControlsFactory $trainingControlsFactory,
Helpers $netxtenHelpers,
private readonly DateTimeFormatter $dateTimeFormatter,
DeletePersonalDataFormFactory $deletePersonalDataFormFactory,
TrainingApplicationAdminFactory $trainingApplicationAdminFactory,
private TrainingFileFormFactory $trainingFileFormFactory,
Expand All @@ -97,7 +95,6 @@ public function __construct(
$this->trainingFiles = $trainingFiles;
$this->trainingReviews = $trainingReviews;
$this->trainingControlsFactory = $trainingControlsFactory;
$this->netxtenHelpers = $netxtenHelpers;
$this->deletePersonalDataFormFactory = $deletePersonalDataFormFactory;
$this->trainingApplicationAdminFactory = $trainingApplicationAdminFactory;
parent::__construct();
Expand Down Expand Up @@ -248,7 +245,7 @@ public function renderPastWithPersonalData(): void
$trainings = $this->trainings->getPastWithPersonalData();
$this->addApplications($trainings);

$this->template->pageTitle = 'Minulá školení s osobními daty starší než ' . $this->netxtenHelpers->localeDay($this->trainingDates->getDataRetentionDate());
$this->template->pageTitle = 'Minulá školení s osobními daty starší než ' . $this->dateTimeFormatter->localeDay($this->trainingDates->getDataRetentionDate());
$this->template->trainings = $trainings;
}

Expand Down
189 changes: 189 additions & 0 deletions site/app/DateTime/DateTimeFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php
declare(strict_types = 1);

namespace MichalSpacekCz\DateTime;

use DateTimeInterface;
use IntlDateFormatter;
use RuntimeException;

class DateTimeFormatter
{

private const DATE_DAY = 'day';
private const DATE_MONTH = 'month';

private const NO_INTERVAL = 1;
private const INTERVAL = 2;
private const INTERVAL_BOUNDARY = 3;
private const INTERVAL_BOUNDARIES = 4;

private const INTERVAL_FORMAT_START = 1;
private const INTERVAL_FORMAT_SEPARATOR = 2;
private const INTERVAL_FORMAT_END = 3;

/** @var array<string, array<string, array{1:string, 2:array<int,string>, 3:array<int, string>, 4?:array<int, string>}>>> */
private array $localDateFormat = [
'en_US' => [
self::DATE_DAY => [
self::NO_INTERVAL => 'MMMM d, y',
self::INTERVAL => [
self::INTERVAL_FORMAT_START => 'MMMM d',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'd, y',
],
self::INTERVAL_BOUNDARY => [
self::INTERVAL_FORMAT_START => 'MMMM d',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'MMMM d, y',
],
self::INTERVAL_BOUNDARIES => [
self::INTERVAL_FORMAT_START => 'MMMM d, y',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'MMMM d, y',
],
],
self::DATE_MONTH => [
self::NO_INTERVAL => 'MMMM y',
self::INTERVAL => [
self::INTERVAL_FORMAT_START => 'MMMM',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'MMMM y',
],
self::INTERVAL_BOUNDARY => [
self::INTERVAL_FORMAT_START => 'MMMM y',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'MMMM y',
],
],
],
// Date formats from http://prirucka.ujc.cas.cz/?id=810
'cs_CZ' => [
self::DATE_DAY => [
self::NO_INTERVAL => 'd. MMMM y',
self::INTERVAL => [
self::INTERVAL_FORMAT_START => 'd.',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'd. MMMM y',
],
self::INTERVAL_BOUNDARY => [
self::INTERVAL_FORMAT_START => 'd. MMMM',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'd. MMMM y',
],
self::INTERVAL_BOUNDARIES => [
self::INTERVAL_FORMAT_START => 'd. MMMM y',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'd. MMMM y',
],
],
self::DATE_MONTH => [
self::NO_INTERVAL => 'LLLL y',
self::INTERVAL => [
self::INTERVAL_FORMAT_START => 'LLLL',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'LLLL y',
],
self::INTERVAL_BOUNDARY => [
self::INTERVAL_FORMAT_START => 'LLLL y',
self::INTERVAL_FORMAT_SEPARATOR => '',
self::INTERVAL_FORMAT_END => 'LLLL y',
],
],
],
];

/** @var array<string, array<int, ?string>> */
private array $comparisonFormat = [
self::DATE_DAY => [
self::NO_INTERVAL => 'Ymd',
self::INTERVAL => 'Ym',
self::INTERVAL_BOUNDARY => 'Y',
],
self::DATE_MONTH => [
self::NO_INTERVAL => 'Ym',
self::INTERVAL => 'Y',
self::INTERVAL_BOUNDARY => null,
],
];


public function __construct(private string $defaultLocale)
{
}


public function loader(string $filter): ?callable
{
$callback = [$this, $filter];
return is_callable($callback) ? $callback : null;
}


private function localeDate(DateTimeInterface $start, ?DateTimeInterface $end, string $format, ?string $locale): string
{
if ($locale === null) {
$locale = $this->defaultLocale;
}

$formatter = new IntlDateFormatter($locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE);
if ($end === null || $this->sameDates($start, $end, $format, self::NO_INTERVAL)) {
$formatter->setPattern($this->localDateFormat[$locale][$format][self::NO_INTERVAL]);
$result = $formatter->format($start);
} else {
if ($this->sameDates($start, $end, $format, self::INTERVAL)) {
$key = self::INTERVAL;
} elseif (
isset($this->comparisonFormat[$format][self::INTERVAL_BOUNDARY])
&& !$this->sameDates($start, $end, $format, self::INTERVAL_BOUNDARY)
) {
$key = self::INTERVAL_BOUNDARIES;
} else {
$key = self::INTERVAL_BOUNDARY;
}

$formatter->setPattern($this->localDateFormat[$locale][$format][$key][self::INTERVAL_FORMAT_START]);
$result = $formatter->format($start);

$result .= $this->localDateFormat[$locale][$format][$key][self::INTERVAL_FORMAT_SEPARATOR];

$formatter->setPattern($this->localDateFormat[$locale][$format][$key][self::INTERVAL_FORMAT_END]);
$result .= $formatter->format($end);
}
if (!$result) {
throw new RuntimeException("Format '{$format}' using {$locale} has failed");
}
return $result;
}


public function localeDay(DateTimeInterface $date, ?string $locale = null): string
{
return $this->localeDate($date, null, self::DATE_DAY, $locale);
}


public function localeMonth(DateTimeInterface $date, ?string $locale = null): string
{
return $this->localeDate($date, null, self::DATE_MONTH, $locale);
}


public function localeIntervalDay(DateTimeInterface $start, DateTimeInterface $end, ?string $locale = null): string
{
return $this->localeDate($start, $end, self::DATE_DAY, $locale);
}


public function localeIntervalMonth(DateTimeInterface $start, DateTimeInterface $end, ?string $locale = null): string
{
return $this->localeDate($start, $end, self::DATE_MONTH, $locale);
}


private function sameDates(DateTimeInterface $start, DateTimeInterface $end, string $format, int $level): bool
{
return isset($this->comparisonFormat[$format][$level]) && ($start->format($this->comparisonFormat[$format][$level]) === $end->format($this->comparisonFormat[$format][$level]));
}

}
6 changes: 3 additions & 3 deletions site/app/Formatter/Texy.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Contributte\Translation\Exceptions\InvalidArgument;
use Contributte\Translation\Translator;
use MichalSpacekCz\Application\LocaleLinkGenerator;
use MichalSpacekCz\DateTime\DateTimeFormatter;
use MichalSpacekCz\Post\LocaleUrls;
use MichalSpacekCz\ShouldNotHappenException;
use MichalSpacekCz\Training\Dates;
Expand All @@ -19,7 +20,6 @@
use Nette\Utils\Arrays;
use Nette\Utils\Html;
use Netxten\Formatter\Texy as NetxtenTexy;
use Netxten\Templating\Helpers;
use Texy\HandlerInvocation;
use Texy\HtmlElement;
use Texy\Link;
Expand Down Expand Up @@ -65,7 +65,7 @@ public function __construct(
private Locales $trainingLocales,
private LocaleLinkGenerator $localeLinkGenerator,
private LocaleUrls $blogPostLocaleUrls,
private Helpers $netxtenHelpers,
private DateTimeFormatter $dateTimeFormatter,
) {
parent::__construct($cacheStorage, self::DEFAULT_NAMESPACE . '.' . $this->translator->getLocale());
}
Expand Down Expand Up @@ -350,7 +350,7 @@ private function replaceTrainingDate(string $name): string
$dates[] = $this->translator->translate('messages.trainings.nodateyet.short');
} else {
foreach ($upcoming[$name]['dates'] as $date) {
$trainingDate = ($date->tentative ? $this->netxtenHelpers->localeIntervalMonth($date->start, $date->end) : $this->netxtenHelpers->localeIntervalDay($date->start, $date->end));
$trainingDate = ($date->tentative ? $this->dateTimeFormatter->localeIntervalMonth($date->start, $date->end) : $this->dateTimeFormatter->localeIntervalDay($date->start, $date->end));
$el = Html::el()
->addHtml(Html::el('strong')->setText($trainingDate))
->addHtml(Html::el()->setText(' '))
Expand Down
19 changes: 15 additions & 4 deletions site/app/Templating/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace MichalSpacekCz\Templating;

use MichalSpacekCz\DateTime\DateTimeFormatter;
use MichalSpacekCz\Formatter\Texy;
use Nette\Utils\Html;

Expand All @@ -12,16 +13,26 @@ class Helpers
private Texy $texyFormatter;


public function __construct(Texy $texyFormatter)
public function __construct(Texy $texyFormatter, private DateTimeFormatter $dateTimeFormatter)
{
$this->texyFormatter = $texyFormatter;
}


public function loader(string $filter): ?callable
/**
* @return array<string, callable>
*/
public function getAll(): array
{
$callback = [$this, $filter];
return is_callable($callback) ? $callback : null;
return [
'staticUrl' => [$this, 'staticUrl'],
'staticImageUrl' => [$this, 'staticImageUrl'],
'format' => [$this, 'format'],
'localeDay' => [$this->dateTimeFormatter, 'localeDay'],
'localeMonth' => [$this->dateTimeFormatter, 'localeMonth'],
'localeIntervalDay' => [$this->dateTimeFormatter, 'localeIntervalDay'],
'localeIntervalMonth' => [$this->dateTimeFormatter, 'localeIntervalMonth'],
];
}


Expand Down
8 changes: 3 additions & 5 deletions site/app/Templating/TemplateFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@
use Nette\Caching\Storage;
use Nette\Http\IRequest;
use Nette\Security\User;
use Netxten\Templating\Helpers as NetxtenHelpers;

class TemplateFactory extends NetteTemplateFactory
{

public function __construct(
private LatteFactory $latteFactory,
private Theme $theme,
private NetxtenHelpers $netxtenHelpers,
private Helpers $templateHelpers,
private Translator $translator,
private ?IRequest $httpRequest = null,
Expand All @@ -37,9 +35,9 @@ public function createTemplate(Control $control = null, string $class = null): T
/** @var Template $template */
$template = parent::createTemplate($control, $class);
$template->darkMode = $this->theme->isDarkMode();
$template->getLatte()
->addFilterLoader([$this->netxtenHelpers, 'loader'])
->addFilterLoader([$this->templateHelpers, 'loader']);
foreach ($this->templateHelpers->getAll() as $name => $callback) {
$template->addFilter($name, $callback);
}
$template->setTranslator($this->translator);
return $template;
}
Expand Down
8 changes: 4 additions & 4 deletions site/app/Training/Dates.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
use Contributte\Translation\Translator;
use DateTime;
use DateTimeImmutable;
use MichalSpacekCz\DateTime\DateTimeFormatter;
use Nette\Database\Explorer;
use Nette\Database\Row;
use Nette\Utils\ArrayHash;
use Nette\Utils\Json;
use Netxten\Templating\Helpers;

class Dates
{
Expand All @@ -35,7 +35,7 @@ public function __construct(
private Explorer $database,
private Statuses $trainingStatuses,
private Prices $prices,
private Helpers $netxtenHelpers,
private DateTimeFormatter $dateTimeFormatter,
private Translator $translator,
) {
}
Expand Down Expand Up @@ -550,7 +550,7 @@ public function formatDateVenueForAdmin(ArrayHash $date): string
{
return sprintf(
'%s, %s',
$this->netxtenHelpers->localeIntervalDay($date->start, $date->end),
$this->dateTimeFormatter->localeIntervalDay($date->start, $date->end),
$date->remote ? $this->translator->translate('messages.label.remote') : $date->venueCity,
);
}
Expand All @@ -562,7 +562,7 @@ public function formatDateVenueForUser(ArrayHash $date): string
$end = $date->end ?? $date->trainingEnd;
return sprintf(
'%s, %s%s',
$date->tentative ? $this->netxtenHelpers->localeIntervalMonth($start, $end) : $this->netxtenHelpers->localeIntervalDay($start, $end),
$date->tentative ? $this->dateTimeFormatter->localeIntervalMonth($start, $end) : $this->dateTimeFormatter->localeIntervalDay($start, $end),
$date->remote ? $this->translator->translate('messages.label.remote') : $date->venueCity,
$date->tentative ? ' (' . $this->translator->translate('messages.label.tentativedate') . ')' : '',
);
Expand Down
Loading

0 comments on commit 98f0dbe

Please sign in to comment.