From 117d8ec68103113d1265f737964b9edc9ad32857 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 4 Dec 2023 10:50:23 +0100 Subject: [PATCH 1/2] link attributes documentation in toc --- docs/en/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/index.rst b/docs/en/index.rst index 46517211e..870bfa0e1 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -36,7 +36,8 @@ Mapping Objects onto a Document Repository :doc:`Inheritance ` * **Mapping Driver References**: - :doc:`Docblock Annotations ` | + :doc:`PHP Attributes ` | + :doc:`Docblock Annotations (deprecated) ` | :doc:`XML ` | :doc:`YAML ` | :doc:`Metadata Drivers ` From 2e397e8be5483f67b7b94ce2db98bed640712ab2 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 4 Dec 2023 11:04:01 +0100 Subject: [PATCH 2/2] fix typos and add attributes mapping test --- CHANGELOG.md | 2 +- cli-config.doctrine_dbal.php.dist | 2 +- cli-config.jackrabbit.php.dist | 2 +- .../reference/installation-configuration.rst | 2 +- docs/en/reference/versioning.rst | 2 +- .../RegisterSystemNodeTypesCommand.php | 2 +- .../Attribute/AttributeMappingTest.php | 355 ++++++++++++++++++ 7 files changed, 361 insertions(+), 6 deletions(-) create mode 100644 tests/Doctrine/Tests/ODM/PHPCR/Functional/Mapping/Attribute/AttributeMappingTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index adcb9f3f1..fe20d251b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -355,7 +355,7 @@ maintenance release of the 1.0 family with bugfixes - Doctrine\Common\Persistence\Event\LifecycleEventArgs Only the MoveEventArgs remain specific to PHPCR-ODM. * **2013-09-27**: Removed deprecated legacy handling for the mapping that - allowed using "name" instead of "property" to configure PHCPR property in mapping. + allowed using "name" instead of "property" to configure PHPCR property in mapping. * **2013-09-26**: [Model] add HierarchyInterface for objects that resolve to nt:HierarchyNode, the method AbstractFile::addChild is diff --git a/cli-config.doctrine_dbal.php.dist b/cli-config.doctrine_dbal.php.dist index f5c86eb9b..d6746bbc6 100644 --- a/cli-config.doctrine_dbal.php.dist +++ b/cli-config.doctrine_dbal.php.dist @@ -2,7 +2,7 @@ /** * The config file is responsible to make class loading work and initialize a * DocumentManagerHelper that contains the doctrine document manager with a - * Session of your phcpr implementation. + * Session of your phpcr implementation. * The array $extraCommands can be used to inject implementation specific commands. * Add instances of commands for eventual implementation specific commands to this array. */ diff --git a/cli-config.jackrabbit.php.dist b/cli-config.jackrabbit.php.dist index 421d2c4ef..b3e0b6bfa 100644 --- a/cli-config.jackrabbit.php.dist +++ b/cli-config.jackrabbit.php.dist @@ -2,7 +2,7 @@ /** * The config file is responsible to make class loading work and initialize a * DocumentManagerHelper that contains the doctrine document manager with a - * Session of your phcpr implementation. + * Session of your phpcr implementation. * The array $extraCommands can be used to inject implementation specific commands. * Add instances of commands for eventual implementation specific commands to this array. */ diff --git a/docs/en/reference/installation-configuration.rst b/docs/en/reference/installation-configuration.rst index 0ae7fc8e1..c2a698b51 100644 --- a/docs/en/reference/installation-configuration.rst +++ b/docs/en/reference/installation-configuration.rst @@ -39,7 +39,7 @@ storage. You can force one of the available providers in your projects composer. Each of the providers requires some additional setup. The following sections will briefly list how to set each of them up. Please refer to the documentation of the provider you choose for details. -Install Jackalope-Jackrabbit PHCPR provider +Install Jackalope-Jackrabbit PHPCR provider ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Jackalope-Jackrabbit uses the Java backend jackrabbit for storage. diff --git a/docs/en/reference/versioning.rst b/docs/en/reference/versioning.rst index 37e28b717..932f65623 100644 --- a/docs/en/reference/versioning.rst +++ b/docs/en/reference/versioning.rst @@ -125,7 +125,7 @@ Note that all fields of a document are automatically versioned, you can not exclude anything from being versioned. Referenced documents are not versioned at the same time, but it is stored to which document the reference pointed at this time. Children and parents are not versioned by default. Children can be -versioned by defining a PHCPR node type that specifies to cascade versioning. +versioned by defining a PHPCR node type that specifies to cascade versioning. This feature however is untested with PHPCR-ODM, if you have feedback please tell us. diff --git a/lib/Doctrine/ODM/PHPCR/Tools/Console/Command/RegisterSystemNodeTypesCommand.php b/lib/Doctrine/ODM/PHPCR/Tools/Console/Command/RegisterSystemNodeTypesCommand.php index 7c6adf1b8..fa8636b8a 100644 --- a/lib/Doctrine/ODM/PHPCR/Tools/Console/Command/RegisterSystemNodeTypesCommand.php +++ b/lib/Doctrine/ODM/PHPCR/Tools/Console/Command/RegisterSystemNodeTypesCommand.php @@ -25,7 +25,7 @@ use Symfony\Component\Console\Output\OutputInterface; /** - * Command to register the phcpr-odm required node types. + * Command to register the phpcr-odm required node types. * * This command registers the necessary node types to get phpcr odm working */ diff --git a/tests/Doctrine/Tests/ODM/PHPCR/Functional/Mapping/Attribute/AttributeMappingTest.php b/tests/Doctrine/Tests/ODM/PHPCR/Functional/Mapping/Attribute/AttributeMappingTest.php new file mode 100644 index 000000000..b04d086ef --- /dev/null +++ b/tests/Doctrine/Tests/ODM/PHPCR/Functional/Mapping/Attribute/AttributeMappingTest.php @@ -0,0 +1,355 @@ +dm = $this->createDocumentManager([__DIR__]); + $this->resetFunctionalNode($this->dm); + } + + public function testAnnotationInheritance(): void + { + $extending = new ExtendingClass(); + $extending->id = '/functional/extending'; + $extending->text = 'test text'; + + $this->dm->persist($extending); + $this->dm->flush(); + + $this->assertEquals(1, $extending->callback_run); + $this->assertEquals(1, $extending->extending_run); + } + + public function testSecondLevelInheritance(): void + { + $second = new SecondLevel(); + $second->id = '/functional/second'; + $this->dm->persist($second); + } + + public function testSecondLevelInheritanceWithDuplicate(): void + { + $second = new SecondLevelWithDuplicate(); + $second->id = '/functional/second'; + $second->text = 'text test'; + + $this->expectException(MappingException::class); + $this->dm->persist($second); + } + + public function testSecondLevelOverwrite(): void + { + $localePrefs = [ + 'en' => ['en', 'de'], + 'de' => ['de', 'en'], + ]; + + $this->dm->setLocaleChooserStrategy(new LocaleChooser($localePrefs, 'en')); + + $secondTrans = new SecondLevelWithDuplicateOverwrite(); + $secondTrans->id = '/functional/secondTrans'; + $secondTrans->text = 'deutsch'; + $this->dm->persist($secondTrans); + $this->dm->bindTranslation($secondTrans, 'de'); + $secondTrans->text = 'english'; + $this->dm->bindTranslation($secondTrans, 'en'); + + $this->dm->flush(); + + $tmpDocDe = $this->dm->findTranslation(null, '/functional/secondTrans', 'de'); + + $this->assertEquals($tmpDocDe->text, 'deutsch'); + + $tmpDocEn = $this->dm->findTranslation(null, '/functional/secondTrans', 'en'); + + $this->assertEquals($tmpDocEn->text, 'english'); + } + + /** + * @dataProvider generatorTypeProvider + * + * @param string $class the fqn class name to load + * @param int $type the generator type constant + * @param string $description to be used in case of failure + */ + public function testIdStrategy($class, $type, $description): void + { + $metadata = $this->dm->getClassMetadata($class); + $this->assertEquals($type, $metadata->idGenerator, $description); + } + + public function generatorTypeProvider(): array + { + return [ + [ + ParentIdStrategy::class, + ClassMetadata::GENERATOR_TYPE_PARENT, + 'parentId', + ], + [ + ParentIdStrategyDifferentOrder::class, + ClassMetadata::GENERATOR_TYPE_PARENT, + 'parentId2', + ], + [ + AutoNameIdStrategy::class, + ClassMetadata::GENERATOR_TYPE_AUTO, + 'autoname as only has parent but not nodename', + ], + [ + AssignedIdStrategy::class, + ClassMetadata::GENERATOR_TYPE_ASSIGNED, + 'assigned', + ], + [ + RepositoryIdStrategy::class, + ClassMetadata::GENERATOR_TYPE_REPOSITORY, + 'repository', + ], + [ + StandardCase::class, + ClassMetadata::GENERATOR_TYPE_ASSIGNED, + 'standardcase', + ], + ]; + } + + /** + * @dataProvider invalidIdProvider + * + * @param string $class fqn of a class with invalid mapping + */ + public function testInvalidId(string $class): void + { + $this->expectException(MappingException::class); + $this->dm->getClassMetadata($class); + } + + public function invalidIdProvider(): array + { + return [ + [ + ParentIdNoParentStrategy::class, + AutoNameIdNoParentStrategy::class, + NoId::class, + ], + ]; + } + + public function testPersistParentId(): void + { + $doc = new ParentIdStrategy(); + $doc->name = 'parent-strategy'; + $doc->parent = $this->dm->find(null, '/functional'); + $this->dm->persist($doc); + $this->dm->flush(); + $this->dm->clear(); + $this->assertInstanceOf(ParentIdStrategy::class, $this->dm->find(null, '/functional/parent-strategy')); + } + + public function testPersistAutoNameId(): void + { + $doc = new AutoNameIdStrategy(); + $doc->parent = $this->dm->find(null, '/functional'); + $this->dm->persist($doc); + $this->dm->flush(); + $id = $this->dm->getUnitOfWork()->getDocumentId($doc); + $this->dm->clear(); + $this->assertInstanceOf(AutoNameIdStrategy::class, $this->dm->find(null, $id)); + } + + public function testPersistRepository(): void + { + $doc = new RepositoryIdStrategy(); + $doc->title = 'repository strategy'; + $this->dm->persist($doc); + $this->dm->flush(); + $id = $this->dm->getUnitOfWork()->getDocumentId($doc); + $this->dm->clear(); + $this->assertInstanceOf(RepositoryIdStrategy::class, $this->dm->find(null, $id)); + } + + // TODO comprehensive test for all possible mapped fields in an abstract test, trying to persist and check if properly set + // then dm->clear and check if still properly set. + + // then a test per mapping implementation extending the abstract test and providing documents with the mapping +} + +#[PHPCR\Document] +class Testclass +{ + #[PHPCR\Id] + public $id; + + #[PHPCR\Node] + public $node; + + #[PHPCR\Field(type: 'string')] + public $text; + + #[PHPCR\Depth] + public $depth; + + public int $callback_run = 0; + + #[PHPCR\PostPersist] + public function callback(): void + { + ++$this->callback_run; + } +} + +#[PHPCR\Document] +class ExtendingClass extends Testclass +{ + #[PHPCR\ReferenceOne] + public $reference; + + public int $extending_run = 0; + + #[PHPCR\PostPersist] + public function extendingCallback(): void + { + ++$this->extending_run; + } +} + +#[PHPCR\Document] +class SecondLevel extends ExtendingClass +{ +} + +#[PHPCR\Document] +class SecondLevelWithDuplicate extends ExtendingClass +{ + #[PHPCR\Field(type: 'long')] + public $text; +} + +#[PHPCR\Document(translator: 'attribute')] +class SecondLevelWithDuplicateOverwrite extends ExtendingClass +{ + #[PHPCR\Locale] + public $locale; + + #[PHPCR\Field(type: 'string', translated: true)] + public $text; +} + +#[PHPCR\Document] +class ParentIdStrategy +{ + #[PHPCR\Nodename] + public $name; + + #[PHPCR\ParentDocument] + public $parent; +} + +#[PHPCR\Document] +class ParentIdStrategyDifferentOrder +{ + #[PHPCR\Nodename] + public $name; + + #[PHPCR\ParentDocument] + public $parent; + + #[PHPCR\Id] + public $id; +} + +#[PHPCR\Document] +class AutoNameIdStrategy +{ + #[PHPCR\ParentDocument] + public $parent; +} + +#[PHPCR\Document] +class AssignedIdStrategy +{ + #[PHPCR\Id(strategy: 'assigned')] + public $id; + + #[PHPCR\Nodename] + public $name; + + #[PHPCR\ParentDocument] + public $parent; +} + +#[PHPCR\Document(repositoryClass: Repository::class)] +class RepositoryIdStrategy +{ + public $title; + + #[PHPCR\Id(strategy: 'repository')] + public $id; +} +class Repository extends DocumentRepository implements RepositoryIdInterface +{ + public function generateId($document, $parent = null) + { + return '/functional/'.str_replace(' ', '-', $document->title); + } +} + +/** + * Invalid document missing a parent mapping for the id strategy + */ +#[PHPCR\Document] +class ParentIdNoParentStrategy +{ + #[PHPCR\Id(strategy: 'parent')] + public $id; + + #[PHPCR\Nodename] + public $name; +} + +/** + * Invalid document not having a parent mapping. + */ +#[PHPCR\Document] +class AutoNameIdNoParentStrategy +{ + #[PHPCR\Id(strategy: 'auto')] + public $id; +} + +/** + * + * Invalid document not having an id at all. + */ +#[PHPCR\Document] +class NoId +{ +} + +#[PHPCR\Document] +class StandardCase +{ + #[PHPCR\Id] + public $id; +}