Ran rector to convert some our twig extensions to use #[AsTwigXX] attributes

This commit is contained in:
Jan Böhmer 2026-02-14 23:53:31 +01:00
parent c8b1320bb9
commit f69b0889eb
11 changed files with 34 additions and 67 deletions

View file

@ -147,10 +147,7 @@ class SecurityController extends AbstractController
'label' => 'user.settings.pw_confirm.label', 'label' => 'user.settings.pw_confirm.label',
], ],
'invalid_message' => 'password_must_match', 'invalid_message' => 'password_must_match',
'constraints' => [new Length([ 'constraints' => [new Length(min: 6, max: 128)],
'min' => 6,
'max' => 128,
])],
]); ]);
$builder->add('submit', SubmitType::class, [ $builder->add('submit', SubmitType::class, [

View file

@ -295,10 +295,7 @@ class UserSettingsController extends AbstractController
'autocomplete' => 'new-password', 'autocomplete' => 'new-password',
], ],
], ],
'constraints' => [new Length([ 'constraints' => [new Length(min: 6, max: 128)],
'min' => 6,
'max' => 128,
])],
]) ])
->add('submit', SubmitType::class, [ ->add('submit', SubmitType::class, [
'label' => 'save', 'label' => 'save',

View file

@ -122,9 +122,7 @@ class AttachmentFormType extends AbstractType
], ],
'constraints' => [ 'constraints' => [
//new AllowedFileExtension(), //new AllowedFileExtension(),
new File([ new File(maxSize: $options['max_file_size']),
'maxSize' => $options['max_file_size'],
]),
], ],
]); ]);

View file

@ -62,7 +62,7 @@ class FieldToProviderMappingType extends AbstractType
'style' => 'width: 80px;' 'style' => 'width: 80px;'
], ],
'constraints' => [ 'constraints' => [
new Range(['min' => 1, 'max' => 10]), new Range(min: 1, max: 10),
], ],
]); ]);
} }

View file

