Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ODM embedded-like functionality #419

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9d487c7
New MappedAssociation annotation.
djlambert Aug 7, 2012
0e55b8a
Annotation driver support for MappedAssocation annotation.
djlambert Aug 7, 2012
8be7fd9
Added array to hold mapped associations.
djlambert Aug 7, 2012
34925e9
Include mapped associations in sleep and reflection wakeup.
djlambert Aug 7, 2012
b5032bd
Added method addMappedAssociation to validate and add mapped associat…
djlambert Aug 7, 2012
ca160d9
Added mapped association exceptions.
djlambert Aug 7, 2012
b165068
Added utility functions to check if class has mapped associations and…
djlambert Aug 7, 2012
457c439
Added method addMappedAssociationDiscriminatorColumnDefinitions to ad…
djlambert Aug 7, 2012
f15895c
Add mapped association discriminator columns to the schema.
djlambert Aug 7, 2012
be0c83b
Include mapped association in change detection.
djlambert Aug 7, 2012
27ec173
Skip association if mapped association discriminator column is empty.
djlambert Aug 7, 2012
3a4e012
Populate mapped association entity.
djlambert Aug 7, 2012
dd315f4
Added method getMappedAssociationDiscriminatorColumnName to get mappe…
djlambert Aug 7, 2012
b4d24e7
Null 'field' value for mapped association discriminator columns to sk…
djlambert Aug 7, 2012
19c2951
Include the mapped association discriminator column value in the upda…
djlambert Aug 7, 2012
d042db4
Added method _getSelectMappedAssociationDiscriminatorColumnSQL to get…
djlambert Aug 7, 2012
02c4f08
Add mapped association descriminator columns to select list. If mappe…
djlambert Aug 7, 2012
3e4a601
Move getClassMetaData call earlier and refactor variable name.
djlambert Aug 7, 2012
72112fa
Check if association is in the skip array.
djlambert Aug 7, 2012
e314497
If mapped association don't INSERT non-existent column.
djlambert Aug 7, 2012
a18a07d
Add mapped association discriminator columns to the INSERT list.
djlambert Aug 7, 2012
66bf0c3
Models for mapped association testing.
djlambert Aug 7, 2012
96971b9
Add new models to model sets and teardown.
djlambert Aug 7, 2012
9602bbf
Tests for mapped associations.
djlambert Aug 7, 2012
e7fa8a3
Remove extra whitespace and add newline at EOF.
djlambert Aug 7, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php
Expand Up @@ -158,10 +158,12 @@ protected function hydrateColumnInfo($entityName, $column)
return null;
}

$field = isset($class->mappedAssociationMappings[$this->_rsm->fieldMappings[$column]]) ? null : true;

return array(
'class' => $class,
'name' => $this->_rsm->fieldMappings[$column],
'field' => true,
'field' => $field,
);

case (isset($this->_rsm->relationMap[$column])):
Expand Down
74 changes: 74 additions & 0 deletions lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
Expand Up @@ -373,6 +373,13 @@ class ClassMetadataInfo implements ClassMetadata
*/
public $columnNames = array();

/**
* READ-ONLY: The mapped associations of the class.
*
* @var array
*/
public $mappedAssociations = array();

/**
* READ-ONLY: The discriminator value of this class.
*
Expand Down Expand Up @@ -816,6 +823,10 @@ public function __sleep()
$serialized[] = "customGeneratorDefinition";
}

if ($this->mappedAssociations) {
$serialized[] = "mappedAssociations";
}

return $serialized;
}

Expand Down Expand Up @@ -854,6 +865,10 @@ public function wakeupReflection($reflService)
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}

foreach ($this->mappedAssociations as $field => $mapping) {
$this->reflFields[$field] = $reflService->getAccessibleProperty($this->name, $field);
}
}

/**
Expand Down Expand Up @@ -2083,6 +2098,45 @@ public function addInheritedFieldMapping(array $fieldMapping)
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
}

/**
* Add a mapped association to the class
*
* @param array $mapping
*
* @throws MappingException
*/
public function addMappedAssociation(array $mapping)
{
$fieldMapping = &$mapping['fieldMapping'];

if (!isset($fieldMapping['columnName'])) {
$fieldMapping['fieldName'] = $mapping['name'] . 'Class';
$fieldMapping['columnName'] = $this->namingStrategy->propertyToColumnName($fieldMapping['fieldName']);
} else {
$fieldMapping['fieldName'] = $fieldMapping['columnName'];
}

if ($fieldMapping['columnName'][0] === '`') {
$fieldMapping['columnName'] = trim($fieldMapping['columnName'], '`');
$fieldMapping['quoted'] = true;
}

$fieldMapping['type'] = 'string';

if (isset($this->fieldNames[$fieldMapping['columnName']])) {
throw MappingException::duplicateColumnName($this->name, $fieldMapping['columnName']);
}

if (!isset($this->associationMappings[$mapping['name']])) {
throw MappingException::associationRequiredForMappedAssociation($this->name, $fieldMapping['columnName']);
} elseif ($this->associationMappings[$mapping['name']]['type'] != self::ONE_TO_ONE || $this->associationMappings[$mapping['name']]['isOwningSide']) {
throw MappingException::unsupportedAssociationForMappedAssociation($this->name, $fieldMapping['columnName']);
}

$this->mappedAssociationMappings[$fieldMapping['columnName']] = $mapping['name'];
$this->mappedAssociations[$mapping['name']] = $mapping;
}

