Exemplo n.º 1
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
         // We can't have expressions in empty() with PHP < 5.5, so store it in a variable
         $arrayValue = (array) $value;
         if (empty($mapping['reference']) || empty($mapping['simple']) || empty($arrayValue)) {
             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);
 }
 /**
  * {@inheritdoc}
  */
 public function add($value)
 {
     /* Initialize the collection before calling add() so this append operation
      * uses the appropriate key. Otherwise, we risk overwriting original data
      * when $newObjects are re-added in a later call to initialize().
      */
     if (isset($this->mapping['strategy']) && CollectionHelper::isHash($this->mapping['strategy'])) {
         $this->initialize();
     }
     $this->coll->add($value);
     $this->changed();
     if ($this->uow !== null && $this->isOrphanRemovalEnabled() && $value !== null) {
         $this->uow->unscheduleOrphanRemoval($value);
     }
     return true;
 }
Exemplo n.º 3
0
 private function loadReferenceManyCollectionOwningSide(PersistentCollection $collection)
 {
     $hints = $collection->getHints();
     $mapping = $collection->getMapping();
     $groupedIds = array();
     $sorted = isset($mapping['sort']) && $mapping['sort'];
     foreach ($collection->getMongoData() as $key => $reference) {
         if (isset($mapping['simple']) && $mapping['simple']) {
             $className = $mapping['targetDocument'];
             $mongoId = $reference;
         } else {
             $className = $this->uow->getClassNameForAssociation($mapping, $reference);
             $mongoId = $reference['$id'];
         }
         $id = $this->dm->getClassMetadata($className)->getPHPIdentifierValue($mongoId);
         // create a reference to the class and id
         $reference = $this->dm->getReference($className, $id);
         // no custom sort so add the references right now in the order they are embedded
         if (!$sorted) {
             if (CollectionHelper::isHash($mapping['strategy'])) {
                 $collection->set($key, $reference);
             } else {
                 $collection->add($reference);
             }
         }
         // only query for the referenced object if it is not already initialized or the collection is sorted
         if ($reference instanceof Proxy && !$reference->__isInitialized__ || $sorted) {
             $groupedIds[$className][] = $mongoId;
         }
     }
     foreach ($groupedIds as $className => $ids) {
         $class = $this->dm->getClassMetadata($className);
         $mongoCollection = $this->dm->getDocumentCollection($className);
         $criteria = $this->cm->merge(array('_id' => array('$in' => array_values($ids))), $this->dm->getFilterCollection()->getFilterCriteria($class), isset($mapping['criteria']) ? $mapping['criteria'] : array());
         $criteria = $this->uow->getDocumentPersister($className)->prepareQueryOrNewObj($criteria);
         $cursor = $mongoCollection->find($criteria);
         if (isset($mapping['sort'])) {
             $cursor->sort($mapping['sort']);
         }
         if (isset($mapping['limit'])) {
             $cursor->limit($mapping['limit']);
         }
         if (isset($mapping['skip'])) {
             $cursor->skip($mapping['skip']);
         }
         if (!empty($hints[Query::HINT_SLAVE_OKAY])) {
             $cursor->slaveOkay(true);
         }
         if (!empty($hints[Query::HINT_READ_PREFERENCE])) {
             $cursor->setReadPreference($hints[Query::HINT_READ_PREFERENCE], $hints[Query::HINT_READ_PREFERENCE_TAGS]);
         }
         $documents = $cursor->toArray(false);
         foreach ($documents as $documentData) {
             $document = $this->uow->getById($documentData['_id'], $class);
             $data = $this->hydratorFactory->hydrate($document, $documentData);
             $this->uow->setOriginalDocumentData($document, $data);
             $document->__isInitialized__ = true;
             if ($sorted) {
                 $collection->add($document);
             }
         }
     }
 }