Skip to content

Commit

Permalink
Add document storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mustanggb committed Feb 15, 2024
1 parent b9dd869 commit 135f56f
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 12 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,8 @@ $ratioList = $pairHistoryManager->getRatioHistory('USD', $startDate, $endDate);
RatioStorage
------------

Two storages for storing ratios are available : CSV File, or Doctrine
Three storages for storing ratios are available : CSV File (csv), Doctrine ORM (doctrine), or MongoDB (document)

By default, TbbcMoneyBundle is configured with CSV File.

If you want to switch to a Doctrine storage, edit your **config.yml**
Expand Down Expand Up @@ -595,18 +596,18 @@ You can :
* subclass the MoneyFormatter and rewrite the getDefaultNumberFormatter method to set a application wide
NumberFormatter

Using the TbbcMoneyBundle without Doctrine
------------------------------------------
Using the TbbcMoneyBundle without Doctrine ORM or MongoDB
---------------------------------------------------------

You have to disable the pair history service in order to use the TbbcMoneyBundle without Doctrine.
You have to disable the pair history service in order to use the TbbcMoneyBundle without Doctrine ORM or MongoDB.

```
tbbc_money:
enable_pair_history: true
```

Note : you can imagine to code your own PairHistoryManager for MongoDB or Propel, it is very easy to do. Don't
hesitate to submit a PR with your code and your tests.
Note : you can imagine to code your own PairHistoryManager for Propel, it is very easy to do. Don't hesitate to
submit a PR with your code and your tests.

Optimizations
-------------
Expand Down
41 changes: 36 additions & 5 deletions src/DependencyInjection/Compiler/PairHistoryCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Tbbc\MoneyBundle\DependencyInjection\Compiler;

use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
Expand All @@ -19,13 +20,19 @@ public function process(ContainerBuilder $container): void
{
$bundles = $container->getParameter('kernel.bundles');
$enabled = $container->getParameter('tbbc_money.enable_pair_history');
$storage = $container->getParameter('tbbc_money.pair.storage');

//Determine if DoctrineBundle is defined
if (true === $enabled) {
if (!isset($bundles['DoctrineBundle'])) {
throw new \RuntimeException('TbbcMoneyBundle - DoctrineBundle is needed to use the pair history function');
}
if (true !== $enabled) {
return;
}

//Determine if DoctrineBundle or DoctrineMongoDBBundle is defined
if (!isset($bundles['DoctrineBundle']) || !isset($bundles['DoctrineMongoDBBundle'])) {
throw new \RuntimeException('TbbcMoneyBundle - DoctrineBundle or DoctrineMongoDBBundle is needed to use the pair history function');
}

//Use DoctrineBundle
if ('doctrine' === $storage) {
$pairHistoryDefinition = new Definition(\Tbbc\MoneyBundle\PairHistory\PairHistoryManager::class, [
new Reference('doctrine.orm.entity_manager'),
$container->getParameter('tbbc_money.reference_currency'),
Expand All @@ -46,5 +53,29 @@ public function process(ContainerBuilder $container): void
]);
$path->process($container);
}

//Use DoctrineMongoDBBundle
if ('document' === $storage) {
$pairHistoryDefinition = new Definition(\Tbbc\MoneyBundle\PairHistory\DocumentPairHistoryManager::class, [
new Reference('doctrine_mongodb.odm.document_manager'),
$container->getParameter('tbbc_money.reference_currency'),
]);
$pairHistoryDefinition->setPublic(true);

$pairHistoryDefinition->addTag('kernel.event_listener', [
'event' => 'tbbc_money.after_ratio_save',
'method' => 'listenSaveRatioEvent',
]);

$container->setDefinition('tbbc_money.pair_history_manager', $pairHistoryDefinition);

//Add document schema mappings
$modelDir = (string) realpath(__DIR__.'/../../Resources/config/document/ratios');
$path = DoctrineMongoDBMappingsPass::createXmlMappingDriver([
$modelDir => 'Tbbc\MoneyBundle\Document',
], [
]);
$path->process($container);
}
}
}
24 changes: 24 additions & 0 deletions src/DependencyInjection/Compiler/StorageCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Tbbc\MoneyBundle\DependencyInjection\Compiler;

use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;
use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
Expand Down Expand Up @@ -41,5 +42,28 @@ public function process(ContainerBuilder $container): void
$container->setDefinition('tbbc_money.pair.doctrine_storage', $storageDoctrineDefinition);
$container->getDefinition('tbbc_money.pair_manager')->replaceArgument(0, new Reference('tbbc_money.pair.doctrine_storage'));
}

//Determine if DoctrineMongoDBBundle is defined
if ('document' === $storage) {
if (!isset($bundles['DoctrineMongoDBBundle'])) {
throw new \RuntimeException('TbbcMoneyBundle - DoctrineMongoDBBundle is needed to use Document as a storage');
}

//Add document schema mappings
$modelDir = (string) realpath(__DIR__.'/../../Resources/config/document/ratios');
$path = DoctrineMongoDBMappingsPass::createXmlMappingDriver([
$modelDir => 'Tbbc\MoneyBundle\Document',
], [
]);
$path->process($container);

$storageDocumentDefinition = new Definition(\Tbbc\MoneyBundle\Pair\Storage\DocumentStorage::class, [
new Reference('doctrine_mongodb.odm.document_manager'),
$container->getParameter('tbbc_money.reference_currency'),
]);

$container->setDefinition('tbbc_money.pair.document_storage', $storageDocumentDefinition);
$container->getDefinition('tbbc_money.pair_manager')->replaceArgument(0, new Reference('tbbc_money.pair.document_storage'));
}
}
}
2 changes: 1 addition & 1 deletion src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private function addCurrencySection(ArrayNodeDefinition $node): void
->cannotBeEmpty()
->defaultValue('csv')
->validate()
->ifNotInArray(['csv', 'doctrine'])
->ifNotInArray(['csv', 'doctrine', 'document'])
->thenInvalid('Invalid storage "%s"')
->end()
->end()
Expand Down
82 changes: 82 additions & 0 deletions src/Document/DocumentRatioHistory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace Tbbc\MoneyBundle\Document;

