浏览代码

Allow dot-separated filter identifiers.

Romain Geissler 13 年之前
父节点
当前提交
02a329987b
共有 4 个文件被更改,包括 102 次插入20 次删除
  1. 7 5
      Builder/DatagridBuilder.php
  2. 11 1
      Filter/Filter.php
  3. 49 9
      Guesser/FilterTypeGuesser.php
  4. 35 5
      Model/ModelManager.php

+ 7 - 5
Builder/DatagridBuilder.php

@@ -56,17 +56,19 @@ class DatagridBuilder implements DatagridBuilderInterface
         $fieldDescription->setAdmin($admin);
 
         if ($admin->getModelManager()->hasMetadata($admin->getClass())) {
-            $metadata = $admin->getModelManager()->getMetadata($admin->getClass());
+            list($metadata, $lastPropertyName, $parentAssociationMappings) = $admin->getModelManager()->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName());
 
             // set the default field mapping
-            if (isset($metadata->fieldMappings[$fieldDescription->getName()])) {
-                $fieldDescription->setFieldMapping($metadata->fieldMappings[$fieldDescription->getName()]);
+            if (isset($metadata->fieldMappings[$lastPropertyName])) {
+                $fieldDescription->setFieldMapping($metadata->fieldMappings[$lastPropertyName]);
             }
 
             // set the default association mapping
-            if (isset($metadata->associationMappings[$fieldDescription->getName()])) {
-                $fieldDescription->setAssociationMapping($metadata->associationMappings[$fieldDescription->getName()]);
+            if (isset($metadata->associationMappings[$lastPropertyName])) {
+                $fieldDescription->setAssociationMapping($metadata->associationMappings[$lastPropertyName]);
             }
+
+            $fieldDescription->setOption('parent_association_mappings', $fieldDescription->getOption('parent_association_mappings', $parentAssociationMappings));
         }
 
         $fieldDescription->setOption('code', $fieldDescription->getOption('code', $fieldDescription->getName()));

+ 11 - 1
Filter/Filter.php

@@ -29,7 +29,17 @@ abstract class Filter extends BaseFilter
 
     protected function association($queryBuilder, $value)
     {
-        return array($this->getOption('alias', $queryBuilder->getRootAlias()), $this->getFieldName());
+        $parentAssociationMappings = $this->getParentAssociationMappings();
+        $alias = $this->getOption('alias', $queryBuilder->getRootAlias());
+        $newAlias = 's_'.$alias;
+
+        foreach($parentAssociationMappings as $parentAssociationMapping){
+            $newAlias .= '_'.$parentAssociationMapping['fieldName'];
+            $queryBuilder->leftJoin(sprintf('%s.%s', $alias, $parentAssociationMapping['fieldName']), $newAlias);
+            $alias = $newAlias;
+        }
+
+        return array($alias, $this->getFieldName());
     }
 
     protected function applyWhere($queryBuilder, $parameter)

+ 49 - 9
Guesser/FilterTypeGuesser.php

@@ -37,7 +37,7 @@ class FilterTypeGuesser implements TypeGuesserInterface
      */
     public function guessType($class, $property)
     {
-        if (!$ret = $this->getMetadata($class)) {
+        if (!$ret = $this->getParentMetadataForProperty($class, $property)) {
             return false;
         }
 
@@ -47,11 +47,13 @@ class FilterTypeGuesser implements TypeGuesserInterface
             'options'        => array(),
         );
 
-        list($metadata, $name) = $ret;
+        list($metadata, $propertyName, $parentAssociationMappings) = $ret;
 
-        if ($metadata->hasAssociation($property)) {
-            $multiple = $metadata->isCollectionValuedAssociation($property);
-            $mapping = $metadata->getAssociationMapping($property);
+        $options['parent_association_mappings'] = $parentAssociationMappings;
+
+        if ($metadata->hasAssociation($propertyName)) {
+            $multiple = $metadata->isCollectionValuedAssociation($propertyName);
+            $mapping = $metadata->getAssociationMapping($propertyName);
 
             switch ($mapping['type']) {
                 case ClassMetadataInfo::ONE_TO_ONE:
@@ -66,6 +68,7 @@ class FilterTypeGuesser implements TypeGuesserInterface
                     $options['field_options'] = array(
                         'class' => $mapping['targetEntity']
                     );
+
                     $options['field_name'] = $mapping['fieldName'];
                     $options['mapping_type'] = $mapping['type'];
 
@@ -73,9 +76,9 @@ class FilterTypeGuesser implements TypeGuesserInterface
             }
         }
 
-        $options['field_name'] = $metadata->fieldMappings[$property]['fieldName'];
+        $options['field_name'] = $metadata->fieldMappings[$propertyName]['fieldName'];
 
-        switch ($metadata->getTypeOfField($property)) {
+        switch ($metadata->getTypeOfField($propertyName)) {
             case 'boolean':
                 $options['field_type'] = 'sonata_type_boolean';
                 $options['field_options'] = array();
@@ -118,12 +121,49 @@ class FilterTypeGuesser implements TypeGuesserInterface
         }
 
         $this->cache[$class] = null;
-        foreach ($this->registry->getEntityManagers() as $name => $em) {
+        foreach ($this->registry->getEntityManagers() as $em) {
             try {
-                return $this->cache[$class] = array($em->getClassMetadata($class), $name);
+                return $this->cache[$class] = $em->getClassMetadata($class);
             } catch (MappingException $e) {
                 // not an entity or mapped super class
             }
         }
     }
+
+    protected function getParentMetadataForProperty($baseClass, $propertyFullName)
+    {
+        $nameElements = explode('.', $propertyFullName);
+        $lastPropertyName = array_pop($nameElements);
+        $class = $baseClass;
+        $parentAssociationMappings = array();
+
+        foreach($nameElements as $nameElement){
+            if (!$metadata = $this->getMetadata($class)) {
+                return null;
+            }
+
+            $class = $metadata->associationMappings[$nameElement]['targetEntity'];
+
+            if (!$metadata->hasAssociation($nameElement)) {
+                return null;
+            }
+
+            $mapping = $metadata->getAssociationMapping($nameElement);
+
+            switch ($mapping['type']) {
+                case ClassMetadataInfo::ONE_TO_ONE:
+                case ClassMetadataInfo::ONE_TO_MANY:
+                case ClassMetadataInfo::MANY_TO_ONE:
+                case ClassMetadataInfo::MANY_TO_MANY:
+                    $parentAssociationMappings[] = $mapping;
+
+                    break;
+
+                default:
+                    return null;
+            }
+        }
+
+        return array($this->getMetadata($class), $lastPropertyName, $parentAssociationMappings);
+    }
 }

+ 35 - 5
Model/ModelManager.php

@@ -53,6 +53,36 @@ class ModelManager implements ModelManagerInterface
         return $this->getEntityManager($class)->getMetadataFactory()->getMetadataFor($class);
     }
 
+
+    /**
+     * Returns the model's metadata holding the fully qualified property, and the last
+     * property name
+     *
+     * @param string $baseClass The base class of the model holding the fully qualified property.
+     * @param string $propertyFullName The name of the fully qualified property (dot ('.') separated
+     * property string)
+     * @return array(
+     *     \Doctrine\ORM\Mapping\ClassMetadata $parentMetadata,
+     *     string $lastPropertyName,
+     *     array $parentAssociationMappings
+     * )
+     */
+    public function getParentMetadataForProperty($baseClass, $propertyFullName)
+    {
+        $nameElements = explode('.', $propertyFullName);
+        $lastPropertyName = array_pop($nameElements);
+        $class = $baseClass;
+        $parentAssociationMappings = array();
+
+        foreach($nameElements as $nameElement){
+            $metadata = $this->getMetadata($class);
+            $parentAssociationMappings[] = $metadata->associationMappings[$nameElement];
+            $class = $metadata->getAssociationTargetClass($nameElement);
+        }
+
+        return array($this->getMetadata($class), $lastPropertyName, $parentAssociationMappings);
+    }
+
     /**
      * Returns true is the model has some metadata
      *
@@ -79,18 +109,18 @@ class ModelManager implements ModelManagerInterface
             throw new \RunTimeException('The name argument must be a string');
         }
 
-        $metadata = $this->getMetadata($class);
+        list($metadata, $propertyName, $parentAssociationMappings) = $this->getParentMetadataForProperty($class, $name);
 
         $fieldDescription = new FieldDescription;
         $fieldDescription->setName($name);
         $fieldDescription->setOptions($options);
 
-        if (isset($metadata->associationMappings[$name])) {
-            $fieldDescription->setAssociationMapping($metadata->associationMappings[$name]);
+        if (isset($metadata->associationMappings[$propertyName])) {
+            $fieldDescription->setAssociationMapping($metadata->associationMappings[$propertyName]);
         }
 
-        if (isset($metadata->fieldMappings[$name])) {
-            $fieldDescription->setFieldMapping($metadata->fieldMappings[$name]);
+        if (isset($metadata->fieldMappings[$propertyName])) {
+            $fieldDescription->setFieldMapping($metadata->fieldMappings[$propertyName]);
         }
 
         return $fieldDescription;