Files
myep-team/src/Twig/AppRuntime.php
T

302 lines
9.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Twig;
use App\BusProNet\DataProvider\CountryDataProvider;
use App\BusProNet\DataProvider\PickupDataProvider;
use App\Entity\SeasonAssignment;
use App\Entity\Teamer;
use App\Entity\Upload;
use App\Service\Season\SeasonAssignmentLabeler;
use App\Service\Teamer\PickupResolver;
use Carbon\CarbonImmutable;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;
use Twig\Extension\RuntimeExtensionInterface;
use Twig\Extra\Intl\IntlExtension;
class AppRuntime implements RuntimeExtensionInterface
{
public function __construct(
private readonly RequestStack $requestStack,
private readonly IntlExtension $intlExtension,
private readonly TranslatorInterface $translator,
private readonly CountryDataProvider $countries,
private readonly PickupDataProvider $pickups,
private readonly PickupResolver $pickupResolver,
private readonly SeasonAssignmentLabeler $seasonAssignmentLabeler,
private readonly string $environment,
) {
}
/**
* Minutes as hours and minutes, the way a timesheet reads them: 510 becomes "8:30".
*
* Hours are not padded and not capped at 24 - a month total is a perfectly ordinary
* "195:45". Null is a day the SaaS never reported, which is not the same as zero.
*/
public function formatDurationHoursMinutes(?int $minutes, string $empty = '–'): string
{
if (null === $minutes) {
return $empty;
}
$sign = $minutes < 0 ? '-' : '';
$minutes = abs($minutes);
return sprintf('%s%d:%02d', $sign, intdiv($minutes, 60), $minutes % 60);
}
public function seasonAssignmentLabel(SeasonAssignment $seasonAssignment): string
{
return $this->seasonAssignmentLabeler->label($seasonAssignment);
}
/**
* The house name for a stored hotel code. Only the code is stored, so every template that
* shows a house resolves it here rather than freezing a name into the record.
*/
public function houseLabel(?string $hotelCode): string
{
return $this->seasonAssignmentLabeler->houseLabel($hotelCode);
}
/**
* All-season is a flag on top of the status, not a status of its own - a teamer can be a
* Bestandsteamer:in and an all-season teamer at once. The general Teamübersicht is the only
* place that overlap is not otherwise visible, so the marker is appended there; the
* dedicated Saisonteamer list passes false, where repeating it on every row says nothing.
*/
public function teamerStatusLabel(Teamer $teamer, bool $includeAllSeason = true): string
{
$label = $this->baseTeamerStatusLabel($teamer);
if (true === $includeAllSeason && true === $teamer->isAllSeason()) {
return sprintf('%s · Saison', $label);
}
return $label;
}
private function baseTeamerStatusLabel(Teamer $teamer): string
{
$labelItems = [];
$user = $teamer->getUser();
if (null !== $user) {
if ($user->hasRole('ROLE_TEAM_ADMIN')) {
$labelItems[] = 'Admin';
}
if ($user->hasRole('ROLE_MANAGER')) {
$labelItems[] = 'Reisemanagement';
}
if ($user->hasRole('ROLE_HOUSE_MANAGER')) {
$labelItems[] = 'Hausleitung';
}
}
if (0 < count($labelItems)) {
return implode(', ', $labelItems);
}
if (Teamer::STATUS_NEW === $teamer->getStatus()) {
return 'Neuteamer:in';
}
return 'Bestandsteamer:in';
}
public function licenseLabel(string $type): string
{
return sprintf('Offizielle %slehrer:innenlizenz', ucfirst(strtolower($type)));
}
public function bpnCountryLabel(?string $token, string $property = 'name'): string
{
$country = $this->countries->get($token);
if (null === $country) {
return 'unbekannt';
}
return 'nationality' === $property ? $country->getNationality() : $country->getName();
}
public function bpnPickupLabel($id): ?string
{
if (null === $id) {
return 'keine Busbegleitung';
}
$pickup = $this->pickups->get((int) $id);
if (null === $pickup) {
return null;
}
return 'ab '.$pickup->getCity();
}
public function hasPickup(?int $pickupId, Teamer $teamer): bool
{
return $this->pickupResolver->hasPickup($pickupId, $teamer);
}
public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string
{
$icon = match ($mimeType) {
'application/pdf' => 'pdf',
'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'excel',
'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'word',
default => 'download',
};
return $this->renderIcon($environment, $icon, $classes);
}
public function formatBytes(int $bytes, ?int $precision = 2): string
{
$size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$precision}f", $bytes / (1024 ** $factor)).@$size[$factor];
}
public function formatMoney(int $amount): string
{
// Amounts are stored as integers so divide by 100 first
$amount = $amount / 100;
return $this->intlExtension->formatCurrency($amount, 'EUR');
}
public function formatRating(?int $rating): string
{
if (null === $rating) {
return '-';
}
// Ratings are stored as integers so divide by 100 first
$rating = $rating / 100;
return '&Oslash; '.$this->intlExtension->formatNumber($rating, ['fraction_digit' => 2]);
}
public function renderIcon(Environment $environment, string $icon, string $classes = 'w-5 h-5'): string
{
return $environment->render('_partials/_icon.html.twig', [
'icon' => $icon,
'class' => $classes,
]);
}
public function renderUploadStatusBadge(string $status): string
{
$label = $this->translator->trans('label.document.status.'.$status);
$class = 'upload-status-badge ';
$class .= match ($status) {
Upload::STATUS_NEW => 'upload-status-badge--new',
Upload::STATUS_REJECTED => 'upload-status-badge--error',
Upload::STATUS_PAID => 'upload-status-badge--paid',
Upload::STATUS_CHECKED => 'upload-status-badge--checked',
default => 'upload-status-badge--default',
};
return sprintf('<span class="%s">%s</span>', $class, $label);
}
public function nl2List(?string $content, string $class = 'list-disc pl-4'): string
{
if (null === $content) {
return '';
}
$items = explode(PHP_EOL, $content);
$list = '<ul class="'.$class.'">';
foreach ($items as $item) {
$list .= '<li>'.htmlspecialchars($item, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8').'</li>';
}
$list .= '</ul>';
return $list;
}
public function isCurrentRoute(string $route): bool
{
$requestedRoute = $this->requestStack->getMainRequest()->attributes->get('_route');
return $requestedRoute === $route;
}
/**
* The attribute is set by MaintenanceModeListener, on the ip whitelist branch only.
*/
public function isMaintenanceMode(): bool
{
return true === $this->requestStack->getMainRequest()?->attributes->get('_maintenance_mode_allowed');
}
public function getEncodedReturnUrl(): string
{
$masterRequest = $this->requestStack->getMainRequest();
if (null === $masterRequest) {
return '';
}
return rawurlencode($masterRequest->getRequestUri());
}
/**
* Passes the return url of the current page on to the next one.
*
* Used by links that lead deeper into a detail view or trigger an action on it:
* they have to keep pointing back at where the user originally came from instead
* of at the page they sit on. Null when there is nothing to pass on, so that the
* url generator drops the parameter rather than emitting an empty one.
*/
public function getForwardedReturnUrl(): ?string
{
$returnUrl = $this->requestStack->getMainRequest()?->query->get('r');
return is_string($returnUrl) && '' !== $returnUrl ? $returnUrl : null;
}
public function renderQaAttribute(string $label, ?string $value = null): string
{
if ('test' !== $this->environment) {
return '';
}
if (null === $value) {
return sprintf(' data-qa-%s', strtolower($label));
}
return sprintf(' data-qa-%s="%s"', strtolower($label), $value);
}
public function dateDiffForHumans(\DateTimeInterface $dateTime, ?\DateTimeInterface $other = null): string
{
$oldLocale = CarbonImmutable::getLocale();
$locale = $this->requestStack->getMainRequest()->getLocale();
CarbonImmutable::setLocale($locale);
$result = CarbonImmutable::instance($dateTime)->diffForHumans($other);
CarbonImmutable::setLocale($oldLocale);
return $result;
}
public function getFilenameWithFolder(Upload $upload): string
{
$folder = substr($upload->getFilename(), 0, 1);
return sprintf('%s/%s', $folder, $upload->getFilename());
}
}