@ -177,10 +177,7 @@ class UserAdminForm extends AbstractType
'required' => false, 'required' => false,
'mapped' => false, 'mapped' => false,
'disabled' => !$this->security->isGranted('set_password', $entity) || $entity->isSamlUser(), 'disabled' => !$this->security->isGranted('set_password', $entity) || $entity->isSamlUser(),
'constraints' => [new Length([ 'constraints' => [new Length(min: 6, max: 128)],
'min' => 6,
'max' => 128,
])],
]) ])
->add('need_pw_change', CheckboxType::class, [ ->add('need_pw_change', CheckboxType::class, [

View file

@ -92,9 +92,7 @@ class UserSettingsType extends AbstractType
'accept' => 'image/*', 'accept' => 'image/*',
], ],
'constraints' => [ 'constraints' => [
new File([ new File(maxSize: '5M'),
'maxSize' => '5M',
]),
], ],
]) ])
->add('aboutMe', RichTextEditorType::class, [ ->add('aboutMe', RichTextEditorType::class, [

View file

@ -23,31 +23,25 @@ declare(strict_types=1);
namespace App\Twig; namespace App\Twig;
use Twig\Attribute\AsTwigFunction;
use App\Services\InfoProviderSystem\ProviderRegistry; use App\Services\InfoProviderSystem\ProviderRegistry;
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface; use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFunction; use Twig\TwigFunction;
class InfoProviderExtension extends AbstractExtension class InfoProviderExtension
{ {
public function __construct( public function __construct(
private readonly ProviderRegistry $providerRegistry private readonly ProviderRegistry $providerRegistry
) {} ) {}
public function getFunctions(): array
{
return [
new TwigFunction('info_provider', $this->getInfoProvider(...)),
new TwigFunction('info_provider_label', $this->getInfoProviderName(...))
];
}
/** /**
* Gets the info provider with the given key. Returns null, if the provider does not exist. * Gets the info provider with the given key. Returns null, if the provider does not exist.
* @param string $key * @param string $key
* @return InfoProviderInterface|null * @return InfoProviderInterface|null
*/ */
private function getInfoProvider(string $key): ?InfoProviderInterface #[AsTwigFunction(name: 'info_provider')]
public function getInfoProvider(string $key): ?InfoProviderInterface
{ {
try { try {
return $this->providerRegistry->getProviderByKey($key); return $this->providerRegistry->getProviderByKey($key);
@ -61,7 +55,8 @@ class InfoProviderExtension extends AbstractExtension
* @param string $key * @param string $key
* @return string|null * @return string|null
*/ */
private function getInfoProviderName(string $key): ?string #[AsTwigFunction(name: 'info_provider_label')]
public function getInfoProviderName(string $key): ?string
{ {
try { try {
return $this->providerRegistry->getProviderByKey($key)->getProviderInfo()['name']; return $this->providerRegistry->getProviderByKey($key)->getProviderInfo()['name'];

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/ */
namespace App\Twig; namespace App\Twig;
use Twig\Attribute\AsTwigFunction;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use App\Services\LogSystem\EventCommentType; use App\Services\LogSystem\EventCommentType;
@ -31,23 +32,14 @@ use Twig\TwigFunction;
use App\Services\LogSystem\EventCommentNeededHelper; use App\Services\LogSystem\EventCommentNeededHelper;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
final class MiscExtension extends AbstractExtension final class MiscExtension
{ {
public function __construct(private readonly EventCommentNeededHelper $eventCommentNeededHelper) public function __construct(private readonly EventCommentNeededHelper $eventCommentNeededHelper)
{ {
} }
public function getFunctions(): array #[AsTwigFunction(name: 'event_comment_needed')]
{ public function evenCommentNeeded(string|EventCommentType $operation_type): bool
return [
new TwigFunction('event_comment_needed', $this->evenCommentNeeded(...)),
new TwigFunction('settings_icon', $this->settingsIcon(...)),
new TwigFunction('uri_without_host', $this->uri_without_host(...))
];
}
private function evenCommentNeeded(string|EventCommentType $operation_type): bool
{ {
if (is_string($operation_type)) { if (is_string($operation_type)) {
$operation_type = EventCommentType::from($operation_type); $operation_type = EventCommentType::from($operation_type);
@ -63,7 +55,8 @@ final class MiscExtension extends AbstractExtension
* @return string|null * @return string|null
* @throws \ReflectionException * @throws \ReflectionException
*/ */
private function settingsIcon(string|object $objectOrClass): ?string #[AsTwigFunction(name: 'settings_icon')]
public function settingsIcon(string|object $objectOrClass): ?string
{ {
//If the given object is a proxy, then get the real object //If the given object is a proxy, then get the real object
if (is_a($objectOrClass, SettingsProxyInterface::class)) { if (is_a($objectOrClass, SettingsProxyInterface::class)) {
@ -82,6 +75,7 @@ final class MiscExtension extends AbstractExtension
* @param Request $request * @param Request $request
* @return string * @return string
*/ */
#[AsTwigFunction(name: 'uri_without_host')]
public function uri_without_host(Request $request): string public function uri_without_host(Request $request): string
{ {
if (null !== $qs = $request->getQueryString()) { if (null !== $qs = $request->getQueryString()) {

View file

@ -22,6 +22,8 @@ declare(strict_types=1);
*/ */
namespace App\Twig; namespace App\Twig;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Twig\Attribute\AsTwigFunction;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFilter; use Twig\TwigFilter;
@ -32,23 +34,15 @@ use Twig\TwigTest;
* The functionalities here extend the Twig with some core functions, which are independently of Part-DB. * The functionalities here extend the Twig with some core functions, which are independently of Part-DB.
* @see \App\Tests\Twig\TwigCoreExtensionTest * @see \App\Tests\Twig\TwigCoreExtensionTest
*/ */
final class TwigCoreExtension extends AbstractExtension final class TwigCoreExtension
{ {
private readonly ObjectNormalizer $objectNormalizer; private readonly NormalizerInterface $objectNormalizer;
public function __construct() public function __construct()
{ {
$this->objectNormalizer = new ObjectNormalizer(); $this->objectNormalizer = new ObjectNormalizer();
} }
public function getFunctions(): array
{
return [
/* Returns the enum cases as values */
new TwigFunction('enum_cases', $this->getEnumCases(...)),
];
}
public function getTests(): array public function getTests(): array
{ {
return [ return [
@ -66,6 +60,7 @@ final class TwigCoreExtension extends AbstractExtension
* @param string $enum_class * @param string $enum_class
* @phpstan-param class-string $enum_class * @phpstan-param class-string $enum_class
*/ */
#[AsTwigFunction(name: 'enum_cases')]
public function getEnumCases(string $enum_class): array public function getEnumCases(string $enum_class): array
{ {
if (!enum_exists($enum_class)) { if (!enum_exists($enum_class)) {

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Twig; namespace App\Twig;
use Twig\Attribute\AsTwigFunction;
use App\Services\System\UpdateAvailableFacade; use App\Services\System\UpdateAvailableFacade;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
@ -31,7 +32,7 @@ use Twig\TwigFunction;
/** /**
* Twig extension for update-related functions. * Twig extension for update-related functions.
*/ */
final class UpdateExtension extends AbstractExtension final class UpdateExtension
{ {
public function __construct(private readonly UpdateAvailableFacade $updateAvailableManager, public function __construct(private readonly UpdateAvailableFacade $updateAvailableManager,
private readonly Security $security) private readonly Security $security)
@ -39,18 +40,10 @@ final class UpdateExtension extends AbstractExtension
} }
public function getFunctions(): array
{
return [
new TwigFunction('is_update_available', $this->isUpdateAvailable(...)),
new TwigFunction('get_latest_version', $this->getLatestVersion(...)),
new TwigFunction('get_latest_version_url', $this->getLatestVersionUrl(...)),
];
}
/** /**
* Check if an update is available and the user has permission to see it. * Check if an update is available and the user has permission to see it.
*/ */
#[AsTwigFunction(name: 'is_update_available')]
public function isUpdateAvailable(): bool public function isUpdateAvailable(): bool
{ {
// Only show to users with the show_updates permission // Only show to users with the show_updates permission
@ -64,6 +57,7 @@ final class UpdateExtension extends AbstractExtension
/** /**
* Get the latest available version string. * Get the latest available version string.
*/ */
#[AsTwigFunction(name: 'get_latest_version')]
public function getLatestVersion(): string public function getLatestVersion(): string
{ {
return $this->updateAvailableManager->getLatestVersionString(); return $this->updateAvailableManager->getLatestVersionString();
@ -72,6 +66,7 @@ final class UpdateExtension extends AbstractExtension
/** /**
* Get the URL to the latest version release page. * Get the URL to the latest version release page.
*/ */
#[AsTwigFunction(name: 'get_latest_version_url')]
public function getLatestVersionUrl(): string public function getLatestVersionUrl(): string
{ {
return $this->updateAvailableManager->getLatestVersionUrl(); return $this->updateAvailableManager->getLatestVersionUrl();

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Twig; namespace App\Twig;
use Twig\Attribute\AsTwigFunction;
use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractDBElement;
use App\Entity\UserSystem\User; use App\Entity\UserSystem\User;
use App\Entity\LogSystem\AbstractLogEntry; use App\Entity\LogSystem\AbstractLogEntry;
@ -57,7 +58,7 @@ use Twig\TwigFunction;
/** /**
* @see \App\Tests\Twig\UserExtensionTest * @see \App\Tests\Twig\UserExtensionTest
*/ */
final class UserExtension extends AbstractExtension final class UserExtension
{ {
private readonly LogEntryRepository $repo; private readonly LogEntryRepository $repo;
@ -82,9 +83,6 @@ final class UserExtension extends AbstractExtension
new TwigFunction('last_editing_user', fn(AbstractDBElement $element): ?User => $this->repo->getLastEditingUser($element)), new TwigFunction('last_editing_user', fn(AbstractDBElement $element): ?User => $this->repo->getLastEditingUser($element)),
/* Returns the user which has created the given entity. */ /* Returns the user which has created the given entity. */
new TwigFunction('creating_user', fn(AbstractDBElement $element): ?User => $this->repo->getCreatingUser($element)), new TwigFunction('creating_user', fn(AbstractDBElement $element): ?User => $this->repo->getCreatingUser($element)),
new TwigFunction('impersonator_user', $this->getImpersonatorUser(...)),
new TwigFunction('impersonation_active', $this->isImpersonationActive(...)),
new TwigFunction('impersonation_path', $this->getImpersonationPath(...)),
]; ];
} }
@ -93,6 +91,7 @@ final class UserExtension extends AbstractExtension
* If the current user is not impersonated, null is returned. * If the current user is not impersonated, null is returned.
* @return User|null * @return User|null
*/ */
#[AsTwigFunction(name: 'impersonator_user')]
public function getImpersonatorUser(): ?User public function getImpersonatorUser(): ?User
{ {
$token = $this->security->getToken(); $token = $this->security->getToken();
@ -107,11 +106,13 @@ final class UserExtension extends AbstractExtension
return null; return null;
} }
#[AsTwigFunction(name: 'impersonation_active')]
public function isImpersonationActive(): bool public function isImpersonationActive(): bool
{ {
return $this->security->isGranted('IS_IMPERSONATOR'); return $this->security->isGranted('IS_IMPERSONATOR');
} }
#[AsTwigFunction(name: 'impersonation_path')]
public function getImpersonationPath(User $user, string $route_name = 'homepage'): string public function getImpersonationPath(User $user, string $route_name = 'homepage'): string
{ {
if (! $this->security->isGranted('CAN_SWITCH_USER', $user)) { if (! $this->security->isGranted('CAN_SWITCH_USER', $user)) {