/** * Initializes a new instance of the <tt>ProxyFactory</tt> class that is * connected to the given <tt>DocumentManager</tt>. * * @param \CosmoW\ODM\Riak\DocumentManager $documentManager The DocumentManager the new factory works for. * @param string $proxyDir The directory to use for the proxy classes. It * must exist. * @param string $proxyNamespace The namespace to use for the proxy classes. * @param integer $autoGenerate Whether to automatically generate proxy classes. */ public function __construct(DocumentManager $documentManager, $proxyDir, $proxyNamespace, $autoGenerate = AbstractProxyFactory::AUTOGENERATE_NEVER) { $this->metadataFactory = $documentManager->getMetadataFactory(); $this->uow = $documentManager->getUnitOfWork(); $this->proxyNamespace = $proxyNamespace; $proxyGenerator = new ProxyGenerator($proxyDir, $proxyNamespace); $proxyGenerator->setPlaceholder('baseProxyInterface', 'CosmoW\\ODM\\Riak\\Proxy\\Proxy'); parent::__construct($proxyGenerator, $this->metadataFactory, $autoGenerate); }
/** * 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); }