Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php declare(strict_types=1);

namespace App\Controller;

use App\Security\Limitation\CustomLimitationValue;
use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Contracts\AdminUi\Permission\PermissionCheckerInterface;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\User\Controller\AuthenticatedRememberedCheckTrait;
use Ibexa\Contracts\User\Controller\RestrictedControllerInterface;
use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class CustomController extends Controller implements RestrictedControllerInterface
{
use AuthenticatedRememberedCheckTrait {
AuthenticatedRememberedCheckTrait::performAccessCheck as public traitPerformAccessCheck;
}

public function __construct(
// ...,
private readonly PermissionResolver $permissionResolver,
private readonly PermissionCheckerInterface $permissionChecker
) {
}

// Controller actions...
public function customAction(Request $request): Response
{
// ...
if ($this->getCustomLimitationValue()) {
// Action only for user having the custom limitation checked
}

return new Response('<html><body>...</body></html>');
}

private function getCustomLimitationValue(): bool
{
$hasAccess = $this->permissionResolver->hasAccess('custom_module', 'custom_function_2');

if (is_bool($hasAccess)) {
return $hasAccess;
}

$customLimitationValues = $this->permissionChecker->getRestrictions($hasAccess, CustomLimitationValue::class);

return $customLimitationValues['value'] ?? false;
}

public function performAccessCheck(): void
{
$this->traitPerformAccessCheck();
$this->denyAccessUnlessGranted(new Attribute('custom_module', 'custom_function_2'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

class CustomLimitationValueMapper implements LimitationValueMapperInterface
{
public function mapLimitationValue(Limitation $limitation): bool
/** return array<bool> */
public function mapLimitationValue(Limitation $limitation): array
{
return $limitation->limitationValues['value'];
return [$limitation->limitationValues['value']];
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{# templates/themes/standard/limitation/custom_limitation_value.html.twig #}
{% block ez_limitation_customlimitation_value %}
<span style="color: {{ values ? 'green' : 'red' }};">{{ values ? 'Yes' : 'No' }}</span>
{% block ibexa_limitation_customlimitation_value %}
{% set isSet = values | first %}
<span style="color: {{ isSet ? 'green' : 'red' }};">{{ isSet ? 'Yes' : 'No' }}</span>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ public function generateUrl(Notification $notification): ?string
return null;
}

}

public function getTypeLabel(): string
{
return /** @Desc("Workflow stage changed") */
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
"ibexa/discounts": "~5.0.x-dev",
"ibexa/discounts-codes": "~5.0.x-dev",
"ibexa/core-search": "~5.0.x-dev",
"ibexa/product-catalog-symbol-attribute": "~5.0.x-dev"
"ibexa/product-catalog-symbol-attribute": "~5.0.x-dev",
"ibexa/messenger": "~5.0.x-dev"
},
"scripts": {
"fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots",
Expand Down
63 changes: 7 additions & 56 deletions docs/permissions/custom_policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ services:

#### Form mapper

To provide support for editing custom policies in the back office, you need to implement [`Ibexa\AdminUi\Limitation\LimitationFormMapperInterface`](https://github.com/ibexa/admin-ui/blob/4.5/src/lib/Limitation/LimitationFormMapperInterface.php).
To provide support for editing custom policies in the back office, you need to implement [`Ibexa\AdminUi\Limitation\LimitationFormMapperInterface`](https://github.com/ibexa/admin-ui/blob/5.0/src/lib/Limitation/LimitationFormMapperInterface.php).

- `mapLimitationForm` adds the limitation field as a child to a provided Symfony form.
- `getFormTemplate` returns the path to the template to use for rendering the limitation form. Here it use [`form_label`]([[= symfony_doc =]]/form/form_customization.html#reference-forms-twig-label) and [`form_widget`]([[= symfony_doc =]]/form/form_customization.html#reference-forms-twig-widget) to do so.
Expand Down Expand Up @@ -205,7 +205,7 @@ Some abstract limitation type form mapper classes are provided to help implement

#### Value mapper

By default, without a value mapper, the limitation value is rendered by using the block `ez_limitation_value_fallback` of the template [`vendor/ibexa/admin-ui/src/bundle/Resources/views/themes/admin/limitation/limitation_values.html.twig`](https://github.com/ibexa/admin-ui/blob/4.5/src/bundle/Resources/views/themes/admin/limitation/limitation_values.html.twig#L1-L6).
By default, without a value mapper, the limitation value is rendered by using the block `ibexa_limitation_value_fallback` of the template [`vendor/ibexa/admin-ui/src/bundle/Resources/views/themes/admin/limitation/limitation_values.html.twig`](https://github.com/ibexa/admin-ui/blob/v[[= latest_tag_5_0 =]]/src/bundle/Resources/views/themes/admin/limitation/limitation_values.html.twig).

To customize the rendering, a value mapper eventually transforms the limitation value and sends it to a custom template.

Expand All @@ -223,17 +223,17 @@ Then register the service with the `ibexa.admin_ui.limitation.mapper.value` tag
[[= include_file('code_samples/back_office/limitation/config/append_to_services.yaml', 9, 12) =]]
```

When a value mapper exists for a limitation, the rendering uses a Twig block named `ez_limitation_<lower_case_identifier>_value` where `<lower_case_identifier>` is the limitation identifier in lower case.
In this example, block name is `ez_limitation_customlimitation_value` as the identifier is `CustomLimitation`.
When a value mapper exists for a limitation, the rendering uses a Twig block named `ibexa_limitation_<lower_case_identifier>_value` where `<lower_case_identifier>` is the limitation identifier in lower case.
In this example, block name is `ibexa_limitation_customlimitation_value` as the identifier is `CustomLimitation`.

This template receives a `values` variable which is the return of the `mapLimitationValue` function from the corresponding value mapper.
This template receives a `values` variable which is the return value of the `mapLimitationValue` function from the corresponding value mapper.

``` html+twig
[[= include_file('code_samples/back_office/limitation/templates/themes/standard/limitation/custom_limitation_value.html.twig') =]]
```

To have your block found, you have to register its template.
Add the template to the configuration under `ezplatform.system.<SCOPE>.limitation_value_templates`:
Add the template to the configuration under `ibexa.system.<SCOPE>.limitation_value_templates`:

``` yaml
[[= include_file('code_samples/back_office/limitation/config/packages/ibexa_security.yaml') =]]
Expand All @@ -251,54 +251,5 @@ For example, `translations/ibexa_content_forms_policies.en.yaml`:
Check if current user has this custom limitation set to true from a custom controller:

```php
<?php declare(strict_types=1);

namespace App\Controller;

use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Contracts\AdminUi\Permission\PermissionCheckerInterface;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class CustomController extends Controller
{
// ...
/** @var PermissionResolver */
private $permissionResolver;

/** @var PermissionCheckerInterface */
private $permissionChecker;

public function __construct(
// ...,
PermissionResolver $permissionResolver,
PermissionCheckerInterface $permissionChecker
)
{
// ...
$this->permissionResolver = $permissionResolver;
$this->permissionChecker = $permissionChecker;
}

// Controller actions...
public function customAction(Request $request): Response {
// ...
if ($this->getCustomLimitationValue()) {
// Action only for user having the custom limitation checked
}
}

private function getCustomLimitationValue(): bool {
$customLimitationValues = $this->permissionChecker->getRestrictions($this->permissionResolver->hasAccess('custom_module', 'custom_function_2'), CustomLimitationValue::class);

return $customLimitationValues['value'] ?? false;
}

public function performAccessCheck()
{
parent::performAccessCheck();
$this->denyAccessUnlessGranted(new Attribute('custom_module', 'custom_function_2'));
}
}
[[= include_file('code_samples/back_office/limitation/src/Controller/CustomController.php') =]]
```
66 changes: 54 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -240,18 +240,6 @@ parameters:
count: 1
path: code_samples/back_office/images/src/PlaceholderProvider.php

-
message: '#^Method App\\Security\\Limitation\\Mapper\\CustomLimitationFormMapper\:\:mapLimitationForm\(\) has parameter \$form with generic interface Symfony\\Component\\Form\\FormInterface but does not specify its types\: TData$#'
identifier: missingType.generics
count: 1
path: code_samples/back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationFormMapper.php

-
message: '#^Return type \(bool\) of method App\\Security\\Limitation\\Mapper\\CustomLimitationValueMapper\:\:mapLimitationValue\(\) should be compatible with return type \(array\<mixed\>\) of method Ibexa\\AdminUi\\Limitation\\LimitationValueMapperInterface\:\:mapLimitationValue\(\)$#'
identifier: method.childReturnType
count: 1
path: code_samples/back_office/limitation/src/Security/Limitation/Mapper/CustomLimitationValueMapper.php

-
message: '#^Method App\\Security\\MyPolicyProvider\:\:getFiles\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
Expand All @@ -270,6 +258,24 @@ parameters:
count: 1
path: code_samples/back_office/menu/menu_item/src/EventSubscriber/MyMenuSubscriber.php

-
message: '#^Access to an undefined property App\\Notification\\ListRenderer\:\:\$translator\.$#'
identifier: property.notFound
count: 1
path: code_samples/back_office/notifications/src/Notification/ListRenderer.php

-
message: '#^Access to an undefined property App\\Notification\\MyRenderer\:\:\$translator\.$#'
identifier: property.notFound
count: 1
path: code_samples/back_office/notifications/src/Notification/MyRenderer.php

-
message: '#^Undefined variable\: \$templateToExtend$#'
identifier: variable.undefined
count: 1
path: code_samples/back_office/notifications/src/Notification/MyRenderer.php

-
message: '#^Cannot call method getValue\(\) on Ibexa\\Contracts\\FieldTypePage\\FieldType\\LandingPage\\Model\\Attribute\|null\.$#'
identifier: method.nonObject
Expand Down Expand Up @@ -540,6 +546,42 @@ parameters:
count: 1
path: code_samples/front/shop/storefront/src/EventSubscriber/BreadcrumbsMenuSubscriber.php

-
message: '#^Call to method addCriterion\(\) on an unknown class Ibexa\\Contracts\\Core\\Repository\\Values\\NotificationQuery\.$#'
identifier: class.notFound
count: 3
path: code_samples/notifications/Src/Query/search.php

-
message: '#^Instantiated class DateCreated not found\.$#'
identifier: class.notFound
count: 1
path: code_samples/notifications/Src/Query/search.php

-
message: '#^Instantiated class Ibexa\\Contracts\\Core\\Repository\\Values\\NotificationQuery not found\.$#'
identifier: class.notFound
count: 1
path: code_samples/notifications/Src/Query/search.php

-
message: '#^Instantiated class Status not found\.$#'
identifier: class.notFound
count: 1
path: code_samples/notifications/Src/Query/search.php

-
message: '#^Instantiated class Type not found\.$#'
identifier: class.notFound
count: 1
path: code_samples/notifications/Src/Query/search.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 1
path: code_samples/notifications/Src/Query/search.php

-
message: '#^Method App\\Block\\Attribute\\MyStringAttributeMapper\:\:map\(\) has parameter \$constraints with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
Expand Down
Loading