Skip to content

Commit

Permalink
Mapping: fix helper
Browse files Browse the repository at this point in the history
  • Loading branch information
f3l1x committed Dec 6, 2024
1 parent dd70a95 commit 817cdc4
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 45 deletions.
20 changes: 8 additions & 12 deletions .docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ nettrine.orm:
> - https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/caching.html
A Doctrine ORM can automatically cache query results and metadata. The feature is optional though, and by default, no cache is configured.
You can enable the result cache by setting the `resultCache` configuration option to an instance of a cache driver.
You can enable the result cache by setting the `defaultCache` configuration option to an instance of a cache driver or `metadataCache`, `queryCache`, `resultCache`, `hydrationCache` separately.

> [!WARNING]
> Cache adapter must implement `Psr\Cache\CacheItemPoolInterface` interface.
Expand Down Expand Up @@ -238,10 +238,7 @@ nettrine.orm:
### Mapping

There are several ways how to map entities to Doctrine ORM. This library supports:

- **attribute**
- **xml**
There are several ways how to map entities to Doctrine ORM. This library supports **attributes** and **xml** out of the box.

### Attributes

Expand Down Expand Up @@ -277,7 +274,7 @@ nettrine.orm:
connection: default
mapping:
App:
type: attribute
type: attributes
dir: %appDir%/Database
prefix: App/Database
```
Expand Down Expand Up @@ -330,19 +327,18 @@ It's a good practice if you have separated modules in your applications.

namespace App\Model\DI;

use Nette\DI\CompilerExtension;
use Nettrine\ORM\DI\Helpers\MappingHelper;
use Nette\DI\CompilerExtension;use Nettrine\ORM\DI\Helpers\MappingHelper;

class DoctrineMappingExtension extends CompilerExtension
{

public function beforeCompile(): void
{
MappingHelper::of($this)
->addAttribute('App\Model\Database', __DIR__ . '/../app/Model/Database')
->addAttribute('Forum\Modules\Database', __DIR__ . '/../../modules/Forum/Database')
->addXml('Gallery1\Modules\Database', __DIR__ . '/../../modules/Gallery1/Database')
->addXml('Gallery2\Modules\Database', __DIR__ . '/../../modules/Gallery2/Database', $simple = TRUE)
->addAttribute($connection = 'default', $namespace = 'App\Model\Database', $path = __DIR__ . '/../app/Model/Database')
->addAttribute('default', 'Forum\Modules\Database', __DIR__ . '/../../modules/Forum/Database')
->addXml('default', 'Gallery1\Modules\Database', __DIR__ . '/../../modules/Gallery1/Database')
->addXml('default', 'Gallery2\Modules\Database', __DIR__ . '/../../modules/Gallery2/Database')
}

}
Expand Down
56 changes: 29 additions & 27 deletions src/DI/Helpers/MappingHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace Nettrine\ORM\DI\Helpers;

use Doctrine\ORM\Mapping\Driver\AttributeDriver;
use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver;
use Nette\DI\CompilerExtension;
use Nette\DI\Definitions\Definition;
use Nette\DI\Definitions\ServiceDefinition;
use Nette\DI\Definitions\Statement;
use Nettrine\ORM\DI\OrmExtension;
Expand All @@ -24,56 +25,57 @@ public static function of(CompilerExtension $extension): self
return new self($extension);
}

public function addAttribute(string $namespace, string $path): self
public function addAttribute(string $connection, string $namespace, string $path): self
{
if (!is_dir($path)) {
throw new LogicalException(sprintf('Given mapping path "%s" does not exist', $path));
}

/** @var ServiceDefinition $attributeDriver */
$attributeDriver = $this->getService(OrmExtension::MANAGER_TAG, 'AttributeDriver');
$attributeDriver->addSetup('addPaths', [[$path]]);

/** @var ServiceDefinition $chainDriver */
$chainDriver = $this->getService(OrmExtension::MAPPING_DRIVER_TAG, 'MappingDriverChain');
$chainDriver->addSetup('addDriver', [$attributeDriver, $namespace]);
$chainDriver = $this->getChainDriver($connection);
$chainDriver->addSetup('addDriver', [
new Statement(AttributeDriver::class, [[$path]]),
$namespace,
]);

return $this;
}

public function addXml(string $namespace, string $path, bool $simple = false): self
public function addXml(string $connection, string $namespace, string $path): self
{
if (!is_dir($path)) {
throw new LogicalException(sprintf('Given mapping path "%s" does not exist', $path));
}

/** @var ServiceDefinition $xmlDriver */
$xmlDriver = $this->getService(OrmExtension::MANAGER_TAG, 'XmlDriver');

if ($simple) {
$xmlDriver->addSetup(new Statement('$service->getLocator()->addNamespacePrefixes([? => ?])', [$path, $namespace]));
} else {
$xmlDriver->addSetup(new Statement('$service->getLocator()->addPaths([?])', [$path]));
}

/** @var ServiceDefinition $chainDriver */
$chainDriver = $this->getService(OrmExtension::MAPPING_DRIVER_TAG, 'MappingDriverChain');
$chainDriver->addSetup('addDriver', [$xmlDriver, $namespace]);
$chainDriver = $this->getChainDriver($connection);
$chainDriver->addSetup('addDriver', [
new Statement(SimplifiedXmlDriver::class, [[$path => $namespace]]),
$namespace,
]);

return $this;
}

private function getService(string $tag, string $name): Definition
private function getChainDriver(string $connection): ServiceDefinition
{
$builder = $this->extension->getContainerBuilder();

$service = $builder->findByTag($tag);
/** @var array<string, array{name: string}> $services */
$services = $builder->findByTag(OrmExtension::MAPPING_DRIVER_TAG);

if ($services === []) {
throw new LogicalException('No mapping driver found');
}

foreach ($services as $serviceName => $tagValue) {
if ($tagValue['name'] === $connection) {
$serviceDef = $builder->getDefinition($serviceName);
assert($serviceDef instanceof ServiceDefinition);

if ($service === []) {
throw new LogicalException(sprintf('Service "%s" not found by tag "%s"', $name, $tag));
return $serviceDef;
}
}

return $builder->getDefinition(current(array_keys($service)));
throw new LogicalException(sprintf('No mapping driver found for connection "%s"', $connection));
}

}
2 changes: 1 addition & 1 deletion src/DI/Pass/ManagerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public function loadManagerConfiguration(string $managerName, mixed $managerConf
// MappingDriver
$mappingDriver = $builder->addDefinition($this->prefix(sprintf('managers.%s.mappingDriver', $managerName)))
->setFactory(MappingDriverChain::class)
->addTag(OrmExtension::MAPPING_DRIVER_TAG)
->addTag(OrmExtension::MAPPING_DRIVER_TAG, ['name' => $managerName])
->setAutowired(false);

// Mapping
Expand Down
64 changes: 59 additions & 5 deletions tests/Cases/DI/Helper/MappingHelper.phpt
Original file line number Diff line number Diff line change
@@ -1,22 +1,76 @@
<?php declare(strict_types = 1);

use Contributte\Tester\Toolkit;
use Contributte\Tester\Utils\ContainerBuilder;
use Contributte\Tester\Utils\Neonkit;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
use Nette\DI\Compiler;
use Nette\DI\CompilerExtension;
use Nettrine\DBAL\DI\DbalExtension;
use Nettrine\ORM\DI\Helpers\MappingHelper;
use Nettrine\ORM\DI\OrmExtension;
use Nettrine\ORM\Exception\LogicalException;
use Tester\Assert;
use Tests\Mocks\DummyExtension;
use Tests\Mocks\Entity\DummyEntity;
use Tests\Toolkit\Tests;

require_once __DIR__ . '/../../../bootstrap.php';

// Validate path for attribute
Toolkit::test(function (): void {
Assert::exception(function (): void {
$extension = new class extends CompilerExtension {
MappingHelper::of(new DummyExtension())->addAttribute('default', 'fake', 'invalid');
}, LogicalException::class, 'Given mapping path "invalid" does not exist');
});

// Empty class
// Attributes
Toolkit::test(function (): void {
$container = ContainerBuilder::of()
->withCompiler(function (Compiler $compiler): void {
$compiler->addExtension('nettrine.dbal', new DbalExtension());
$compiler->addExtension('nettrine.orm', new OrmExtension());
$compiler->addExtension('custom', new class extends CompilerExtension {

};
public function beforeCompile(): void
{
MappingHelper::of($this)
->addAttribute('default', 'App2\Database', Tests::FIXTURES_PATH . '/../Mocks')
->addXml('default', 'App3\Database', Tests::FIXTURES_PATH . '/../Toolkit');
}

MappingHelper::of($extension)->addAttribute('fake', 'invalid');
}, LogicalException::class, 'Given mapping path "invalid" does not exist');
});
$compiler->addConfig([
'parameters' => [
'tempDir' => Tests::TEMP_PATH,
'fixturesDir' => Tests::FIXTURES_PATH,
],
]);
$compiler->addConfig(Neonkit::load(
<<<'NEON'
nettrine.dbal:
connections:
default:
driver: pdo_sqlite
password: test
user: test
path: ":memory:"
nettrine.orm:
managers:
default:
connection: default
mapping:
App:
type: attributes
dirs: [%fixturesDir%/Entity]
namespace: Tests\Mocks
NEON
));
})
->build();

/** @var MappingDriverChain $driver */
$driver = $container->getService('nettrine.orm.managers.default.mappingDriver');
Assert::count(3, $driver->getDrivers());
Assert::equal([DummyEntity::class], $driver->getAllClassNames());
});
10 changes: 10 additions & 0 deletions tests/Mocks/DummyExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php declare(strict_types = 1);

namespace Tests\Mocks;

use Nette\DI\CompilerExtension;

class DummyExtension extends CompilerExtension
{

}

0 comments on commit 817cdc4

Please sign in to comment.