Skip to content

Conversation

mnocon
Copy link
Contributor

@mnocon mnocon commented Sep 22, 2025

This PR fixes the following error:

 ------ --------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  Line   back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationValueMapper.php                                                                          
 ------ --------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  :13    Return type bool of method App\Security\Limitation\Mapper\CustomLimitationValueMapper::mapLimitationValue() is not covariant with return type array of method  
         Ibexa\AdminUi\Limitation\LimitationValueMapperInterface::mapLimitationValue().                                                                                 
 ------ -----------------------------------------------------------------------------------------

The interface is typehinted to return array, not bool as in our example:
https://github.com/ibexa/admin-ui/blob/main/src/lib/Limitation/LimitationValueMapperInterface.php#L23

Other things done:

  1. Extracted CustomController to separate file and fixed PHPStan issues.
    The last commit contains changes coming from Rector - added the interface introduced in IBX-10170: Introduced AccessCheckController contract user#111
  2. Ibexified the examples - changed occuranges of ez to ibexa

Notes:

  1. It's working!
Screenshot 2025-09-22 at 18 28 45 Screenshot 2025-09-22 at 18 27 40 2) The Notification errors reported by PHPStan are fixed in https://github.com//pull/2911 (on 4.6 first), I will merge them to 5.0 and remove the baseline changes once that PR is approved.

Copy link

Preview of modified files

Preview of modified Markdown:

Copy link

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/back_office/limitation/src/Controller/CustomController.php


code_samples/back_office/limitation/src/Controller/CustomController.php

