Next major version 2 with PHP 8.1, Symfony 6, Tabler UI, 2FA ... (#2902)

This commit is contained in:
Kevin Papst
2022-12-31 21:19:55 +01:00
committed by GitHub
parent 95e06746bd
commit 90a0fd8a22
2164 changed files with 83700 additions and 86426 deletions

View File

@@ -16,22 +16,14 @@ use Twig\Extension\RuntimeExtensionInterface;
final class EncoreExtension implements RuntimeExtensionInterface, ServiceSubscriberInterface
{
/**
* @var string
*/
private $publicDir;
/**
* @var ContainerInterface
*/
private $container;
private string $publicDir;
public function __construct(ContainerInterface $container, string $projectDirectory)
public function __construct(private ContainerInterface $container, string $projectDirectory)
{
$this->container = $container;
$this->publicDir = $projectDirectory . '/public';
}
public static function getSubscribedServices()
public static function getSubscribedServices(): array
{
return [
EntrypointLookupInterface::class,

View File

@@ -15,23 +15,10 @@ use Twig\Extension\RuntimeExtensionInterface;
final class MarkdownExtension implements RuntimeExtensionInterface
{
/**
* @var Markdown
*/
private $markdown;
/**
* @var SystemConfiguration
*/
private $configuration;
/**
* @var bool|null
*/
private $markdownEnabled;
private ?bool $markdownEnabled = null;
public function __construct(Markdown $parser, SystemConfiguration $configuration)
public function __construct(private Markdown $markdown, private SystemConfiguration $configuration)
{
$this->markdown = $parser;
$this->configuration = $configuration;
}
private function isMarkdownEnabled(): bool

View File

@@ -16,11 +16,8 @@ use Twig\Extension\RuntimeExtensionInterface;
final class ReportingExtension implements RuntimeExtensionInterface
{
private $service;
public function __construct(ReportingService $reportingService)
public function __construct(private ReportingService $service)
{
$this->service = $reportingService;
}
/**

View File

@@ -16,6 +16,7 @@ use App\Event\PageActionsEvent;
use App\Event\ThemeEvent;
use App\Event\ThemeJavascriptTranslationsEvent;
use App\Utils\Color;
use App\Utils\FormFormatConverter;
use Symfony\Bridge\Twig\AppVariable;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -24,19 +25,8 @@ use Twig\Extension\RuntimeExtensionInterface;
final class ThemeExtension implements RuntimeExtensionInterface
{
private $eventDispatcher;
private $translator;
private $configuration;
/**
* @var bool
*/
private $randomColors;
public function __construct(EventDispatcherInterface $dispatcher, TranslatorInterface $translator, SystemConfiguration $configuration)
public function __construct(private EventDispatcherInterface $eventDispatcher, private TranslatorInterface $translator, private SystemConfiguration $configuration)
{
$this->eventDispatcher = $dispatcher;
$this->translator = $translator;
$this->configuration = $configuration;
}
/**
@@ -65,10 +55,8 @@ final class ThemeExtension implements RuntimeExtensionInterface
{
$themeEvent = new PageActionsEvent($user, $payload, $action, $view);
$eventName = 'actions.' . $action;
if ($this->eventDispatcher->hasListeners($eventName)) {
$this->eventDispatcher->dispatch($themeEvent, $eventName);
if ($this->eventDispatcher->hasListeners($themeEvent->getEventName())) {
$this->eventDispatcher->dispatch($themeEvent, $themeEvent->getEventName());
}
return $themeEvent;
@@ -80,14 +68,19 @@ final class ThemeExtension implements RuntimeExtensionInterface
$this->eventDispatcher->dispatch($event);
return $event->getTranslations();
$all = [];
foreach ($event->getTranslations() as $key => $translation) {
$all[$key] = $this->translator->trans($translation[0], [], $translation[1]);
}
return $all;
}
public function getProgressbarClass(float $percent, ?bool $reverseColors = false): string
{
$colors = ['xl' => 'progress-bar-danger', 'l' => 'progress-bar-warning', 'm' => 'progress-bar-success', 's' => 'progress-bar-primary', 'e' => 'progress-bar-info'];
$colors = ['xl' => 'bg-red', 'l' => 'bg-warning', 'm' => 'bg-green', 's' => 'bg-green', 'e' => ''];
if (true === $reverseColors) {
$colors = ['s' => 'progress-bar-danger', 'm' => 'progress-bar-warning', 'l' => 'progress-bar-success', 'xl' => 'progress-bar-primary', 'e' => 'progress-bar-info'];
$colors = ['s' => 'bg-red', 'm' => 'bg-warning', 'l' => 'bg-green', 'xl' => 'bg-green', 'e' => ''];
}
if ($percent > 90) {
@@ -107,58 +100,44 @@ final class ThemeExtension implements RuntimeExtensionInterface
public function generateTitle(?string $prefix = null, string $delimiter = ' – '): string
{
$title = $this->configuration->getBrandingTitle();
if (null === $title || \strlen($title) === 0) {
$title = Constants::SOFTWARE;
}
return ($prefix ?? '') . $title . $delimiter . $this->translator->trans('time_tracking', [], 'messages');
return ($prefix ?? '') . Constants::SOFTWARE . $delimiter . $this->translator->trans('time_tracking', [], 'messages');
}
/**
* @param string $name
* @return mixed
* @deprecated since 1.15
*/
public function getThemeConfig(string $name)
{
@trigger_error('The twig function "theme_config" was deprecated with 1.15, replace it with the global "kimai_config" variable.', E_USER_DEPRECATED);
switch ($name) {
case 'auto_reload_datatable':
@trigger_error('The configuration auto_reload_datatable is deprecated and was removed with 1.4', E_USER_DEPRECATED);
return false;
case 'soft_limit':
return $this->configuration->getTimesheetActiveEntriesHardLimit();
default:
$name = 'theme.' . $name;
break;
}
return $this->configuration->find($name);
}
public function colorize(?string $color, ?string $identifier = null, ?string $fallback = null): string
public function colorize(?string $color, ?string $identifier = null): string
{
if ($color !== null) {
return $color;
}
if ($this->randomColors === null) {
$this->randomColors = $this->configuration->isThemeRandomColors();
return (new Color())->getRandom($identifier);
}
public function getTimePresets(string $timezone, string $format): array
{
$converter = new FormFormatConverter();
$format = $converter->convert($format);
$intervalMinutes = $this->configuration->getTimesheetIncrementMinutes();
if ($intervalMinutes < 5) {
return [];
}
if ($this->randomColors) {
return (new Color())->getRandom($identifier);
$maxMinutes = 24 * 60 - $intervalMinutes;
$date = new \DateTime('now', new \DateTimeZone($timezone));
$date->setTime(0, 0, 0);
$presets = [
$date->format($format)
];
for ($minutes = $intervalMinutes; $minutes <= $maxMinutes; $minutes += $intervalMinutes) {
$date->modify('+' . $intervalMinutes . ' minutes');
$presets[] = $date->format($format);
}
if ($fallback !== null) {
return $fallback;
}
return Constants::DEFAULT_COLOR;
return $presets;
}
}

View File

@@ -9,24 +9,36 @@
namespace App\Twig\Runtime;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Model\FavoriteTimesheet;
use App\Repository\TimesheetRepository;
use App\Timesheet\FavoriteRecordService;
use Twig\Extension\RuntimeExtensionInterface;
final class TimesheetExtension implements RuntimeExtensionInterface
{
/**
* @var TimesheetRepository
*/
private $repository;
public function __construct(TimesheetRepository $repository)
public function __construct(private TimesheetRepository $repository, private FavoriteRecordService $favoriteRecordService)
{
$this->repository = $repository;
}
public function activeEntries(User $user): array
/**
* @param User $user
* @param bool $ticktac
* @return array<Timesheet>
*/
public function activeEntries(User $user, bool $ticktac = true): array
{
return $this->repository->getActiveEntries($user);
return $this->repository->getActiveEntries($user, $ticktac);
}
/**
* @param User $user
* @param int $limit
* @return array<FavoriteTimesheet>
*/
public function favoriteEntries(User $user, int $limit = 5): array
{
return $this->favoriteRecordService->favoriteEntries($user, $limit);
}
}

View File

@@ -9,21 +9,18 @@
namespace App\Twig\Runtime;
use App\Entity\User;
use App\Widget\WidgetException;
use App\Widget\WidgetInterface;
use App\Widget\WidgetService;
use Symfony\Component\Security\Core\Security;
use Twig\Environment;
use Twig\Extension\RuntimeExtensionInterface;
final class WidgetExtension implements RuntimeExtensionInterface
{
/**
* @var WidgetService
*/
private $service;
public function __construct(WidgetService $service)
public function __construct(private WidgetService $service, private Security $security)
{
$this->service = $service;
}
/**
@@ -32,10 +29,10 @@ final class WidgetExtension implements RuntimeExtensionInterface
* @return string
* @throws WidgetException
*/
public function renderWidget($widget, array $options = [])
public function renderWidget(Environment $environment, $widget, array $options = []): string
{
if (!($widget instanceof WidgetInterface) && !\is_string($widget)) {
throw new \InvalidArgumentException('Widget must either implement WidgetInterface or be a string');
throw new \InvalidArgumentException('Widget must be either a WidgetInterface or a string');
}
if (\is_string($widget)) {
@@ -46,8 +43,18 @@ final class WidgetExtension implements RuntimeExtensionInterface
$widget = $this->service->getWidget($widget);
}
$renderer = $this->service->findRenderer($widget);
$user = $this->security->getUser();
if ($user instanceof User) {
$widget->setUser($user);
}
return $renderer->render($widget, $options);
$options = $widget->getOptions($options);
return $environment->render($widget->getTemplateName(), [
'data' => $widget->getData($options),
'options' => $options,
'title' => $widget->getTitle(),
'widget' => $widget,
]);
}
}