PHPackages                             whitedigital-eu/entity-resource-mapper-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. whitedigital-eu/entity-resource-mapper-bundle

ActiveSymfony-bundle[API Development](/categories/api)

whitedigital-eu/entity-resource-mapper-bundle
=============================================

Bundle to map Doctrine entity object to and from API resource object.

0.24.13(1y ago)11.2k↓100%2[8 issues](https://github.com/whitedigital-eu/entity-resource-mapper/issues)5MITPHPPHP &gt;=8.1

Since May 2Pushed 9mo ago1 watchersCompare

[ Source](https://github.com/whitedigital-eu/entity-resource-mapper)[ Packagist](https://packagist.org/packages/whitedigital-eu/entity-resource-mapper-bundle)[ RSS](/packages/whitedigital-eu-entity-resource-mapper-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (30)Versions (112)Used By (5)

Entity Resource Mapper Bundle
=============================

[](#entity-resource-mapper-bundle)

1. Extends Symfony / Api Platform functionality by helping to map Doctrine entity objects with Api Platform resource objects and offers other helpers such as filters, JSON Functions, etc.
2. Implements AuthorizationService which centralizes all authorization configuration and provides methods for authorizing resources in:

- Data provider - collection get
- Data provider - item get
- Data persister - item post/put/patch
- Data persister - item delete
- Individual resource in EntityToResourceMapper

Requirements
------------

[](#requirements)

PHP 8.1+
Symfony 6.3+

Installation
------------

[](#installation)

The recommended way to install is via Composer:

```
composer require whitedigital-eu/entity-resource-mapper-bundle
```

Configuration
-------------

[](#configuration)

### ClassMapper service

[](#classmapper-service)

You should create ClassMapper service configuration file, for example:

```
namespace App\Service;

use App\Dto\CustumerDto;
use App\Entity\Customer;

use WhiteDigital\EntityResourceMapper\Mapper\ClassMapperConfiguratorInterface;
use WhiteDigital\EntityResourceMapper\Mapper\ClassMapper;

class ClassMapperConfigurator implements ClassMapperConfiguratorInterface
{
    public function __invoke(ClassMapper $classMapper)
    {
        $classMapper->registerMapping(CustomerResource::class, Customer::class);
        // with Callback - must return true for mapping to be active
        $classMapper->registerMapping(PublicHtmlResource::class, Html::class, callback: static fn (array $context) => !self::isAdmin($context));
        $classMapper->registerMapping(AdminHtmlResource::class, Html::class, callback: static fn (array $context) => self::isAdmin($context));
    }

    /**
     * IsAdmin or else IsPublic.
     */
    private static function isAdmin(array $context): bool
    {
        return array_key_exists('request_uri', $context) && str_starts_with($context['request_uri'], '/api/admin');
    }
}
```

and register it as configurator for ClassMapper service in your services.yaml file:

```
    WhiteDigital\EntityResourceMapper\Mapper\ClassMapperConfiguratorInterface:
      class: App\Service\ClassMapperConfigurator
```

Additionally, you can use Mapping attribute to register mapping:

```
use App\Dto\CustumerDto;
use Doctrine\ORM\Mapping as ORM;
use WhiteDigital\EntityResourceMapper\Attribute\Mapping;

#[ORM\Entity]
#[Mapping(CustumerDto::class)]
class Customer ...
```

```
use WhiteDigital\EntityResourceMapper\Attribute\Mapping;
use App\Entity\Customer;

#[Mapping(Customer::class)]
class CustumerDto ...
```

### Filters

[](#filters)

Following filters are currently available (filters works as described in Api Platform docs, except for comments below):

- ResourceBooleanFilter
- ResourceDateFilter *(throws exception, if value is not a valid DateTime object)*
- ResourceEnumFilter *(same as SearchFilter but with explicit documentation)*
- ResourceExistsFilter
- ResourceJsonFilter *(new filter)*
- ResourceNumericFilter
- ResourceOrderFilter *(allows ordering by json values)*
- ResourceOrderCustomFilter *(Order filter which will order by custom SELECT fields, which are not included in root alias nor joins)*
- ResourceRangeFilter
- ResourceSearchFilter

### JSON Functions

[](#json-functions)

Following PostgreSQL functions are available in Doctrine and used in ResourceJsonFilter and ResourceOrderFilter:

- JSONB\_PATH\_EXISTS(%s, %s) - PostgreSQL function jsonb\_path\_exists(%s::jsonb, %s)
- JSON\_GET\_TEXT(%s, %s) - PostgreSQL alias for %s-&gt;&gt;%s
- JSON\_ARRAY\_LENGTH(%s) - PostgreSQL function json\_array\_length(%s)
- JSON\_CONTAINS(%s, %s) - PostgreSQL alias for %s::jsonb @&gt; '%s'

### DBAL Types

[](#dbal-types)

This bundle comes with and autoconfigures following dbal types to use UTC time zone:

- date
- datetime
- date\_immutable
- datetime\_immutable

### Security

[](#security)

Available operation types:

- `AuthorizationService::ALL` Includes all of the below
- `AuthorizationService::COL_GET` Collection GET
- `AuthorizationService::ITEM_GET` Item GET
- `AuthorizationService::COL_POST` Collection POST
- `AuthorizationService::ITEM_PATCH` Item PUT + PATCH
- `AuthorizationService::ITEM_DELETE` Item DELETE

Available grant types:

- `GrantType::ALL` resource fully available
- `GrantType::LIMITED` resource is available with limitations
- `GrantType::NONE` resource not available

AuthorizationService Configurator must be implemented.

```
// src/Service/Configurator/AuthorizationServiceConfigurator.php

use WhiteDigital\EntityResourceMapper\Resource\BaseResource;
use WhiteDigital\EntityResourceMapper\Security\AuthorizationServiceConfiguratorInterface;

final class AuthorizationServiceConfigurator implements AuthorizationServiceConfiguratorInterface
{
    public function __invoke(AuthorizationService $service): void
    {
        $service->setAuthorizationOverride(static fn (BaseEntity|BaseResource|null $object = null) => 'cli' === strtolower(PHP_SAPI) && 'test' !== $_ENV['APP_ENV']);

        $service->setResources([
            ActivityResource::class => [
                AuthorizationService::ALL => ['ROLE_SUPER_ADMIN' => GrantType::ALL, 'ROLE_KAM' => GrantType::ALL],
                AuthorizationService::COL_GET => [, 'ROLE_JUNIOR_KAM' => GrantType::OWN],
                AuthorizationService::ITEM_GET => [, 'ROLE_JUNIOR_KAM' => GrantType::GROUP],
                AuthorizationService::COL_POST => [],
                AuthorizationService::ITEM_PATCH => [],
                AuthorizationService::ITEM_DELETE => [],
            ]]);

        //either mainResource or roles key must be set
        $service->setMenuStructure(
                [
                    ['name' => 'ACTIVITIES',
                        'mainResource' => ActivityResource::class,
                    ],
                    ['name' => 'REPORTS',
                        'roles' => ['ROLE_SUPER_ADMIN', 'ROLE_KAM'],
                    ],
                 ]);
    }
}
```

register it as service:

```
WhiteDigital\EntityResourceMapper\Security\AuthorizationServiceConfiguratorInterface:
    class: AuthorizationServiceConfigurator

```

If `setAuthorizationOverride` closure is set, it will be called with current object (resource or entity) and if it returns true, authorization will be skipped.

Use following methods:

- In DataProvider, getCollection:

```
$this->authorizationService->limitGetCollection($resourceClass, $queryBuilder); // This will affect queryBuilder object
```

- In DataProvider, getItem:

```
$this->authorizationService->authorizeSingleObject($entity, AuthorizationService::ITEM_GET); // This will throw AccessDeniedException if not authorized
```

- In DataPersister, persist:

```
$this->authorizationService->authorizeSingleObject($data, AuthorizationService::ITEM_PATCH); // This will throw AccessDeniedException if not authorized
// or
$this->authorizationService->authorizeSingleObject($data, AuthorizationService::COL_POST; // This will throw AccessDeniedException if not authorized
```

- In DataPersister, remove:

```
$this->authorizationService->authorizeSingleObject($data, AuthorizationService::ITEM_DELETE); // This will throw AccessDeniedException if not authorized
```

- In any Resource, if you have defined its grant as LIMITED, you must add attribute to BaseResource class, to define access resolver configurations for each of the resource classes

```
#[AuthorizeResource(accessResolvers: [
    new AccessResolverConfiguration(className: OwnerPropertyAccessResolver::class, config: ['ownerPropertyPath' => 'supervisor']),
])]
```

Same class must also set following property with correct normalization group:

```
    #[Groups('deal_read')]
    #[ApiProperty(attributes: ["openapi_context" => ["description" => "If Authorization GrantType::OWN or GROUP is calculated, resource can be restricted."]])]
    public bool $isRestricted = false;
```

### Property visibility check

[](#property-visibility-check)

Sometimes you want to return all items in endpoint but want to limit properties returned based on user roles. To do so, you need to set `GrantType::LIMITED` to role and operation you want to have this visibility check and add `#[VisibleProperty]` attribute to resource where this check should be done. `#[VisibleProperty]` attribute takes 2 parameters: `ownerProperty` and `properties`. `properties` is an array of all properties you want to `SHOW`. `ownerProperty` is the name of property which to check against current logged in user.

> **IMPORTANT**: If resource has GrantType::LIMITED to some role for get or get\_collection operations, at least one access resolver or `#[VisibleProperty]` must be set!

### Explicit check if all roles are configured in authorization service

[](#explicit-check-if-all-roles-are-configured-in-authorization-service)

If you want explicitly check if all project defined roles are fully configured in authorization service, you can configure this check by passing BackedEnum containing all needed roles to configuration.

> Default value is `[]`, so without this configuration check will not be triggered.

```
