Skip to content
Browse files

Merge pull request #180 from doctrine/hashmaps

added support for hashmaps (PHPCR-56)
  • Loading branch information...
2 parents c62988d + 8cdeef4 commit 96ce1bab8ebf3726530845451034139cf35f78b1 @dbu dbu committed Oct 7, 2012
View
2 lib/Doctrine/ODM/PHPCR/Mapping/Annotations/DoctrineAnnotations.php
@@ -89,6 +89,8 @@ class Property
public $type = 'undefined';
/** @var boolean */
public $multivalue = false;
+ /** @var string */
+ public $assoc;
}
/**
* Base class for all the translatable properties (i.e. every property but Uuid and Version)
View
33 lib/Doctrine/ODM/PHPCR/Mapping/ClassMetadata.php
@@ -584,6 +584,13 @@ protected function validateAndCompleteFieldMapping($mapping, $isField = true)
$mapping['name'] = $mapping['fieldName'];
}
+ if ($isField && isset($mapping['assoc'])) {
+ $mapping['multivalue'] = true;
+ if (empty($mapping['assoc'])) {
+ $mapping['assoc'] = $mapping['name'].'Keys';
+ }
+ }
+
if (isset($this->fieldMappings[$mapping['fieldName']])
|| ($this->node == $mapping['fieldName'])
|| ($this->nodename == $mapping['fieldName'])
@@ -629,6 +636,32 @@ protected function validateAndCompleteAssociationMapping($mapping)
return $mapping;
}
+ public function validateClassMapping()
+ {
+ $assocFields = array();
+ foreach ($this->fieldMappings as $fieldName => $mapping) {
+ if (empty($mapping['assoc'])) {
+ continue;
+ }
+
+ if (!empty($this->fieldMappings[$mapping['assoc']])) {
+ throw MappingException::assocOverlappingFieldDefinition($this->name, $fieldName, $mapping['assoc']);
+ }
+
+ if (!empty($assocFields[$mapping['assoc']])) {
+ throw MappingException::assocOverlappingAssocDefinition($this->name, $fieldName, $assocFields[$mapping['assoc']]);
+ }
+
+ $assocFields[$mapping['assoc']] = $fieldName;
+ }
+
+ if (count($this->translatableFields)) {
+ if (!isset($this->localeMapping)) {
+ throw new MappingException("You must define a locale mapping for translatable document '".$this->name."'");
+ }
+ }
+ }
+
public function mapManyToOne($mapping)
{
$mapping = $this->validateAndCompleteAssociationMapping($mapping);
View
9 lib/Doctrine/ODM/PHPCR/Mapping/Driver/AnnotationDriver.php
@@ -41,7 +41,6 @@
*/
class AnnotationDriver extends AbstractAnnotationDriver implements MappingDriver
{
-
/**
* {@inheritdoc}
*
@@ -180,12 +179,6 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
}
}
- // Check there is a @Locale annotation for translatable documents
- if (count($metadata->translatableFields)) {
- if (!isset($metadata->localeMapping)) {
- throw new MappingException("You must define a @Locale field for translatable document '$className'");
- }
- }
+ $metadata->validateClassMapping();
}
-
}
View
1 lib/Doctrine/ODM/PHPCR/Mapping/Driver/XmlDriver.php
@@ -177,6 +177,7 @@ public function loadMetadataForClass($className, ClassMetadata $class)
}
}
+ $class->validateClassMapping();
}
private function addReferenceMapping(ClassMetadata $class, $reference, $type)
View
1 lib/Doctrine/ODM/PHPCR/Mapping/Driver/YamlDriver.php
@@ -195,6 +195,7 @@ public function loadMetadataForClass($className, ClassMetadata $class)
}
}
+ $class->validateClassMapping();
}
private function addMappingFromReference(ClassMetadata $class, $fieldName, $reference, $type)
View
24 lib/Doctrine/ODM/PHPCR/Mapping/MappingException.php
@@ -32,17 +32,17 @@ class MappingException extends \Exception
{
public static function classNotFound($className)
{
- return new self('The class: ' . $className . ' could not be found');
+ return new self("The class: '$className'. could not be found");
}
public static function classIsNotAValidDocument($className)
{
- return new self('Class '.$className.' is not a valid document or mapped super class.');
+ return new self("Class '$className' is not a valid document or mapped super class.");
}
public static function reflectionFailure($document, \ReflectionException $previousException)
{
- return new self('An error occurred in ' . $document, 0, $previousException);
+ return new self("An error occurred in '$document'", 0, $previousException);
}
/**
@@ -51,7 +51,7 @@ public static function reflectionFailure($document, \ReflectionException $previo
*/
public static function duplicateFieldMapping($document, $fieldName)
{
- return new self('Property "'.$fieldName.'" in "'.$document.'" was already declared, but it must be declared only once');
+ return new self("Property '$fieldName'. in .'$document'. was already declared, but it must be declared only once");
}
/**
@@ -60,7 +60,7 @@ public static function duplicateFieldMapping($document, $fieldName)
*/
public static function missingTypeDefinition($document, $fieldName)
{
- return new self('Property "'.$fieldName.'" in "'.$document.'" must have a type attribute defined');
+ return new self("Property '$fieldName' in '$document' must have a type attribute defined");
}
public static function fileMappingDriversRequireConfiguredDirectoryPath($path)
@@ -70,19 +70,29 @@ public static function fileMappingDriversRequireConfiguredDirectoryPath($path)
public static function classNotMapped($className)
{
- return new self('Class ' . $className . ' is not mapped to a document');
+ return new self("Class '$className' is not mapped to a document");
}
public static function pathRequired()
{
- return new self('Path is requiredt');
+ return new self('Path is required');
}
public static function noTypeSpecified()
{
return new self('No type specified');
}
+ public static function assocOverlappingFieldDefinition($document, $fieldName, $overlappingFieldName)
+ {
+ return new self("The 'assoc' attributes may not overlap with field '$overlappingFieldName' for property '$fieldName' in '$document'.");
+ }
+
+ public static function assocOverlappingAssocDefinition($document, $fieldName, $overlappingAssoc)
+ {
+ return new self("The 'assoc' attributes may not overlap with assoc property '$overlappingAssoc' for property '$fieldName' in '$document'.");
+ }
+
public static function mappingNotFound($className, $fieldName)
{
return new self("No mapping found for field '$fieldName' in class '$className'.");
View
19 lib/Doctrine/ODM/PHPCR/UnitOfWork.php
@@ -261,10 +261,13 @@ public function createDocument($className, NodeInterface $node, array &$hints =
foreach ($class->fieldMappings as $fieldName => $mapping) {
if (isset($properties[$mapping['name']])) {
if ($mapping['multivalue']) {
- $collection = $properties[$mapping['name']] instanceof Collection
- ? $properties[$mapping['name']]
- : new ArrayCollection((array)$properties[$mapping['name']])
- ;
+ if ($properties[$mapping['name']] instanceof Collection) {
+ $collection = $properties[$mapping['name']];
+ } elseif (isset($mapping['assoc']) && isset($properties[$mapping['assoc']])) {
+ $collection = new ArrayCollection(array_combine((array)$properties[$mapping['assoc']], (array)$properties[$mapping['name']]));
+ } else {
+ $collection = new ArrayCollection((array)$properties[$mapping['name']]);
+ }
$documentState[$fieldName] = new MultivaluePropertyCollection($collection);
$this->multivaluePropertyCollections[] = $documentState[$fieldName];
} else {
@@ -1431,6 +1434,10 @@ private function executeInserts($documents)
if ($class->fieldMappings[$fieldName]['multivalue']) {
$value = $fieldValue === null ? null : $fieldValue->toArray();
+ if ($value && isset($class->fieldMappings[$fieldName]['assoc'])) {
+ $node->setProperty($class->fieldMappings[$fieldName]['assoc'], array_keys($value), $type);
+ $value = array_values($value);
+ }
$node->setProperty($class->fieldMappings[$fieldName]['name'], $value, $type);
} else {
$node->setProperty($class->fieldMappings[$fieldName]['name'], $fieldValue, $type);
@@ -1502,6 +1509,10 @@ private function executeUpdates($documents, $dispatchEvents = true)
$type = PropertyType::valueFromName($class->fieldMappings[$fieldName]['type']);
if ($class->fieldMappings[$fieldName]['multivalue']) {
$value = $fieldValue === null ? null : $fieldValue->toArray();
+ if ($value && isset($class->fieldMappings[$fieldName]['assoc'])) {
+ $node->setProperty($class->fieldMappings[$fieldName]['assoc'], array_keys($value), $type);
+ $value = array_values($value);
+ }
$node->setProperty($class->fieldMappings[$fieldName]['name'], $value, $type);
} else {
$node->setProperty($class->fieldMappings[$fieldName]['name'], $fieldValue, $type);
View
48 tests/Doctrine/Tests/ODM/PHPCR/Functional/BasicCrudTest.php
@@ -38,6 +38,8 @@ public function setUp()
$user = $this->node->addNode('user');
$user->setProperty('username', 'lsmith');
$user->setProperty('numbers', array(3, 1, 2));
+ $user->setProperty('parameters', array('bar', 'dong'));
+ $user->setProperty('parameterKey', array('foo', 'ding'));
$user->setProperty('phpcr:class', $this->type, PropertyType::STRING);
$this->dm->getPhpcrSession()->save();
}
@@ -402,6 +404,50 @@ public function testNoIdProperty()
$this->assertEquals('test2', $userNew->username);
$this->assertEquals($user->numbers->toArray(), $userNew->numbers->toArray());
}
+
+ public function testAssocProperty()
+ {
+ $user = new User();
+ $user->username = "test";
+ $assocArray = array('foo' => 'bar', 'ding' => 'dong');
+ $user->parameters = $assocArray;
+ $user->id = '/functional/test';
+
+ $this->dm->persist($user);
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $user = $this->dm->find(null, '/functional/test');
+
+ $this->assertNotNull($user);
+ $this->assertEquals($user->parameters->toArray(), $assocArray);
+
+ $assocArray = array('foo' => 'bar', 'hello' => 'world', 'check' => 'out');
+ $user->parameters = $assocArray;
+
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $user = $this->dm->find(null, '/functional/test');
+
+ $this->assertNotNull($user);
+ $this->assertEquals($user->parameters->toArray(), $assocArray);
+
+ $user->parameters->remove('foo');
+ unset($assocArray['foo']);
+ $user->parameters->set('boo', 'yah');
+ $assocArray['boo'] = 'yah';
+ $user->parameters->set('hello', 'welt');
+ $assocArray['hello'] = 'welt';
+
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $user = $this->dm->find(null, '/functional/test');
+
+ $this->assertNotNull($user);
+ $this->assertEquals($user->parameters->toArray(), $assocArray);
+ }
}
/**
@@ -417,6 +463,8 @@ class User
public $username;
/** @PHPCRODM\Int(name="numbers", multivalue=true) */
public $numbers;
+ /** @PHPCRODM\String(name="parameters", assoc="") */
+ public $parameters;
}
/**

0 comments on commit 96ce1ba

Please sign in to comment.
Something went wrong with that request. Please try again.