Пример #1
0
 /**
  * Sets a PersistentCollection instance.
  *
  * This method is intended to be used with the "set" or "setArray"
  * strategies. The "setArray" strategy will ensure that the collection is
  * set as a BSON array, which means the collection elements will be
  * reindexed numerically before storage.
  *
  * @param PersistentCollection $coll
  * @param array $options
  */
 private function setCollection(PersistentCollection $coll, array $options)
 {
     list($propertyPath, $parent) = $this->getPathAndParent($coll);
     $coll->initialize();
     $mapping = $coll->getMapping();
     $setData = $this->pb->prepareAssociatedCollectionValue($coll, CollectionHelper::usesSet($mapping['strategy']));
     $query = array('$set' => array($propertyPath => $setData));
     $this->executeQuery($parent, $query, $options);
 }
Пример #2
0
 /**
  * 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 mixed $value
  * @param ClassMetadata $class        Defaults to $this->class
  * @param boolean $prepareValue Whether or not to prepare the value
  * @return array        Prepared field name and value
  */
 private function prepareQueryElement($fieldName, $value = null, $class = null, $prepareValue = true)
 {
     $class = isset($class) ? $class : $this->class;
     // @todo Consider inlining calls to ClassMetadataInfo methods
     // Process all non-identifier fields by translating field names
     if ($class->hasField($fieldName) && !$class->isIdentifier($fieldName)) {
         $mapping = $class->fieldMappings[$fieldName];
         $fieldName = $mapping['name'];
         if (!$prepareValue) {
             return array($fieldName, $value);
         }
         // Prepare mapped, embedded objects
         if (!empty($mapping['embedded']) && is_object($value) && !$this->dm->getMetadataFactory()->isTransient(get_class($value))) {
             return array($fieldName, $this->pb->prepareEmbeddedDocumentValue($mapping, $value));
         }
         // No further preparation unless we're dealing with a simple reference
         if (empty($mapping['reference']) || empty($mapping['simple'])) {
             return array($fieldName, $value);
         }
         // Additional preparation for one or more simple reference values
         $targetClass = $this->dm->getClassMetadata($mapping['targetDocument']);
         if (!is_array($value)) {
             return array($fieldName, $targetClass->getDatabaseIdentifierValue($value));
         }
         // Objects without operators or with DBRef fields can be converted immediately
         if (!$this->hasQueryOperators($value) || $this->hasDBRefFields($value)) {
             return array($fieldName, $targetClass->getDatabaseIdentifierValue($value));
         }
         return array($fieldName, $this->prepareQueryExpression($value, $targetClass));
     }
     // Process identifier fields
     if ($class->hasField($fieldName) && $class->isIdentifier($fieldName) || $fieldName === '_id') {
         $fieldName = '_id';
         if (!$prepareValue) {
             return array($fieldName, $value);
         }
         if (!is_array($value)) {
             return array($fieldName, $class->getDatabaseIdentifierValue($value));
         }
         // Objects without operators or with DBRef fields can be converted immediately
         if (!$this->hasQueryOperators($value) || $this->hasDBRefFields($value)) {
             return array($fieldName, $class->getDatabaseIdentifierValue($value));
         }
         return array($fieldName, $this->prepareQueryExpression($value, $class));
     }
     // No processing for unmapped, non-identifier, non-dotted field names
     if (strpos($fieldName, '.') === false) {
         return array($fieldName, $value);
     }
     /* Process "fieldName.objectProperty" queries (on arrays or objects).
      *
      * We can limit parsing here, since at most three segments are
      * significant: "fieldName.objectProperty" with an optional index or key
      * for collections stored as either BSON arrays or objects.
      */
     $e = explode('.', $fieldName, 4);
     // No further processing for unmapped fields
     if (!isset($class->fieldMappings[$e[0]])) {
         return array($fieldName, $value);
     }
     $mapping = $class->fieldMappings[$e[0]];
     $e[0] = $mapping['name'];
     // Hash and raw fields will not be prepared beyond the field name
     if ($mapping['type'] === Type::HASH || $mapping['type'] === Type::RAW) {
         $fieldName = implode('.', $e);
         return array($fieldName, $value);
     }
     if (isset($mapping['strategy']) && CollectionHelper::isHash($mapping['strategy']) && isset($e[2])) {
         $objectProperty = $e[2];
         $objectPropertyPrefix = $e[1] . '.';
         $nextObjectProperty = implode('.', array_slice($e, 3));
     } elseif ($e[1] != '$') {
         $fieldName = $e[0] . '.' . $e[1];
         $objectProperty = $e[1];
         $objectPropertyPrefix = '';
         $nextObjectProperty = implode('.', array_slice($e, 2));
     } elseif (isset($e[2])) {
         $fieldName = $e[0] . '.' . $e[1] . '.' . $e[2];
         $objectProperty = $e[2];
         $objectPropertyPrefix = $e[1] . '.';
         $nextObjectProperty = implode('.', array_slice($e, 3));
     } else {
         $fieldName = $e[0] . '.' . $e[1];
         return array($fieldName, $value);
     }
     // No further processing for fields without a targetDocument mapping
     if (!isset($mapping['targetDocument'])) {
         if ($nextObjectProperty) {
             $fieldName .= '.' . $nextObjectProperty;
         }
         return array($fieldName, $value);
     }
     $targetClass = $this->dm->getClassMetadata($mapping['targetDocument']);
     // No further processing for unmapped targetDocument fields
     if (!$targetClass->hasField($objectProperty)) {
         if ($nextObjectProperty) {
             $fieldName .= '.' . $nextObjectProperty;
         }
         return array($fieldName, $value);
     }
     $targetMapping = $targetClass->getFieldMapping($objectProperty);
     $objectPropertyIsId = $targetClass->isIdentifier($objectProperty);
     // Prepare DBRef identifiers or the mapped field's property path
     $fieldName = $objectPropertyIsId && !empty($mapping['reference']) && empty($mapping['simple']) ? $e[0] . '.$id' : $e[0] . '.' . $objectPropertyPrefix . $targetMapping['name'];
     // Process targetDocument identifier fields
     if ($objectPropertyIsId) {
         if (!$prepareValue) {
             return array($fieldName, $value);
         }
         if (!is_array($value)) {
             return array($fieldName, $targetClass->getDatabaseIdentifierValue($value));
         }
         // Objects without operators or with DBRef fields can be converted immediately
         if (!$this->hasQueryOperators($value) || $this->hasDBRefFields($value)) {
             return array($fieldName, $targetClass->getDatabaseIdentifierValue($value));
         }
         return array($fieldName, $this->prepareQueryExpression($value, $targetClass));
     }
     /* The property path may include a third field segment, excluding the
      * collection item pointer. If present, this next object property must
      * be processed recursively.
      */
     if ($nextObjectProperty) {
         // Respect the targetDocument's class metadata when recursing
         $nextTargetClass = isset($targetMapping['targetDocument']) ? $this->dm->getClassMetadata($targetMapping['targetDocument']) : null;
         list($key, $value) = $this->prepareQueryElement($nextObjectProperty, $value, $nextTargetClass, $prepareValue);
         $fieldName .= '.' . $key;
     }
     return array($fieldName, $value);
 }