/**
* INTERNAL:
* Adds a named query to this class.
Expand Down Expand Up @@ -2467,6 +2521,26 @@ public function hasSqlResultSetMapping($name)
return isset($this->sqlResultSetMappings[$name]);
}

/**
* Checks whether the class has any mapped associations.
*
* @return array
*/
public function hasMappedAssociations()
{
return $this->mappedAssociations;
}

/**
* Return array of all mapped associations of the class.
*
* @return array
*/
public function getMappedAssociations()
{
return $this->mappedAssociations;
}

/**
* {@inheritDoc}
*/
Expand Down
14 changes: 12 additions & 2 deletions lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php
Expand Up @@ -40,12 +40,22 @@ public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform
: $class->fieldMappings[$fieldName]['columnName'];
}

/**
* {@inheritdoc}
*/
public function getMappedAssociationDiscriminatorColumnName(array $assoc, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($assoc['fieldMapping']['quoted'])
? $platform->quoteIdentifier($assoc['fieldMapping']['columnName'])
: $assoc['fieldMapping']['columnName'];
}

/**
* {@inheritdoc}
*/
public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
{
return isset($class->table['quoted'])
return isset($class->table['quoted'])
? $platform->quoteIdentifier($class->table['name'])
: $class->table['name'];
}
Expand Down Expand Up @@ -137,4 +147,4 @@ public function getColumnAlias($columnName, $counter, AbstractPlatform $platform
return $platform->getSQLResultCasing($columnName);
}

}
}
12 changes: 12 additions & 0 deletions lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
Expand Up @@ -400,6 +400,18 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)

$metadata->mapManyToMany($mapping);
}

// Evaluate MappedAssociation annotation
$mappedAssociation = array();
if ($mappedAssocAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\MappedAssociation')) {
$mappedAssociation['name'] = $property->getName();
$mappedAssociation['fieldMapping'] = array (
'columnName' => $mappedAssocAnnot->discriminatorColumn,
'length' => $mappedAssocAnnot->length,
'nullable' => $mappedAssocAnnot->nullable,
);
$metadata->addMappedAssociation($mappedAssociation);
}
}

// Evaluate AssociationOverrides annotation
Expand Down
1 change: 1 addition & 0 deletions lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php
Expand Up @@ -64,3 +64,4 @@
require_once __DIR__.'/../AssociationOverrides.php';
require_once __DIR__.'/../AttributeOverride.php';
require_once __DIR__.'/../AttributeOverrides.php';
require_once __DIR__.'/../MappedAssociation.php';
36 changes: 36 additions & 0 deletions lib/Doctrine/ORM/Mapping/MappedAssociation.php
@@ -0,0 +1,36 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\ORM\Mapping;

/**
* @Annotation
* @Target("PROPERTY")
*/
final class MappedAssociation implements Annotation
{
/** @var string */
public $discriminatorColumn;

/** @var integer */
public $length = 255;

/** @var boolean */
public $nullable = true;
}
22 changes: 22 additions & 0 deletions lib/Doctrine/ORM/Mapping/MappingException.php
Expand Up @@ -438,4 +438,26 @@ public static function invalidCascadeOption(array $cascades, $className, $proper
$cascades
));
}

/**
* @param string $className
* @param string $field
*
* @return self
*/
public static function associationRequiredForMappedAssociation($className, $field)
{
return new self("One-to-one association required on '$className#$field' for mapped association.");
}

/**
* @param string $className
* @param string $field
*
* @return self
*/
public static function unsupportedAssociationForMappedAssociation($className, $field)
{
return new self("Invalid association type on '$className#$field' for mapped association. Only one-to-one associations are supported with the mapped entity reusing the primary key.");
}
}
13 changes: 12 additions & 1 deletion lib/Doctrine/ORM/Mapping/QuoteStrategy.php
Expand Up @@ -109,4 +109,15 @@ function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platfo
*/
function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null);

}
/**
* Gets the (possibly quoted) mapped association discriminator column name
*
* @param array $assoc
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getMappedAssociationDiscriminatorColumnName(array $assoc, ClassMetadata $class, AbstractPlatform $platform);

}