/** {@inheritdoc} */ public function getFieldMapping($fieldName) { if (!$this->hasField($fieldName)) { throw new MetadataException("Field '{$fieldName}' not found in class '{$this->getClass()}'."); } return $this->classMetadata->getFieldMapping($fieldName); }
/** * @param string $fieldName * @return $this * @throws MappingException */ private function fromReference($fieldName) { if (!$this->class->hasReference($fieldName)) { MappingException::referenceMappingNotFound($this->class->name, $fieldName); } $referenceMapping = $this->class->getFieldMapping($fieldName); $targetMapping = $this->dm->getClassMetadata($referenceMapping['targetDocument']); parent::from($targetMapping->getCollection()); if ($referenceMapping['isOwningSide']) { if ($referenceMapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) { throw MappingException::cannotLookupNonIdReference($this->class->name, $fieldName); } $this->foreignField('_id')->localField($referenceMapping['name']); } else { if (isset($referenceMapping['repositoryMethod'])) { throw MappingException::repositoryMethodLookupNotAllowed($this->class->name, $fieldName); } $mappedByMapping = $targetMapping->getFieldMapping($referenceMapping['mappedBy']); if ($mappedByMapping['storeAs'] !== ClassMetadataInfo::REFERENCE_STORE_AS_ID) { throw MappingException::cannotLookupNonIdReference($this->class->name, $fieldName); } $this->localField('_id')->foreignField($mappedByMapping['name']); } return $this; }
/** {@inheritdoc} */ public function getAssociationMapping($name) { if (!$this->classMetadata->hasAssociation($name)) { throw new MetadataException("Association '{$name}' not found in class '{$this->getClass()}'."); } return $this->classMetadata->getFieldMapping($name); }
/** * Checks that the current field includes a reference to the supplied document. */ public function includesReferenceTo($document) { if ($this->currentField) { $this->query[$this->currentField][$this->cmd . 'elemMatch'] = $this->class ? $this->dm->createDBRef($document, $this->class->getFieldMapping($this->currentField)) : $this->dm->createDBRef($document); } else { $this->query[$this->cmd . 'elemMatch'] = $this->dm->createDBRef($document); } return $this; }
public function getFieldsMetadata($class) { $result = array(); foreach ($this->odmMetadata->getReflectionProperties() as $property) { $name = $property->getName(); $mapping = $this->odmMetadata->getFieldMapping($name); $values = array('title' => $name, 'source' => true); if (isset($mapping['fieldName'])) { $values['field'] = $mapping['fieldName']; } if (isset($mapping['id']) && $mapping['id'] == 'id') { $values['primary'] = true; } switch ($mapping['type']) { case 'id': case 'int': case 'string': case 'float': case 'many': $values['type'] = 'text'; break; case 'boolean': $values['type'] = 'boolean'; break; case 'date': $values['type'] = 'date'; break; } $result[$name] = $values; } return $result; }
/** * Gets reference mapping for current field from current class or its descendants. * * @return array * @throws MappingException */ private function getReferenceMapping() { $mapping = null; try { $mapping = $this->class->getFieldMapping($this->currentField); } catch (MappingException $e) { if (empty($this->class->discriminatorMap)) { throw $e; } $foundIn = null; foreach ($this->class->discriminatorMap as $child) { $childClass = $this->dm->getClassMetadata($child); if ($childClass->hasAssociation($this->currentField)) { if ($mapping !== null && $mapping !== $childClass->getFieldMapping($this->currentField)) { throw MappingException::referenceFieldConflict($this->currentField, $foundIn->name, $childClass->name); } $mapping = $childClass->getFieldMapping($this->currentField); $foundIn = $childClass; } } if ($mapping === null) { throw MappingException::mappingNotFoundInClassNorDescendants($this->class->name, $this->currentField); } } return $mapping; }
/** * Prepares a query value and converts the php value to the database value if it is an identifier. * It also handles converting $fieldName to the database name if they are different. * * @param string $fieldName * @param string $value * @return mixed $value */ private function prepareQueryValue(&$fieldName, $value) { // Process "association.fieldName" if (strpos($fieldName, '.') !== false) { $e = explode('.', $fieldName); $mapping = $this->class->getFieldMapping($e[0]); if ($this->class->hasField($e[0])) { $name = $this->class->fieldMappings[$e[0]]['name']; if ($name !== $e[0]) { $e[0] = $name; } } if (isset($mapping['targetDocument'])) { $targetClass = $this->dm->getClassMetadata($mapping['targetDocument']); if ($targetClass->hasField($e[1])) { if ($targetClass->identifier === $e[1] || $e[1] === '$id') { $fieldName = $e[0] . '.$id'; $value = $targetClass->getDatabaseIdentifierValue($value); } } } // Process all non identifier fields } elseif ($this->class->hasField($fieldName) && !$this->class->isIdentifier($fieldName)) { $name = $this->class->fieldMappings[$fieldName]['name']; $mapping = $this->class->fieldMappings[$fieldName]; if ($name !== $fieldName) { $fieldName = $name; } // Process identifier } elseif ($fieldName === $this->class->identifier || $fieldName === '_id') { $fieldName = '_id'; $value = $this->class->getDatabaseIdentifierValue($value); } return $value; }
/** * Prepares a query value and converts the php value to the database value if it is an identifier. * It also handles converting $fieldName to the database name if they are different. * * @param string $fieldName * @param string $value * @return mixed $value */ private function prepareQueryValue(&$fieldName, $value) { // Process "association.fieldName" if (strpos($fieldName, '.') !== false) { $e = explode('.', $fieldName); $mapping = $this->class->getFieldMapping($e[0]); $name = $mapping['name']; if ($name !== $e[0]) { $e[0] = $name; } if (isset($mapping['targetDocument'])) { $targetClass = $this->dm->getClassMetadata($mapping['targetDocument']); if ($targetClass->hasField($e[1])) { if ($targetClass->identifier === $e[1]) { $e[1] = '$id'; if (is_array($value)) { foreach ($value as $k => $v) { $value[$k] = $targetClass->getDatabaseIdentifierValue($v); } } else { $value = $targetClass->getDatabaseIdentifierValue($value); } } else { $targetMapping = $targetClass->getFieldMapping($e[1]); $targetName = $targetMapping['name']; if ($targetName !== $e[1]) { $e[1] = $targetName; } } $fieldName = $e[0] . '.' . $e[1]; } } // Process all non identifier fields // We only change the field names here to the mongodb field name used for persistence } elseif ($this->class->hasField($fieldName) && !$this->class->isIdentifier($fieldName)) { $name = $this->class->fieldMappings[$fieldName]['name']; $mapping = $this->class->fieldMappings[$fieldName]; if ($name !== $fieldName) { $fieldName = $name; } // Process identifier } elseif ($this->class->hasField($fieldName) && $this->class->isIdentifier($fieldName) || $fieldName === '_id') { $fieldName = '_id'; if (is_array($value)) { foreach ($value as $k => $v) { if ($k[0] === '$' && is_array($v)) { foreach ($v as $k2 => $v2) { $value[$k][$k2] = $this->class->getDatabaseIdentifierValue($v2); } } else { $value[$k] = $this->class->getDatabaseIdentifierValue($v); } } } else { $value = $this->class->getDatabaseIdentifierValue($value); } } return $value; }
public function getFieldsMetadata($class, $group = 'default') { $result = array(); foreach ($this->odmMetadata->getReflectionProperties() as $property) { $name = $property->getName(); $mapping = $this->odmMetadata->getFieldMapping($name); $values = array('title' => $name, 'source' => true); if (isset($mapping['fieldName'])) { $values['field'] = $mapping['fieldName']; $values['id'] = $mapping['fieldName']; } if (isset($mapping['id']) && $mapping['id'] == 'id') { $values['primary'] = true; } switch ($mapping['type']) { case 'id': case 'string': case 'bin_custom': case 'bin_func': case 'bin_md5': case 'bin': case 'bin_uuid': case 'file': case 'key': case 'increment': $values['type'] = 'text'; break; case 'int': case 'float': $values['type'] = 'number'; break; /*case 'hash': $values['type'] = 'array';*/ /*case 'hash': $values['type'] = 'array';*/ case 'boolean': $values['type'] = 'boolean'; break; case 'date': case 'timestamp': $values['type'] = 'date'; break; case 'collection': $values['type'] = 'array'; break; case 'one': $values['type'] = 'array'; break; case 'many': $values['type'] = 'array'; break; default: $values['type'] = 'text'; } $result[$name] = $values; } return $result; }
/** * Checks that the current field includes a reference to the supplied document. */ public function includesReferenceTo($document) { $dbRef = $this->dm->createDBRef($document); if ($this->currentField) { $keys = array('ref' => true, 'id' => true, 'db' => true); if ($this->class) { $mapping = $this->class->getFieldMapping($this->currentField); if (isset($mapping['targetDocument'])) { unset($keys['ref'], $keys['db']); } } foreach ($keys as $key => $value) { $this->query[$this->currentField][$this->cmd . 'elemMatch'][$this->cmd . $key] = $dbRef[$this->cmd . $key]; } } else { $this->query[$this->cmd . 'elemMatch'] = $dbRef; } return $this; }
public function testClassMetadataInstanceSerialization() { $cm = new ClassMetadata('Documents\\CmsUser'); // Test initial state $this->assertTrue(count($cm->getReflectionProperties()) == 0); $this->assertTrue($cm->reflClass instanceof \ReflectionClass); $this->assertEquals('Documents\\CmsUser', $cm->name); $this->assertEquals('Documents\\CmsUser', $cm->rootDocumentName); $this->assertEquals(array(), $cm->subClasses); $this->assertEquals(array(), $cm->parentClasses); $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_NONE, $cm->inheritanceType); // Customize state $cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION); $cm->setSubclasses(array("One", "Two", "Three")); $cm->setParentClasses(array("UserParent")); $cm->setCustomRepositoryClass("UserRepository"); $cm->setDiscriminatorField('disc'); $cm->mapOneEmbedded(array('fieldName' => 'phonenumbers', 'targetDocument' => 'Bar')); $cm->setFile('customFileProperty'); $cm->setDistance('customDistanceProperty'); $cm->setSlaveOkay(true); $cm->setShardKey(array('_id' => '1')); $cm->setCollectionCapped(true); $cm->setCollectionMax(1000); $cm->setCollectionSize(500); $this->assertTrue(is_array($cm->getFieldMapping('phonenumbers'))); $this->assertEquals(1, count($cm->fieldMappings)); $this->assertEquals(1, count($cm->associationMappings)); $serialized = serialize($cm); $cm = unserialize($serialized); // Check state $this->assertTrue(count($cm->getReflectionProperties()) > 0); $this->assertEquals('Documents', $cm->namespace); $this->assertTrue($cm->reflClass instanceof \ReflectionClass); $this->assertEquals('Documents\\CmsUser', $cm->name); $this->assertEquals('UserParent', $cm->rootDocumentName); $this->assertEquals(array('Documents\\One', 'Documents\\Two', 'Documents\\Three'), $cm->subClasses); $this->assertEquals(array('UserParent'), $cm->parentClasses); $this->assertEquals('Documents\\UserRepository', $cm->customRepositoryClassName); $this->assertEquals('disc', $cm->discriminatorField); $this->assertTrue(is_array($cm->getFieldMapping('phonenumbers'))); $this->assertEquals(1, count($cm->fieldMappings)); $this->assertEquals(1, count($cm->associationMappings)); $this->assertEquals('customFileProperty', $cm->file); $this->assertEquals('customDistanceProperty', $cm->distance); $this->assertTrue($cm->slaveOkay); $this->assertEquals(array('keys' => array('_id' => 1), 'options' => array()), $cm->getShardKey()); $mapping = $cm->getFieldMapping('phonenumbers'); $this->assertEquals('Documents\\Bar', $mapping['targetDocument']); $this->assertTrue($cm->getCollectionCapped()); $this->assertEquals(1000, $cm->getCollectionMax()); $this->assertEquals(500, $cm->getCollectionSize()); }
/** * Prepare where values converting document object field names to the document collection * field name. * * @param string $fieldName * @param string $value * @return string $value */ private function prepareWhereValue(&$fieldName, $value) { if (strpos($fieldName, '.') !== false) { $e = explode('.', $fieldName); $mapping = $this->class->getFieldMapping($e[0]); if ($this->class->hasField($e[0])) { $name = $this->class->fieldMappings[$e[0]]['name']; if ($name !== $e[0]) { $e[0] = $name; } } if (isset($mapping['targetDocument'])) { $targetClass = $this->dm->getClassMetadata($mapping['targetDocument']); if ($targetClass->hasField($e[1]) && $targetClass->identifier === $e[1]) { $fieldName = $e[0] . '.$id'; $value = $targetClass->getDatabaseIdentifierValue($value); } elseif ($e[1] === '$id') { $value = $targetClass->getDatabaseIdentifierValue($value); } } } elseif ($this->class->hasField($fieldName) && ! $this->class->isIdentifier($fieldName)) { $name = $this->class->fieldMappings[$fieldName]['name']; if ($name !== $fieldName) { $fieldName = $name; } } else { if ($fieldName === $this->class->identifier || $fieldName === '_id') { $fieldName = '_id'; if (is_array($value)) { if (isset($value[$this->cmd.'in'])) { foreach ($value[$this->cmd.'in'] as $k => $v) { $value[$this->cmd.'in'][$k] = $this->class->getDatabaseIdentifierValue($v); } } else { foreach ($value as $k => $v) { $value[$k] = $this->class->getDatabaseIdentifierValue($v); } } } else { $value = $this->class->getDatabaseIdentifierValue($value); } } } return $value; }
/** * Return the document field mapping for a property path. * * @param ClassMetadata $metadata * @param object $document * @param string $path * @return array * @throw ConstraintDefinitionException if no field mapping exists for the property path */ private function getFieldMappingForPropertyPath(ClassMetadata $metadata, $document, $path) { // Extract the first part of the property path before any dot separator $fieldName = false !== ($beforeDot = strstr($path, '.', true)) ? $beforeDot : $path; if (!$metadata->hasField($fieldName)) { throw new ConstraintDefinitionException(sprintf('Mapping for "%s" does not exist for "%s"', $path, $metadata->name)); } return $metadata->getFieldMapping($fieldName); }
/** * Checks if $field type is valid * * @param \Doctrine\ODM\MongoDB\Mapping\ClassMetadata $meta * @param string $field * * @return boolean */ protected function isValidField($meta, $field) { $mapping = $meta->getFieldMapping($field); return $mapping && in_array($mapping['type'], $this->validTypes); }
/** * Prime references within a mapped field of one or more documents. * * If a $primer callable is provided, it should have the same signature as * the default primer defined in the constructor. If $primer is not * callable, the default primer will be used. * * @param ClassMetadata $class Class metadata for the document * @param array|\Traversable $documents Documents containing references to prime * @param string $fieldName Field name containing references to prime * @param array $hints UnitOfWork hints for priming queries * @param callable $primer Optional primer callable * @throws \InvalidArgumentException If the mapped field is not the owning * side of a reference relationship. * @throws \InvalidArgumentException If $primer is not callable * @throws \LogicException If the mapped field is a simple reference and is * missing a target document class. */ public function primeReferences(ClassMetadata $class, $documents, $fieldName, array $hints = array(), $primer = null) { $mapping = $class->getFieldMapping($fieldName); /* Inverse-side references would need to be populated before we can * collect references to be primed. This is not supported. */ if (!isset($mapping['reference']) || !$mapping['isOwningSide']) { throw new \InvalidArgumentException(sprintf('Field "%s" is not the owning side of a reference relationship in class "%s"', $fieldName, $class->name)); } /* Simple reference require a target document class so we can construct * the priming query. */ if (!empty($mapping['simple']) && empty($mapping['targetDocument'])) { throw new \LogicException(sprintf('Field "%s" is a simple reference without a target document class in class "%s"', $fieldName, $class->name)); } if ($primer !== null && !is_callable($primer)) { throw new \InvalidArgumentException('$primer is not callable'); } $primer = $primer ?: $this->defaultPrimer; $groupedIds = array(); foreach ($documents as $document) { $fieldValue = $class->getFieldValue($document, $fieldName); /* The field will need to be either a Proxy (reference-one) or * PersistentCollection (reference-many) in order to prime anything. */ if (!is_object($fieldValue)) { continue; } if ($mapping['type'] === 'one' && $fieldValue instanceof Proxy && !$fieldValue->__isInitialized()) { $refClass = $this->dm->getClassMetadata(get_class($fieldValue)); $id = $this->uow->getDocumentIdentifier($fieldValue); $groupedIds[$refClass->name][serialize($id)] = $id; } elseif ($mapping['type'] == 'many' && $fieldValue instanceof PersistentCollection) { $this->addManyReferences($fieldValue, $groupedIds); } } foreach ($groupedIds as $className => $ids) { $refClass = $this->dm->getClassMetadata($className); call_user_func($primer, $this->dm, $refClass, array_values($ids), $hints); } }
private function prepareIndexes(ClassMetadata $class) { $indexes = $class->getIndexes(); $newIndexes = array(); foreach ($indexes as $index) { $newIndex = array('keys' => array(), 'options' => $index['options']); foreach ($index['keys'] as $key => $value) { $mapping = $class->getFieldMapping($key); $newIndex['keys'][$mapping['name']] = $value; } $newIndexes[] = $newIndex; } return $newIndexes; }
/** * @param ClassMetadata $class * @return array */ private function prepareIndexes(ClassMetadata $class) { $persister = $this->dm->getUnitOfWork()->getDocumentPersister($class->name); $indexes = $class->getIndexes(); $newIndexes = array(); foreach ($indexes as $index) { $newIndex = array('keys' => array(), 'options' => $index['options']); foreach ($index['keys'] as $key => $value) { $key = $persister->prepareFieldName($key); if ($class->hasField($key)) { $mapping = $class->getFieldMapping($key); $newIndex['keys'][$mapping['name']] = $value; } else { $newIndex['keys'][$key] = $value; } } $newIndexes[] = $newIndex; } return $newIndexes; }