use DateTime;
use DateTimeInterface;

class DocumentRatioHistory
{
protected ?string $id = null;
protected string $referenceCurrencyCode = '';
protected string $currencyCode = '';
protected float $ratio = 0;
protected DateTimeInterface $savedAt;

public function __construct()
{
$this->savedAt = new DateTime();
}

public function setId(string $id): self
{
$this->id = $id;

return $this;
}

public function getId(): ?string
{
return $this->id;
}

public function setCurrencyCode(string $currencyCode): self
{
$this->currencyCode = $currencyCode;

return $this;
}

public function getCurrencyCode(): string
{
return $this->currencyCode;
}

public function setRatio(float $ratio): self
{
$this->ratio = $ratio;

return $this;
}

public function getRatio(): float
{
return $this->ratio;
}

public function setReferenceCurrencyCode(string $referenceCurrencyCode): self
{
$this->referenceCurrencyCode = $referenceCurrencyCode;

return $this;
}

public function getReferenceCurrencyCode(): string
{
return $this->referenceCurrencyCode;
}

public function setSavedAt(DateTimeInterface $savedAt): self
{
$this->savedAt = $savedAt;

return $this;
}

public function getSavedAt(): DateTimeInterface
{
return $this->savedAt;
}
}
45 changes: 45 additions & 0 deletions src/Document/DocumentStorageRatio.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Tbbc\MoneyBundle\Document;

class DocumentStorageRatio
{
private ?string $id = null;

public function __construct(
private ?string $currencyCode = null,
private ?float $ratio = null,
) {
}

public function getId(): ?string
{
return $this->id;
}

public function setCurrencyCode(string $currencyCode): self
{
$this->currencyCode = $currencyCode;

return $this;
}

public function getCurrencyCode(): ?string
{
return $this->currencyCode;
}

public function setRatio(float $ratio): self
{
$this->ratio = $ratio;

return $this;
}

public function getRatio(): ?float
{
return $this->ratio;
}
}
89 changes: 89 additions & 0 deletions src/Pair/Storage/DocumentStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace Tbbc\MoneyBundle\Pair\Storage;

use Doctrine\ODM\MongoDB\DocumentManager;
use Tbbc\MoneyBundle\Document\DocumentStorageRatio;
use Tbbc\MoneyBundle\Pair\StorageInterface;

/**
* Class DocumentStorage.
*
* @author Philippe Le Van.
*/
class DocumentStorage implements StorageInterface
{
protected array $ratioList = [];

public function __construct(protected DocumentManager $documentManager, protected string $referenceCurrencyCode)
{
}

public function loadRatioList(bool $force = false): array
{
if ((false === $force) && (count($this->ratioList) > 0)) {
return $this->ratioList;
}

$repository = $this->documentManager->getRepository(DocumentStorageRatio::class);
$documentStorageRatios = $repository->findAll();

if (0 === count($documentStorageRatios)) {
$this->ratioList = [$this->referenceCurrencyCode => 1.0];
$this->saveRatioList($this->ratioList);

return $this->ratioList;
}

$this->ratioList = [];

foreach ($documentStorageRatios as $documentStorageRatio) {
if (
null !== ($code = $documentStorageRatio->getCurrencyCode())
&& null !== ($ratio = $documentStorageRatio->getRatio())
) {
$this->ratioList[$code] = $ratio;
}
}

return $this->ratioList;
}

/**
* @psalm-param array<string, null|float> $ratioList
*/
public function saveRatioList(array $ratioList): void
{
/** @var DocumentStorageRatio[] $documentStorageRatios */
$documentStorageRatios = $this->documentManager->getRepository(DocumentStorageRatio::class)->findAll();

// index them in an associative array
$existingStorageRatios = [];
foreach ($documentStorageRatios as $documentStorageRatio) {
$existingStorageRatios[$documentStorageRatio->getCurrencyCode()] = $documentStorageRatio;
}

foreach ($ratioList as $currencyCode => $ratio) {
// load from existing, or create a new
$existingStorageRatio = $existingStorageRatios[$currencyCode] ?? new DocumentStorageRatio($currencyCode, $ratio);
$existingStorageRatio->setRatio($ratio);
$this->documentManager->persist($existingStorageRatio);

// remove from the array, as we do not want to remove this one
unset($existingStorageRatios[$currencyCode]);
}

// remove the remaining ones
foreach ($existingStorageRatios as $documentStorageRatio) {
$this->documentManager->remove($documentStorageRatio);
}

// flush to database
$this->documentManager->flush();
$this->documentManager->clear();

$this->ratioList = $ratioList;
}
}
Loading

0 comments on commit 135f56f

Please sign in to comment.