mirror of
https://github.com/doctrine/mongodb-maker-bundle.git
synced 2026-03-23 22:42:07 +01:00
PHPORM-439 Initialize the make:document command (#3)
* Setup test * Draft implementation of make:document command * doctrine/mongodb-odm-bundle has now an official recipe * Add tests to MongoDBHelper * Update attribute namespace for ODM v2.16 * Fix tests * Require version 1.x from symfony/maker-bundle, as it exist in my fork and in the symfony repo * Add symfony/phpunit-bridge because it's symlinked in test environment 'https://github.com/symfony/maker-bundle/pull/480#pullrequestreview-304282682' * Add mongodb-atlas-local container to tests * Add PHP 8.5 polyfill
This commit is contained in:
82
.github/workflows/continuous-integration.yml
vendored
82
.github/workflows/continuous-integration.yml
vendored
@@ -8,12 +8,82 @@ on:
|
||||
branches:
|
||||
- "*.x"
|
||||
|
||||
env:
|
||||
fail-fast: true
|
||||
|
||||
jobs:
|
||||
phpunit:
|
||||
name: "PHPUnit"
|
||||
uses: "doctrine/.github/.github/workflows/continuous-integration.yml@13.1.0"
|
||||
with:
|
||||
php-versions: '["8.4", "8.5"]'
|
||||
phpunit-options-lowest: "--do-not-fail-on-deprecation"
|
||||
secrets:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
services:
|
||||
mongodb:
|
||||
image: "mongodb/mongodb-atlas-local:latest"
|
||||
ports:
|
||||
- "27017:27017"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dependencies:
|
||||
- "highest"
|
||||
include:
|
||||
- php-version: "8.4"
|
||||
dependencies: "lowest"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Install PHP with PCOV"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
extensions: "mongodb"
|
||||
coverage: "pcov"
|
||||
ini-file: "development"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "${{ matrix.dependencies }}"
|
||||
composer-options: "--prefer-dist"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: >
|
||||
vendor/bin/phpunit --coverage-clover=coverage.xml
|
||||
${{ matrix.dependencies == 'lowest' && '--do-not-fail-on-deprecation' || '' }}
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v5"
|
||||
with:
|
||||
name: "phpunit-${{ matrix.php-version }}-${{ matrix.dependencies }}.coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
upload_coverage:
|
||||
name: "Upload coverage to Codecov"
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs:
|
||||
- "phpunit"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Download coverage files"
|
||||
uses: "actions/download-artifact@v6"
|
||||
with:
|
||||
path: "reports"
|
||||
|
||||
- name: "Upload to Codecov"
|
||||
uses: "codecov/codecov-action@v5"
|
||||
with:
|
||||
directory: "reports"
|
||||
env:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,5 +3,6 @@
|
||||
/composer.lock
|
||||
/phpcs.xml
|
||||
/phpunit.xml
|
||||
/tests/tmp
|
||||
/var
|
||||
/vendor
|
||||
|
||||
@@ -3,19 +3,26 @@
|
||||
"description": "Symfony MakerBundle for MongoDB ODM",
|
||||
"keywords": ["mongodb", "maker", "odm", "dev"],
|
||||
"type": "symfony-bundle",
|
||||
"repositories": [
|
||||
{ "type": "github", "url": "https://github.com/GromNaN/symfony-maker-bundle" }
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.4",
|
||||
"ext-mongodb": "^2.1",
|
||||
"doctrine/mongodb-odm-bundle": "^5.5",
|
||||
"symfony/maker-bundle": "^1.65",
|
||||
"symfony/http-kernel": "^7.4|^8"
|
||||
"doctrine/mongodb-odm": "^2.16",
|
||||
"doctrine/mongodb-odm-bundle": "^5.6",
|
||||
"symfony/http-kernel": "^7.4|^8",
|
||||
"symfony/maker-bundle": "^1@dev",
|
||||
"symfony/polyfill-php85": "^1.33"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^14",
|
||||
"phpstan/phpstan": "^2.1.30",
|
||||
"phpstan/phpstan-phpunit": "^2.0.7",
|
||||
"phpunit/phpunit": "^12.5",
|
||||
"symfony/framework-bundle": "^7.4|^8"
|
||||
"symfony/phpunit-bridge": "^8",
|
||||
"symfony/framework-bundle": "^7.4|^8",
|
||||
"twig/twig": "^3.22"
|
||||
},
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
|
||||
3
config/help/MakeDocument.txt
Normal file
3
config/help/MakeDocument.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The <info>%command.name%</info> command creates or updates a document and repository class.
|
||||
|
||||
<info>php %command.full_name% BlogPost</info>
|
||||
@@ -14,11 +14,29 @@ declare(strict_types=1);
|
||||
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\Maker\MakeDocument;
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDB\DocumentClassGenerator;
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDB\MongoDBHelper;
|
||||
|
||||
return static function (ContainerConfigurator $container): void {
|
||||
$services = $container->services();
|
||||
|
||||
$services->set('doctrine_mongodb_maker.mongodb_helper', MongoDBHelper::class)
|
||||
->args([
|
||||
service('doctrine_mongodb'),
|
||||
]);
|
||||
|
||||
$services->set('doctrine_mongodb_maker.document_class_generator', DocumentClassGenerator::class)
|
||||
->args([
|
||||
service('maker.generator'),
|
||||
service('doctrine_mongodb_maker.mongodb_helper'),
|
||||
]);
|
||||
|
||||
$services->set('doctrine_mongodb_maker.maker.make_document', MakeDocument::class)
|
||||
->args([])
|
||||
->args([
|
||||
service('maker.file_manager'),
|
||||
service('doctrine_mongodb_maker.mongodb_helper'),
|
||||
service('maker.generator'),
|
||||
service('doctrine_mongodb_maker.document_class_generator'),
|
||||
])
|
||||
->tag('maker.command');
|
||||
};
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
<file>config</file>
|
||||
<file>src</file>
|
||||
<file>tests</file>
|
||||
<file>tests/TestKernel.php</file>
|
||||
<file>tests/BundleTest.php</file>
|
||||
<file>tests/Maker</file>
|
||||
|
||||
<rule ref="Doctrine" />
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint" />
|
||||
|
||||
@@ -4,6 +4,8 @@ parameters:
|
||||
paths:
|
||||
- src
|
||||
- tests
|
||||
excludePaths:
|
||||
- tests/tmp
|
||||
|
||||
includes:
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
|
||||
@@ -6,9 +6,15 @@
|
||||
failOnAllIssues="true"
|
||||
displayDetailsOnAllIssues="true"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<env name="MONGODB_URI" value="mongodb://localhost:27017" />
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Doctrine MongoDB Maker Bundle Test Suite">
|
||||
<directory>./tests/</directory>
|
||||
<exclude>./tests/tmp</exclude>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
|
||||
@@ -4,39 +4,390 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\Maker;
|
||||
|
||||
use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDB\DocumentClassGenerator;
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDB\MongoDBHelper;
|
||||
use Doctrine\ODM\MongoDB\Types\Type;
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
use ReflectionProperty;
|
||||
use Symfony\Bundle\MakerBundle\ConsoleStyle;
|
||||
use Symfony\Bundle\MakerBundle\DependencyBuilder;
|
||||
use Symfony\Bundle\MakerBundle\FileManager;
|
||||
use Symfony\Bundle\MakerBundle\Generator;
|
||||
use Symfony\Bundle\MakerBundle\InputAwareMakerInterface;
|
||||
use Symfony\Bundle\MakerBundle\InputConfiguration;
|
||||
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
|
||||
use Symfony\Bundle\MakerBundle\Maker\Common\UidTrait;
|
||||
use Symfony\Bundle\MakerBundle\Str;
|
||||
use Symfony\Bundle\MakerBundle\Util\ClassDetails;
|
||||
use Symfony\Bundle\MakerBundle\Util\ClassSource\Model\ClassProperty;
|
||||
use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator;
|
||||
use Symfony\Bundle\MakerBundle\Validator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function class_exists;
|
||||
use function dirname;
|
||||
use function file_get_contents;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function str_starts_with;
|
||||
use function substr;
|
||||
|
||||
final class MakeDocument extends AbstractMaker implements InputAwareMakerInterface
|
||||
{
|
||||
use UidTrait;
|
||||
|
||||
public function __construct(
|
||||
private FileManager $fileManager,
|
||||
private MongoDBHelper $mongoDBHelper,
|
||||
private Generator|null $generator = null,
|
||||
private DocumentClassGenerator|null $documentClassGenerator = null,
|
||||
) {
|
||||
$this->generator ??= new Generator($fileManager, 'App\\');
|
||||
$this->documentClassGenerator ??= new DocumentClassGenerator($this->generator, $this->mongoDBHelper);
|
||||
}
|
||||
|
||||
public static function getCommandName(): string
|
||||
{
|
||||
return 'doctrine:mongodb:make:document';
|
||||
return 'make:document';
|
||||
}
|
||||
|
||||
public static function getCommandDescription(): string
|
||||
{
|
||||
return 'Creates a new MongoDB ODM document class';
|
||||
return 'Create or update a MongoDB ODM document class';
|
||||
}
|
||||
|
||||
public function configureCommand(Command $command, InputConfiguration $inputConfig): void
|
||||
{
|
||||
// TODO: Implement configureCommand() method.
|
||||
$command
|
||||
->addArgument('name', InputArgument::OPTIONAL, sprintf('Class name of the document to create or update (e.g. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
|
||||
->addOption('regenerate', null, InputOption::VALUE_NONE, 'Instead of adding new fields, simply generate the methods (e.g. getter/setter) for existing fields')
|
||||
->addOption('overwrite', null, InputOption::VALUE_NONE, 'Overwrite any existing getter/setter methods')
|
||||
->setHelp((string) file_get_contents(dirname(__DIR__, 2) . '/config/help/MakeDocument.txt'));
|
||||
|
||||
$this->addWithUuidOption($command);
|
||||
|
||||
$inputConfig->setArgumentAsNonInteractive('name');
|
||||
}
|
||||
|
||||
public function configureDependencies(DependencyBuilder $dependencies, InputInterface|null $input = null): void
|
||||
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void
|
||||
{
|
||||
// TODO: Implement configureDependencies() method.
|
||||
$documentClassName = $input->getArgument('name');
|
||||
if ($documentClassName && empty($this->verifyDocumentName($documentClassName))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->getOption('regenerate')) {
|
||||
$io->block([
|
||||
'This command will generate any missing methods (e.g. getters & setters) for a class or all classes in a namespace.',
|
||||
'To overwrite any existing methods, re-run this command with the --overwrite flag',
|
||||
], null, 'fg=yellow');
|
||||
$classOrNamespace = $io->ask('Enter a class or namespace to regenerate', $this->getDocumentNamespace(), Validator::notBlank(...));
|
||||
|
||||
$input->setArgument('name', $classOrNamespace);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->checkIsUsingUid($input);
|
||||
|
||||
$argument = $command->getDefinition()->getArgument('name');
|
||||
$question = $this->createDocumentClassQuestion($argument->getDescription());
|
||||
$documentClassName ??= $io->askQuestion($question);
|
||||
|
||||
while ($this->verifyDocumentName($documentClassName)) {
|
||||
if ($io->confirm(sprintf('"%s" contains one or more non-ASCII characters, which can be problematic with MongoDB. It is recommended to use only ASCII characters for document names. Continue anyway?', $documentClassName), false)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$documentClassName = $io->askQuestion($question);
|
||||
}
|
||||
|
||||
$input->setArgument('name', $documentClassName);
|
||||
}
|
||||
|
||||
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
|
||||
{
|
||||
// TODO: Implement generate() method.
|
||||
$overwrite = $input->getOption('overwrite');
|
||||
|
||||
// the regenerate option has entirely custom behavior
|
||||
if ($input->getOption('regenerate')) {
|
||||
$io->comment('Document regeneration is not yet implemented.');
|
||||
$this->writeSuccessMessage($io);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$documentClassDetails = $generator->createClassNameDetails(
|
||||
$input->getArgument('name'),
|
||||
'Document\\',
|
||||
);
|
||||
|
||||
$classExists = class_exists($documentClassDetails->getFullName());
|
||||
if (! $classExists) {
|
||||
$documentPath = $this->documentClassGenerator->generateDocumentClass(
|
||||
documentClassDetails: $documentClassDetails,
|
||||
idType: $this->getIdType(),
|
||||
);
|
||||
|
||||
$generator->writeChanges();
|
||||
$io->text([
|
||||
'',
|
||||
'Document generated! Now let\'s add some fields!',
|
||||
'You can always add more fields later manually or by re-running this command.',
|
||||
]);
|
||||
} else {
|
||||
$documentPath = $this->getPathOfClass($documentClassDetails->getFullName());
|
||||
$io->text('Your document already exists! So let\'s add some new fields!');
|
||||
}
|
||||
|
||||
$currentFields = $this->getPropertyNames($documentClassDetails->getFullName());
|
||||
$manipulator = $this->createClassManipulator($documentPath, $io, $overwrite);
|
||||
|
||||
$isFirstField = true;
|
||||
while (true) {
|
||||
$newField = $this->askForNextField($io, $currentFields, $documentClassDetails->getFullName(), $isFirstField);
|
||||
$isFirstField = false;
|
||||
|
||||
if ($newField === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
$manipulator->addEntityField($newField);
|
||||
$currentFields[] = $newField->propertyName;
|
||||
|
||||
$this->fileManager->dumpFile($documentPath, $manipulator->getSourceCode());
|
||||
}
|
||||
|
||||
$this->writeSuccessMessage($io);
|
||||
$io->text([
|
||||
'Next: Add more fields with the same command, or start using your document!',
|
||||
'',
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureDependencies(DependencyBuilder $dependencies, InputInterface|null $input = null): void
|
||||
{
|
||||
$dependencies->addClassDependency(
|
||||
DoctrineMongoDBBundle::class,
|
||||
'doctrine/mongodb-odm-bundle',
|
||||
);
|
||||
}
|
||||
|
||||
/** @param string[] $fields */
|
||||
private function askForNextField(ConsoleStyle $io, array $fields, string $documentClass, bool $isFirstField): ClassProperty|null
|
||||
{
|
||||
$io->writeln('');
|
||||
|
||||
if ($isFirstField) {
|
||||
$questionText = 'New property name (press <return> to stop adding fields)';
|
||||
} else {
|
||||
$questionText = 'Add another property? Enter the property name (or press <return> to stop adding fields)';
|
||||
}
|
||||
|
||||
$fieldName = $io->ask($questionText, null, function ($name) use ($fields) {
|
||||
// allow it to be empty
|
||||
if (! $name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if (in_array($name, $fields, true)) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" property already exists.', $name));
|
||||
}
|
||||
|
||||
return Validator::validateDoctrineFieldName($name, $this->mongoDBHelper->getRegistry());
|
||||
});
|
||||
|
||||
if (! $fieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$defaultType = 'string';
|
||||
// try to guess the type by the field name prefix/suffix
|
||||
$snakeCasedField = Str::asSnakeCase($fieldName);
|
||||
|
||||
$suffix = substr($snakeCasedField, -3);
|
||||
if ($suffix === '_at') {
|
||||
$defaultType = 'date_immutable';
|
||||
} elseif ($suffix === '_id') {
|
||||
$defaultType = 'int';
|
||||
} elseif (str_starts_with($snakeCasedField, 'is_')) {
|
||||
$defaultType = 'bool';
|
||||
} elseif (str_starts_with($snakeCasedField, 'has_')) {
|
||||
$defaultType = 'bool';
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$types = $this->getTypesMap();
|
||||
|
||||
$allValidTypes = array_keys($types);
|
||||
|
||||
while ($type === null) {
|
||||
$question = new Question('Field type (enter <comment>?</comment> to see all types)', $defaultType);
|
||||
$question->setAutocompleterValues($allValidTypes);
|
||||
$type = $io->askQuestion($question);
|
||||
|
||||
if ($type === '?') {
|
||||
$this->printAvailableTypes($io);
|
||||
$io->writeln('');
|
||||
|
||||
$type = null;
|
||||
} elseif (! in_array($type, $allValidTypes, true)) {
|
||||
$this->printAvailableTypes($io);
|
||||
$io->error(sprintf('Invalid type "%s".', $type));
|
||||
$io->writeln('');
|
||||
|
||||
$type = null;
|
||||
}
|
||||
}
|
||||
|
||||
// this is a normal field
|
||||
$classProperty = new ClassProperty(propertyName: $fieldName, type: $type);
|
||||
|
||||
if ($type === 'string') {
|
||||
// MongoDB doesn't have length constraints at the database level
|
||||
// but we can still track it for validation purposes
|
||||
$classProperty->length = null;
|
||||
}
|
||||
|
||||
if ($io->confirm('Can this field be null in the database (nullable)', false)) {
|
||||
$classProperty->nullable = true;
|
||||
}
|
||||
|
||||
return $classProperty;
|
||||
}
|
||||
|
||||
private function printAvailableTypes(ConsoleStyle $io): void
|
||||
{
|
||||
$allTypes = $this->getTypesMap();
|
||||
|
||||
$typesTable = [
|
||||
'main' => [
|
||||
'string' => [],
|
||||
'int' => [],
|
||||
'float' => [],
|
||||
'bool' => [],
|
||||
],
|
||||
'array_object' => [
|
||||
'hash' => [],
|
||||
'collection' => [],
|
||||
'object_id' => [],
|
||||
],
|
||||
'date_time' => [
|
||||
'date' => ['date_immutable'],
|
||||
'timestamp' => [],
|
||||
],
|
||||
];
|
||||
|
||||
$printSection = static function (array $sectionTypes) use ($io, &$allTypes): void {
|
||||
foreach ($sectionTypes as $mainType => $subTypes) {
|
||||
if (! array_key_exists($mainType, $allTypes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($subTypes as $key => $potentialType) {
|
||||
if (! array_key_exists($potentialType, $allTypes)) {
|
||||
unset($subTypes[$key]);
|
||||
}
|
||||
|
||||
unset($allTypes[$potentialType]);
|
||||
}
|
||||
|
||||
unset($allTypes[$mainType]);
|
||||
|
||||
$line = sprintf(' * <comment>%s</comment>', $mainType);
|
||||
|
||||
if ($subTypes !== []) {
|
||||
$line .= sprintf(' or %s', implode(' or ', array_map(
|
||||
static fn ($subType) => sprintf('<comment>%s</comment>', $subType),
|
||||
$subTypes,
|
||||
)));
|
||||
}
|
||||
|
||||
$io->writeln($line);
|
||||
}
|
||||
|
||||
$io->writeln('');
|
||||
};
|
||||
|
||||
$io->writeln('<info>Main Types</info>');
|
||||
$printSection($typesTable['main']);
|
||||
|
||||
$io->writeln('<info>Array/Object Types</info>');
|
||||
$printSection($typesTable['array_object']);
|
||||
|
||||
$io->writeln('<info>Date/Time Types</info>');
|
||||
$printSection($typesTable['date_time']);
|
||||
|
||||
$io->writeln('<info>Other Types</info>');
|
||||
$allTypes = array_map(static fn () => [], $allTypes);
|
||||
$printSection($allTypes);
|
||||
}
|
||||
|
||||
private function createDocumentClassQuestion(string $questionText): Question
|
||||
{
|
||||
$question = new Question($questionText);
|
||||
$question->setValidator(Validator::notBlank(...));
|
||||
$question->setAutocompleterValues($this->mongoDBHelper->getDocumentsForAutocomplete());
|
||||
|
||||
return $question;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function verifyDocumentName(string $documentName): array
|
||||
{
|
||||
preg_match('/([^\x00-\x7F]+)/u', $documentName, $matches);
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
private function createClassManipulator(string $path, ConsoleStyle $io, bool $overwrite): ClassSourceManipulator
|
||||
{
|
||||
$manipulator = new ClassSourceManipulator(
|
||||
sourceCode: $this->fileManager->getFileContents($path),
|
||||
overwrite: $overwrite,
|
||||
);
|
||||
|
||||
$manipulator->setIo($io);
|
||||
|
||||
return $manipulator;
|
||||
}
|
||||
|
||||
private function getPathOfClass(string $class): string
|
||||
{
|
||||
return (new ClassDetails($class))->getPath();
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function getPropertyNames(string $class): array
|
||||
{
|
||||
if (! class_exists($class)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$reflClass = new ReflectionClass($class);
|
||||
|
||||
return array_map(static fn (ReflectionProperty $prop) => $prop->getName(), $reflClass->getProperties());
|
||||
}
|
||||
|
||||
private function getDocumentNamespace(): string
|
||||
{
|
||||
return $this->mongoDBHelper->getDocumentNamespace();
|
||||
}
|
||||
|
||||
/** @return array<string, string> */
|
||||
private function getTypesMap(): array
|
||||
{
|
||||
return Type::getTypesMap();
|
||||
}
|
||||
}
|
||||
|
||||
91
src/MongoDB/DocumentClassGenerator.php
Normal file
91
src/MongoDB/DocumentClassGenerator.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\MongoDB;
|
||||
|
||||
use Doctrine\ODM\MongoDB\DocumentManager;
|
||||
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
|
||||
use Symfony\Bundle\MakerBundle\Generator;
|
||||
use Symfony\Bundle\MakerBundle\Maker\Common\EntityIdTypeEnum;
|
||||
use Symfony\Bundle\MakerBundle\Str;
|
||||
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
|
||||
use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator;
|
||||
|
||||
use function dirname;
|
||||
|
||||
/** @internal */
|
||||
final class DocumentClassGenerator
|
||||
{
|
||||
public function __construct(
|
||||
private Generator $generator,
|
||||
private MongoDBHelper $mongoDBHelper,
|
||||
) {
|
||||
}
|
||||
|
||||
public function generateDocumentClass(
|
||||
ClassNameDetails $documentClassDetails,
|
||||
bool $generateRepositoryClass = true,
|
||||
EntityIdTypeEnum $idType = EntityIdTypeEnum::INT,
|
||||
): string {
|
||||
$repoClassDetails = $this->generator->createClassNameDetails(
|
||||
$documentClassDetails->getRelativeName(),
|
||||
'Repository\\',
|
||||
'Repository',
|
||||
);
|
||||
|
||||
$collectionName = $this->mongoDBHelper->getPotentialCollectionName($documentClassDetails->getFullName());
|
||||
|
||||
$useStatements = new UseStatementGenerator([
|
||||
$repoClassDetails->getFullName(),
|
||||
['Doctrine\\ODM\\MongoDB\\Mapping\\Attribute' => 'ODM'],
|
||||
]);
|
||||
|
||||
$templatePath = dirname(__DIR__, 2) . '/templates/mongodb/Document.tpl.php';
|
||||
$documentPath = $this->generator->generateClass(
|
||||
$documentClassDetails->getFullName(),
|
||||
$templatePath,
|
||||
[
|
||||
'use_statements' => $useStatements,
|
||||
'repository_class_name' => $repoClassDetails->getShortName(),
|
||||
'collection_name' => $collectionName,
|
||||
'id_type' => $idType,
|
||||
],
|
||||
);
|
||||
|
||||
if ($generateRepositoryClass) {
|
||||
$this->generateRepositoryClass(
|
||||
$repoClassDetails->getFullName(),
|
||||
$documentClassDetails->getFullName(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
return $documentPath;
|
||||
}
|
||||
|
||||
public function generateRepositoryClass(
|
||||
string $repositoryClass,
|
||||
string $documentClass,
|
||||
bool $includeExampleComments = true,
|
||||
): void {
|
||||
$shortDocumentClass = Str::getShortClassName($documentClass);
|
||||
|
||||
$useStatements = new UseStatementGenerator([
|
||||
$documentClass,
|
||||
DocumentManager::class,
|
||||
DocumentRepository::class,
|
||||
]);
|
||||
|
||||
$templatePath = dirname(__DIR__, 2) . '/templates/mongodb/Repository.tpl.php';
|
||||
$this->generator->generateClass(
|
||||
$repositoryClass,
|
||||
$templatePath,
|
||||
[
|
||||
'use_statements' => $useStatements,
|
||||
'document_class_name' => $shortDocumentClass,
|
||||
'include_example_comments' => $includeExampleComments,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
101
src/MongoDB/MongoDBHelper.php
Normal file
101
src/MongoDB/MongoDBHelper.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\MongoDB;
|
||||
|
||||
use Doctrine\ODM\MongoDB\DocumentManager;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Symfony\Bundle\MakerBundle\Str;
|
||||
|
||||
use function array_first;
|
||||
use function array_keys;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function str_contains;
|
||||
|
||||
/** @internal */
|
||||
final class MongoDBHelper
|
||||
{
|
||||
private const string DEFAULT_DOCUMENT_NAMESPACE = 'App\\Document';
|
||||
|
||||
public function __construct(
|
||||
private ManagerRegistry $registry,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRegistry(): ManagerRegistry
|
||||
{
|
||||
return $this->registry;
|
||||
}
|
||||
|
||||
public function getPotentialCollectionName(string $className): string
|
||||
{
|
||||
$shortClassName = Str::getShortClassName($className);
|
||||
|
||||
return Str::asSnakeCase($shortClassName);
|
||||
}
|
||||
|
||||
public function getDocumentNamespace(): string
|
||||
{
|
||||
$documentManager = $this->registry->getManager();
|
||||
|
||||
if (! $documentManager instanceof DocumentManager) {
|
||||
return self::DEFAULT_DOCUMENT_NAMESPACE;
|
||||
}
|
||||
|
||||
$metadataDriver = $documentManager->getConfiguration()->getMetadataDriverImpl();
|
||||
$documentNamespaces = [];
|
||||
|
||||
if ($metadataDriver === null) {
|
||||
return self::DEFAULT_DOCUMENT_NAMESPACE;
|
||||
}
|
||||
|
||||
foreach ($metadataDriver->getAllClassNames() as $className) {
|
||||
$parts = explode('\\', $className);
|
||||
if (count($parts) <= 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array_pop($parts);
|
||||
$documentNamespaces[implode('\\', $parts)] = true;
|
||||
}
|
||||
|
||||
$namespaces = array_keys($documentNamespaces);
|
||||
|
||||
// Prefer 'Document' namespace if it exists
|
||||
foreach ($namespaces as $namespace) {
|
||||
if (str_contains($namespace, '\\Document')) {
|
||||
return $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
return array_first($namespaces) ?? self::DEFAULT_DOCUMENT_NAMESPACE;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getDocumentsForAutocomplete(): array
|
||||
{
|
||||
$documentManager = $this->registry->getManager();
|
||||
|
||||
if (! $documentManager instanceof DocumentManager) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$metadataDriver = $documentManager->getConfiguration()->getMetadataDriverImpl();
|
||||
$allDocuments = [];
|
||||
|
||||
if ($metadataDriver === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($metadataDriver->getAllClassNames() as $className) {
|
||||
$allDocuments[] = $className;
|
||||
$allDocuments[] = Str::getShortClassName($className);
|
||||
}
|
||||
|
||||
return $allDocuments;
|
||||
}
|
||||
}
|
||||
42
templates/mongodb/Document.tpl.php
Normal file
42
templates/mongodb/Document.tpl.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Bundle\MakerBundle\Maker\Common\EntityIdTypeEnum;
|
||||
|
||||
?>
|
||||
<?= "<?php\n" ?>
|
||||
|
||||
namespace <?= $namespace ?>;
|
||||
|
||||
<?= $use_statements; ?>
|
||||
|
||||
#[ODM\Document(repositoryClass: <?= $repository_class_name ?>::class)]
|
||||
#[ODM\Collection(name: '<?= $collection_name ?>')]
|
||||
class <?= $class_name."\n" ?>
|
||||
{
|
||||
<?php if (EntityIdTypeEnum::UUID === $id_type): ?>
|
||||
#[ODM\Id(strategy: 'UUID')]
|
||||
private ?string $id = null;
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
<?php elseif (EntityIdTypeEnum::ULID === $id_type): ?>
|
||||
#[ODM\Id(strategy: 'UUID')]
|
||||
private ?string $id = null;
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
<?php else: ?>
|
||||
#[ODM\Id]
|
||||
private ?string $id = null;
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
<?php endif ?>
|
||||
}
|
||||
|
||||
40
templates/mongodb/Repository.tpl.php
Normal file
40
templates/mongodb/Repository.tpl.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?= "<?php\n" ?>
|
||||
|
||||
namespace <?= $namespace ?>;
|
||||
|
||||
<?= $use_statements; ?>
|
||||
|
||||
/**
|
||||
* @extends DocumentRepository<<?= $document_class_name ?>>
|
||||
*/
|
||||
class <?= $class_name ?> extends DocumentRepository
|
||||
{
|
||||
public function __construct(DocumentManager $dm)
|
||||
{
|
||||
parent::__construct($dm, $dm->getUnitOfWork(), $dm->getClassMetadata(<?= $document_class_name ?>::class));
|
||||
}
|
||||
|
||||
<?php if ($include_example_comments): ?>
|
||||
/**
|
||||
* @return <?= $document_class_name ?>[]
|
||||
*/
|
||||
public function findByExampleField(mixed $value): array
|
||||
{
|
||||
return $this->createQueryBuilder()
|
||||
->field('exampleField')->equals($value)
|
||||
->getQuery()
|
||||
->execute()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function findOneBySomeField(mixed $value): ?<?= $document_class_name ?>
|
||||
|
||||
{
|
||||
return $this->createQueryBuilder()
|
||||
->field('exampleField')->equals($value)
|
||||
->getQuery()
|
||||
->getSingleResult();
|
||||
}
|
||||
<?php endif ?>
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class BundleTest extends TestCase
|
||||
|
||||
$commandLoader = $kernel->getContainer()->get('console.command_loader');
|
||||
self::assertInstanceOf(CommandLoaderInterface::class, $commandLoader);
|
||||
self::assertTrue($commandLoader->has('doctrine:mongodb:make:document'));
|
||||
self::assertTrue($commandLoader->has('make:document'));
|
||||
|
||||
$kernel->shutdown();
|
||||
}
|
||||
|
||||
81
tests/Maker/MakeDocumentTest.php
Normal file
81
tests/Maker/MakeDocumentTest.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony MakerBundle package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\Tests\Maker;
|
||||
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\Maker\MakeDocument;
|
||||
use Generator;
|
||||
use Symfony\Bundle\MakerBundle\Test\MakerTestCase;
|
||||
use Symfony\Bundle\MakerBundle\Test\MakerTestDetails;
|
||||
use Symfony\Bundle\MakerBundle\Test\MakerTestRunner;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
use function getenv;
|
||||
|
||||
class MakeDocumentTest extends MakerTestCase
|
||||
{
|
||||
protected function getMakerClass(): string
|
||||
{
|
||||
return MakeDocument::class;
|
||||
}
|
||||
|
||||
private static function createMakeDocumentTest(bool $withDatabase = true): MakerTestDetails
|
||||
{
|
||||
return self::buildMakerTest()
|
||||
->preRun(static function (MakerTestRunner $runner) use ($withDatabase): void {
|
||||
if (! $withDatabase) {
|
||||
return;
|
||||
}
|
||||
|
||||
$runner->replaceInFile(
|
||||
'.env',
|
||||
'mongodb://localhost:27017',
|
||||
(string) getenv('MONGODB_URI'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected function createKernel(): KernelInterface
|
||||
{
|
||||
return new MakerTestKernel('dev', true);
|
||||
}
|
||||
|
||||
public static function getTestDetails(): Generator
|
||||
{
|
||||
yield 'it_creates_a_new_class_basic' => [
|
||||
self::createMakeDocumentTest()
|
||||
->run(static function (MakerTestRunner $runner): void {
|
||||
$runner->runMaker([
|
||||
// document class name
|
||||
'User',
|
||||
// no additional fields
|
||||
'',
|
||||
]);
|
||||
|
||||
self::runDocumentTest($runner);
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
private static function runDocumentTest(MakerTestRunner $runner, array $data = []): void
|
||||
{
|
||||
$runner->renderTemplateFile(
|
||||
'make-document/GeneratedDocumentTest.php.twig',
|
||||
'tests/GeneratedDocumentTest.php',
|
||||
['data' => $data],
|
||||
);
|
||||
|
||||
$runner->runTests();
|
||||
}
|
||||
}
|
||||
38
tests/Maker/MakerTestKernel.php
Normal file
38
tests/Maker/MakerTestKernel.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\Tests\Maker;
|
||||
|
||||
use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDBMakerBundle;
|
||||
use Symfony\Bundle\MakerBundle\Test\MakerTestKernel as MakerBundleTestKernel;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class MakerTestKernel extends MakerBundleTestKernel
|
||||
{
|
||||
public function registerBundles(): iterable
|
||||
{
|
||||
yield from parent::registerBundles();
|
||||
yield new DoctrineMongoDBBundle();
|
||||
yield new MongoDBMakerBundle();
|
||||
}
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader): void
|
||||
{
|
||||
parent::registerContainerConfiguration($loader);
|
||||
|
||||
$loader->load(static function (ContainerBuilder $container): void {
|
||||
$container->loadFromExtension('doctrine_mongodb', [
|
||||
'default_connection' => 'default',
|
||||
'connections' => [
|
||||
'default' => ['server' => 'mongodb://localhost:27017'],
|
||||
],
|
||||
'document_managers' => [
|
||||
'default' => ['auto_mapping' => true],
|
||||
],
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
144
tests/MongoDB/MongoDBHelperTest.php
Normal file
144
tests/MongoDB/MongoDBHelperTest.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Doctrine MongoDB Maker Bundle package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\Tests\MongoDB;
|
||||
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDB\MongoDBHelper;
|
||||
use Doctrine\ODM\MongoDB\Configuration;
|
||||
use Doctrine\ODM\MongoDB\DocumentManager;
|
||||
use Doctrine\ODM\MongoDB\Mapping\Driver\AttributeDriver;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Generator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\Stub;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MongoDBHelperTest extends TestCase
|
||||
{
|
||||
private MongoDBHelper $helper;
|
||||
private ManagerRegistry&Stub $registry;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->registry = $this->createStub(ManagerRegistry::class);
|
||||
$this->helper = new MongoDBHelper($this->registry);
|
||||
}
|
||||
|
||||
#[DataProvider('getPotentialCollectionNameDataProvider')]
|
||||
public function testGetPotentialCollectionName(string $className, string $expectedCollectionName): void
|
||||
{
|
||||
$result = $this->helper->getPotentialCollectionName($className);
|
||||
|
||||
$this->assertSame($expectedCollectionName, $result);
|
||||
}
|
||||
|
||||
/** @return Generator<string, array{0: string, 1: string}> */
|
||||
public static function getPotentialCollectionNameDataProvider(): Generator
|
||||
{
|
||||
yield 'simple class name' => [
|
||||
'App\\Document\\User',
|
||||
'user',
|
||||
];
|
||||
|
||||
yield 'camel case to snake case' => [
|
||||
'App\\Document\\UserProfile',
|
||||
'user_profile',
|
||||
];
|
||||
|
||||
yield 'already snake case' => [
|
||||
'App\\Document\\user_account',
|
||||
'user_account',
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetDocumentNamespaceWhenDocumentManagerIsNotAvailable(): void
|
||||
{
|
||||
$this->registry->method('getManager')->willReturn($this->createStub(ObjectManager::class));
|
||||
$result = $this->helper->getDocumentNamespace();
|
||||
|
||||
$this->assertSame('App\\Document', $result);
|
||||
}
|
||||
|
||||
/** @param class-string[] $classNames */
|
||||
#[DataProvider('getDocumentNamespaceWithDocumentsDataProvider')]
|
||||
public function testGetDocumentNamespaceWithDocuments(array $classNames, string $expectedNamespace): void
|
||||
{
|
||||
$documentManagerMock = $this->createStub(DocumentManager::class);
|
||||
$configMock = $this->createStub(Configuration::class);
|
||||
$driverMock = $this->createStub(AttributeDriver::class);
|
||||
|
||||
$driverMock->method('getAllClassNames')->willReturn($classNames);
|
||||
$configMock->method('getMetadataDriverImpl')->willReturn($driverMock);
|
||||
$documentManagerMock->method('getConfiguration')->willReturn($configMock);
|
||||
|
||||
$this->registry->method('getManager')->willReturn($documentManagerMock);
|
||||
$result = $this->helper->getDocumentNamespace();
|
||||
|
||||
$this->assertSame($expectedNamespace, $result);
|
||||
}
|
||||
|
||||
/** @return Generator<string, array<int, mixed>> */
|
||||
public static function getDocumentNamespaceWithDocumentsDataProvider(): Generator
|
||||
{
|
||||
yield 'single class with Document namespace' => [
|
||||
['App\\Document\\User'],
|
||||
'App\\Document',
|
||||
];
|
||||
|
||||
yield 'multiple classes in Document namespace' => [
|
||||
['App\\Document\\User', 'App\\Document\\Post'],
|
||||
'App\\Document',
|
||||
];
|
||||
|
||||
yield 'classes in Document and other namespace' => [
|
||||
['App\\Models\\Post', 'App\\Document\\User'],
|
||||
'App\\Document',
|
||||
];
|
||||
|
||||
yield 'single class without Document namespace' => [
|
||||
['App\\Entity\\User'],
|
||||
'App\\Entity',
|
||||
];
|
||||
|
||||
yield 'multiple classes without Document namespace' => [
|
||||
['App\\Entity\\User', 'App\\Entity\\Post'],
|
||||
'App\\Entity',
|
||||
];
|
||||
|
||||
yield 'multiple different namespaces without Document' => [
|
||||
['App\\Entity\\User', 'App\\Models\\Post'],
|
||||
'App\\Entity',
|
||||
];
|
||||
|
||||
yield 'multiple different namespaces with Document' => [
|
||||
['App\\Entity\\User', 'App\\Document\\Post', 'App\\Models\\Product'],
|
||||
'App\\Document',
|
||||
];
|
||||
|
||||
yield 'nested Document namespace' => [
|
||||
['Doctrine\\Bundle\\MongoDBMakerBundle\\Document\\BlogPost'],
|
||||
'Doctrine\\Bundle\\MongoDBMakerBundle\\Document',
|
||||
];
|
||||
|
||||
yield 'single class without namespace' => [
|
||||
['SingleClass'],
|
||||
'App\\Document',
|
||||
];
|
||||
|
||||
yield 'empty class list' => [
|
||||
[],
|
||||
'App\\Document',
|
||||
];
|
||||
}
|
||||
}
|
||||
62
tests/TestKernel.php
Normal file
62
tests/TestKernel.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\MongoDBMakerBundle\Tests;
|
||||
|
||||
use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle;
|
||||
use Doctrine\Bundle\MongoDBMakerBundle\MongoDBMakerBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Bundle\MakerBundle\DependencyInjection\CompilerPass\MakeCommandRegistrationPass;
|
||||
use Symfony\Bundle\MakerBundle\MakerBundle;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
class TestKernel extends Kernel implements CompilerPassInterface
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
|
||||
public function registerBundles(): iterable
|
||||
{
|
||||
return [
|
||||
new FrameworkBundle(),
|
||||
new DoctrineMongoDBBundle(),
|
||||
new MakerBundle(),
|
||||
new MongoDBMakerBundle(),
|
||||
];
|
||||
}
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader): void
|
||||
{
|
||||
$loader->load(static function (ContainerBuilder $container): void {
|
||||
$container->loadFromExtension('framework', ['secret' => 'S0ME_SECRET']);
|
||||
$container->loadFromExtension('doctrine_mongodb', [
|
||||
'default_connection' => 'default',
|
||||
'connections' => [
|
||||
'default' => ['server' => 'mongodb://localhost:27017'],
|
||||
],
|
||||
'document_managers' => [
|
||||
'default' => ['auto_mapping' => true],
|
||||
],
|
||||
]);
|
||||
$container->loadFromExtension('maker', []);
|
||||
$container->loadFromExtension('mongodb_maker', ['generate_final_documents' => true]);
|
||||
});
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
/**
|
||||
* Makes all makers public to help the tests
|
||||
*
|
||||
* @see \Symfony\Bundle\MakerBundle\Test\MakerTestKernel::process()
|
||||
*/
|
||||
foreach ($container->findTaggedServiceIds(MakeCommandRegistrationPass::MAKER_TAG) as $id => $tags) {
|
||||
$defn = $container->getDefinition($id);
|
||||
$defn->setPublic(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
tests/fixtures/make-document/GeneratedDocumentTest.php.twig
vendored
Normal file
35
tests/fixtures/make-document/GeneratedDocumentTest.php.twig
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests;
|
||||
|
||||
use App\Document\User;
|
||||
use Doctrine\ODM\MongoDB\DocumentManager;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
class GeneratedDocumentTest extends KernelTestCase
|
||||
{
|
||||
public function testGeneratedDocument()
|
||||
{
|
||||
self::bootKernel();
|
||||
/** @var DocumentManager $dm */
|
||||
$dm = self::$kernel->getContainer()
|
||||
->get('doctrine_mongodb')
|
||||
->getManager();
|
||||
|
||||
$dm->createQueryBuilder(User::class)
|
||||
->remove()
|
||||
->getQuery()
|
||||
->execute();
|
||||
|
||||
$user = new User();
|
||||
{% for field, value in data %}
|
||||
$user->{{ field }} = '{{ value }}';
|
||||
{% endfor %}
|
||||
$dm->persist($user);
|
||||
$dm->flush();
|
||||
|
||||
$actualUser = $dm->getRepository(User::class)->findAll();
|
||||
|
||||
$this->assertcount(1, $actualUser);
|
||||
}
|
||||
}
|
||||
17
tests/fixtures/make-document/documents/User-basic.php
vendored
Normal file
17
tests/fixtures/make-document/documents/User-basic.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Document;
|
||||
|
||||
use Doctrine\ODM\MongoDB\Mapping\Attribute as ODM;
|
||||
|
||||
#[ODM\Document]
|
||||
class User
|
||||
{
|
||||
#[ODM\Id]
|
||||
public int|null $id = null;
|
||||
|
||||
#[ODM\Field]
|
||||
public string|null $firstName = null;
|
||||
}
|
||||
Reference in New Issue
Block a user