docs/permissions/custom_policies.md@253:```php
docs/permissions/custom_policies.md@254:[[= include_file('code_samples/back_office/limitation/src/Controller/CustomController.php') =]]
docs/permissions/custom_policies.md@255:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\Controller;
004⫶
005⫶use App\Security\Limitation\CustomLimitationValue;
006⫶use Ibexa\Contracts\AdminUi\Controller\Controller;
007⫶use Ibexa\Contracts\AdminUi\Permission\PermissionCheckerInterface;
008⫶use Ibexa\Contracts\Core\Repository\PermissionResolver;
009⫶use Ibexa\Contracts\User\Controller\AuthenticatedRememberedCheckTrait;
010⫶use Ibexa\Contracts\User\Controller\RestrictedControllerInterface;
011⫶use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute;
012⫶use Symfony\Component\HttpFoundation\Request;
013⫶use Symfony\Component\HttpFoundation\Response;
014⫶
015⫶class CustomController extends Controller implements RestrictedControllerInterface
016⫶{
017⫶ use AuthenticatedRememberedCheckTrait {
018⫶ AuthenticatedRememberedCheckTrait::performAccessCheck as public traitPerformAccessCheck;
019⫶ }
020⫶
021⫶ public function __construct(
022⫶ // ...,
023⫶ private readonly PermissionResolver $permissionResolver,
024⫶ private readonly PermissionCheckerInterface $permissionChecker
025⫶ ) {
026⫶ }
027⫶
028⫶ // Controller actions...
029⫶ public function customAction(Request $request): Response
030⫶ {
031⫶ // ...
032⫶ if ($this->getCustomLimitationValue()) {
033⫶ // Action only for user having the custom limitation checked
034⫶ }
035⫶
036⫶ return new Response('<html><body>...</body></html>');
037⫶ }
038⫶
039⫶ private function getCustomLimitationValue(): bool
040⫶ {
041⫶ $hasAccess = $this->permissionResolver->hasAccess('custom_module', 'custom_function_2');
042⫶
043⫶ if (is_bool($hasAccess)) {
044⫶ return $hasAccess;
045⫶ }
046⫶
047⫶ $customLimitationValues = $this->permissionChecker->getRestrictions($hasAccess, CustomLimitationValue::class);
048⫶
049⫶ return $customLimitationValues['value'] ?? false;
050⫶ }
051⫶
052⫶ public function performAccessCheck(): void
053⫶ {
054⫶ $this->traitPerformAccessCheck();
055⫶ $this->denyAccessUnlessGranted(new Attribute('custom_module', 'custom_function_2'));
056⫶ }
057⫶}


code_samples/back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationValueMapper.php

docs/permissions/custom_policies.md@216:``` php
docs/permissions/custom_policies.md@217:[[= include_file('code_samples/back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationValueMapper.php') =]]
docs/permissions/custom_policies.md@218:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Security\Limitation\Mapper;
006⫶
007⫶use Ibexa\AdminUi\Limitation\LimitationValueMapperInterface;
008⫶use Ibexa\Contracts\Core\Repository\Values\User\Limitation;
009⫶
010⫶class CustomLimitationValueMapper implements LimitationValueMapperInterface
011⫶{

code_samples/back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationValueMapper.php

docs/permissions/custom_policies.md@216:``` php
docs/permissions/custom_policies.md@217:[[= include_file('code_samples/back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationValueMapper.php') =]]
docs/permissions/custom_policies.md@218:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Security\Limitation\Mapper;
006⫶
007⫶use Ibexa\AdminUi\Limitation\LimitationValueMapperInterface;
008⫶use Ibexa\Contracts\Core\Repository\Values\User\Limitation;
009⫶
010⫶class CustomLimitationValueMapper implements LimitationValueMapperInterface
011⫶{
012⫶    public function mapLimitationValue(Limitation $limitation): bool
013⫶ {
014⫶ return $limitation->limitationValues['value'];
015⫶ }
016⫶}
012⫶    /** return array<bool> */
013⫶ public function mapLimitationValue(Limitation $limitation): array
014⫶ {
015⫶ return [$limitation->limitationValues['value']];
016⫶ }
017⫶}


code_samples/back_office/limitation/templates/themes/standard/limitation/custom_limitation_value.html.twig

docs/permissions/custom_policies.md@231:``` html+twig
docs/permissions/custom_policies.md@232:[[= include_file('code_samples/back_office/limitation/templates/themes/standard/limitation/custom_limitation_value.html.twig') =]]
docs/permissions/custom_policies.md@233:```

001⫶{# templates/themes/standard/limitation/custom_limitation_value.html.twig #}


code_samples/back_office/limitation/templates/themes/standard/limitation/custom_limitation_value.html.twig

docs/permissions/custom_policies.md@231:``` html+twig
docs/permissions/custom_policies.md@232:[[= include_file('code_samples/back_office/limitation/templates/themes/standard/limitation/custom_limitation_value.html.twig') =]]
docs/permissions/custom_policies.md@233:```

001⫶{# templates/themes/standard/limitation/custom_limitation_value.html.twig #}
002⫶{% block ez_limitation_customlimitation_value %}
003⫶ <span style="color: {{ values ? 'green' : 'red' }};">{{ values ? 'Yes' : 'No' }}</span>
004⫶{% endblock %}
002⫶{% block ibexa_limitation_customlimitation_value %}
003⫶ {% set isSet = values | first %}
004⫶ <span style="color: {{ isSet ? 'green' : 'red' }};">{{ isSet ? 'Yes' : 'No' }}</span>
005⫶{% endblock %}


code_samples/back_office/notifications/src/Notification/MyRenderer.php

docs/administration/back_office/notifications.md@72:```php
docs/administration/back_office/notifications.md@73:[[= include_file('code_samples/back_office/notifications/src/Notification/MyRenderer.php') =]]
docs/administration/back_office/notifications.md@74:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Notification;
006⫶
007⫶use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
008⫶use Ibexa\Core\Notification\Renderer\NotificationRenderer;
009⫶use Ibexa\Core\Notification\Renderer\TypedNotificationRendererInterface;
010⫶use Symfony\Component\Routing\RouterInterface;
011⫶use Twig\Environment;
012⫶
013⫶class MyRenderer implements NotificationRenderer, TypedNotificationRendererInterface
014⫶{
015⫶ public function __construct(
016⫶ protected Environment $twig,
017⫶ protected RouterInterface $router
018⫶ ) {
019⫶ }
020⫶
021⫶ public function render(Notification $notification): string
022⫶ {
023⫶ return $this->twig->render('@ibexadesign/notification.html.twig', [
024⫶ 'notification' => $notification,
025⫶ 'template_to_extend' => $templateToExtend,
026⫶ ]);
027⫶ }
028⫶
029⫶ public function generateUrl(Notification $notification): ?string
030⫶ {
031⫶ if (array_key_exists('content_id', $notification->data)) {
032⫶ return $this->router->generate('ibexa.content.view', ['contentId' => $notification->data['content_id']]);
033⫶ }
034⫶
035⫶ return null;
036⫶ }
037⫶


code_samples/back_office/notifications/src/Notification/MyRenderer.php

docs/administration/back_office/notifications.md@72:```php
docs/administration/back_office/notifications.md@73:[[= include_file('code_samples/back_office/notifications/src/Notification/MyRenderer.php') =]]
docs/administration/back_office/notifications.md@74:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Notification;
006⫶
007⫶use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
008⫶use Ibexa\Core\Notification\Renderer\NotificationRenderer;
009⫶use Ibexa\Core\Notification\Renderer\TypedNotificationRendererInterface;
010⫶use Symfony\Component\Routing\RouterInterface;
011⫶use Twig\Environment;
012⫶
013⫶class MyRenderer implements NotificationRenderer, TypedNotificationRendererInterface
014⫶{
015⫶ public function __construct(
016⫶ protected Environment $twig,
017⫶ protected RouterInterface $router
018⫶ ) {
019⫶ }
020⫶
021⫶ public function render(Notification $notification): string
022⫶ {
023⫶ return $this->twig->render('@ibexadesign/notification.html.twig', [
024⫶ 'notification' => $notification,
025⫶ 'template_to_extend' => $templateToExtend,
026⫶ ]);
027⫶ }
028⫶
029⫶ public function generateUrl(Notification $notification): ?string
030⫶ {
031⫶ if (array_key_exists('content_id', $notification->data)) {
032⫶ return $this->router->generate('ibexa.content.view', ['contentId' => $notification->data['content_id']]);
033⫶ }
034⫶
035⫶ return null;
036⫶ }
037⫶
038⫶    }
039⫶
040⫶ public function getTypeLabel(): string
041⫶ {
042⫶ return /** @Desc("Workflow stage changed") */
043⫶ $this->translator->trans(
044⫶ 'workflow.notification.stage_change.label',
045⫶ [],
046⫶ 'ibexa_workflow'
047⫶ );
048⫶ }
049⫶}
038⫶    public function getTypeLabel(): string
039⫶ {
040⫶ return /** @Desc("Workflow stage changed") */
041⫶ $this->translator->trans(
042⫶ 'workflow.notification.stage_change.label',
043⫶ [],
044⫶ 'ibexa_workflow'
045⫶ );
046⫶ }
047⫶}


Download colorized diff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants