Skip to content

Commit

Permalink
Merge pull request #7 from yceruto/doctrine
Browse files Browse the repository at this point in the history
add doctrine mapping
  • Loading branch information
yceruto committed Jan 9, 2023
2 parents f46dd1f + 2605b4b commit 410b02f
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 2 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,27 @@ You can disable this integration by modifying the configuration:
twig:
enabled: false

## Doctrine Integration

Doctrine allows you to map an embedded object to a database column using the `Embedded` attribute and this bundle provides
the `Money\Money` ORM mapping definitions for use with the Doctrine bundle, if it is enabled. This means that you can use
Doctrine's entity manager to persist and retrieve your entities with the embedded money values, without having to manually
configure the ORM mappings. This can simplify your development process and allow you to focus on other aspects of your application:

use Doctrine\ORM\Mapping\Embedded;
use Money\Money;

class Product
{
#[Embedded]
private Money $price;
}

You can also use the fields of embedded classes that have been mapped using Doctrine in DQL (Doctrine Query Language)
queries, just as if they were declared in the Product class itself:

SELECT p FROM Product p WHERE p.price.amount > 1000 AND p.price.currency.code = 'EUR'

## Data Transfer Object

By design, the `Money\Money` value object is immutable, which means that it is not possible to change the original amount and currency
Expand Down
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"require-dev": {
"ext-gmp": "*",
"ext-intl": "*",
"doctrine/doctrine-bundle": "^2.8",
"doctrine/orm": "^2.14",
"phpunit/phpunit": "^9.5",
"psalm/plugin-phpunit": "^0.18.4",
"psalm/plugin-symfony": "^5.0",
Expand Down
10 changes: 10 additions & 0 deletions config/doctrine/mapping/Currency.orm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<embeddable name="Money\Currency">
<field name="code" column="currency" length="3" />
</embeddable>
</doctrine-mapping>
11 changes: 11 additions & 0 deletions config/doctrine/mapping/Money.orm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<embeddable name="Money\Money">
<field name="amount" />
<embedded name="currency" class="Money\Currency" use-column-prefix="false" />
</embeddable>
</doctrine-mapping>
21 changes: 20 additions & 1 deletion src/DependencyInjection/MoneyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,34 @@
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\Form\Forms;
use Twig\Environment;
use Yceruto\MoneyBundle\DependencyInjection\Compiler\CurrenciesPass;
use Yceruto\MoneyBundle\DependencyInjection\Compiler\FormattersPass;
use Yceruto\MoneyBundle\Formatter\IntlNumberFormatterFactory;

class MoneyExtension extends Extension
class MoneyExtension extends Extension implements PrependExtensionInterface
{
public function prepend(ContainerBuilder $container): void
{
if ($container->hasExtension('doctrine')) {
$container->prependExtensionConfig('doctrine', [
'orm' => [
'mappings' => [
'Money' => [
'is_bundle' => false,
'type' => 'xml',
'dir' => \dirname(__DIR__, 2).'/config/doctrine/mapping/',
'prefix' => 'Money',
],
],
],
]);
}
}

public function load(array $configs, ContainerBuilder $container): void
{
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
Expand Down
38 changes: 37 additions & 1 deletion tests/DependencyInjection/MoneyExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

namespace Yceruto\MoneyBundle\Tests\DependencyInjection;

use Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Money\Converter;
use Money\Currency;
use Money\Currencies\AggregateCurrencies;
Expand Down Expand Up @@ -126,13 +130,45 @@ public function testExchangesServices(): void
self::assertEquals(Money::EUR('200'), $converted);
}

public function testMoneyDoctrineMapping(): void
{
$container = $this->createContainer([], [[]], static function (ContainerBuilder $container) {
$container->registerExtension(new DoctrineExtension());
$container->loadFromExtension('doctrine', [
'dbal' => [],
]);

(new MoneyExtension())->prepend($container);
});

/** @var Registry $doctrine */
$doctrine = $container->get('doctrine');
/** @var EntityManager $manager */
$manager = $doctrine->getManager();
/** @var ClassMetadata $metadata */
$metadata = $manager->getClassMetadata(Money::class);

self::assertTrue($metadata->isEmbeddedClass);
self::assertSame(Money::class, $metadata->getName());
self::assertSame(['amount', 'currency.code'], $metadata->getFieldNames());
self::assertSame('string', $metadata->getTypeOfField('amount'));
self::assertSame('string', $metadata->getTypeOfField('currency.code'));
self::assertCount(1, $metadata->embeddedClasses);
self::assertSame(Currency::class, $metadata->embeddedClasses['currency']['class']);
}

/**
* @param array<class-string|string> $publicServices
* @param array<array-key, array<array-key, mixed>> $configs
*/
private function createContainer(array $publicServices = [], array $configs = [[]], \Closure $callback = null): ContainerInterface
{
$container = (new ContainerBuilder(new ParameterBag()))
$parameters = [
'kernel.debug' => true,
'kernel.bundles' => [],
'kernel.cache_dir' => sys_get_temp_dir(),
];
$container = (new ContainerBuilder(new ParameterBag($parameters)))
->addCompilerPass(new CurrenciesPass())
->addCompilerPass(new FormattersPass())
->addCompilerPass(new ParsersPass())
Expand Down

0 comments on commit 410b02f

Please sign in to comment.