Skip to content

Commit

Permalink
Merge pull request #31 from Ehyiah/matt/allow-service-override
Browse files Browse the repository at this point in the history
refacto bundle, add override default service by implementation of int…
  • Loading branch information
Ehyiah authored Jun 10, 2024
2 parents 355e023 + 587c769 commit f9591f6
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 70 deletions.
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ As the mapping logic is using the propertyAccess component, you can specify nest

## <u>Simple Usage</u>

1 - Create a DTO that will 'hold' the mapping logic
```php
// src/DTO/MyAwesomeDTO

Expand All @@ -90,12 +91,46 @@ As the mapping logic is using the propertyAccess component, you can specify nest
}
```

If you call ```mapToTarget()``` function of the service in a controller, handler or wherever you need it, the service will take properties tagged with MappingAware attribute
2 - Inject the ```MappingServiceInterface``` into your code, and call the methods.

```php
use App\src\Entity\MyAwesomeEntity;
use App\src\DTO\MyAwesomeDTO;
use Ehyiah\MappingBundle\Attributes;
use Ehyiah\MappingBundle\MappingServiceInterface;

class SomeUsefulServiceOrHandlerOrController
{
public function __construct(
private MappingServiceInterface $mappingService,
) {
}

public function handle()
{
$entity = new MyAwesomeEntity();
$dto = new MyAwesomeDTO();

$this->mappingService->mapToTarget($dto, $entity);
$this->mappingService->mapFromTarget($entity, $dto);
}
}
```
If you call ```mapToTarget()``` function of the service tagged with ```MappingServiceInterface``` in a controller, handler or wherever you need it, the service will take properties tagged with MappingAware attribute
and will put the values stored in the DTO into the properties in the entity and flush them (default value).


# <u>Advanced usage</u>

## <u>Replace the Built-in service</u>
A Default service implementing ```MappingServiceInterface``` exist in the bundle. But you may need to create a service that implements the ```MappingServiceInterface``` to replace the default built-in.

### Create your own service
To create your own service :
- Just create a service that implements the ```MappingServiceInterface```, there is nothing more to do, no need to register or override the default built-in. The compiler pass do the work for you.
- In this service you will handle the logic yourself.
- Of course you can take the basis methods of the default service and modify them to your needs inside your custom service.

## <u>Transformers</u>

Sometimes you need to modify data between the objects.
Expand Down
36 changes: 0 additions & 36 deletions config/services.xml

This file was deleted.

12 changes: 12 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

Ehyiah\MappingBundle\:
resource: '../src/'
exclude:
- '../src/Attributes/'
- '../src/DependencyInjection/'
- '../src/Exception/'
- '../src/Kernel.php'
30 changes: 30 additions & 0 deletions src/DependencyInjection/Compiler/MappingServicePass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Ehyiah\MappingBundle\DependencyInjection\Compiler;

use Ehyiah\MappingBundle\MappingService;
use Ehyiah\MappingBundle\MappingServiceInterface;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

class MappingServicePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$taggedServices = $container->findTaggedServiceIds('ehyiah.mapping_bundle.mapping_service');

if (count($taggedServices) > 1 && array_key_exists(MappingService::class, $taggedServices)) {
unset($taggedServices[MappingService::class]);
}

if (1 === count($taggedServices)) {
$definition = new Definition(MappingServiceInterface::class);
$container->setDefinition(MappingServiceInterface::class, $definition);
$container->setAlias(MappingServiceInterface::class, array_key_first($taggedServices));
} else {
throw new LogicException('Please create a single MappingService service. You got ' . count($taggedServices) . ' services.');
}
}
}
30 changes: 0 additions & 30 deletions src/DependencyInjection/MappingExtension.php

This file was deleted.

31 changes: 29 additions & 2 deletions src/MappingBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,42 @@

namespace Ehyiah\MappingBundle;

use Ehyiah\MappingBundle\DependencyInjection\Compiler\MappingServicePass;
use Ehyiah\MappingBundle\DependencyInjection\Compiler\TransformerPass;
use Exception;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

// More details on https://symfony.com/doc/current/bundles/configuration.html#using-the-abstractbundle-class
class MappingBundle extends Bundle
class MappingBundle extends AbstractBundle
{
public function build(ContainerBuilder $container): void
{
$container->addCompilerPass(new TransformerPass());
$container->addCompilerPass(new MappingServicePass());
}

/**
* @throws Exception
*/
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
{
parent::prependExtension($container, $builder);

$loader = new YamlFileLoader($builder, new FileLocator(__DIR__ . '/../config/packages'));
$loader->load('monolog.yaml');
}

/**
* @param array<string,array<string,mixed>> $config
*/
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{
parent::loadExtension($config, $container, $builder);

$container->import('../config/services.yaml');
}
}
2 changes: 1 addition & 1 deletion src/MappingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use ReflectionException;
use Symfony\Component\PropertyAccess\PropertyAccessor;

final class MappingService
final class MappingService implements MappingServiceInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
Expand Down
13 changes: 13 additions & 0 deletions src/MappingServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Ehyiah\MappingBundle;

use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag('ehyiah.mapping_bundle.mapping_service')]
interface MappingServiceInterface
{
public function mapToTarget(object $mappingAwareSourceObject, ?object $targetObject = null, bool $persist = false, bool $flush = false): object;

public function mapFromTarget(object $sourceObject, object $mappingAwareTargetObject): object;
}

0 comments on commit f9591f6

Please sign in to comment.