3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the MIT license. For more information, see
17 * <http://www.doctrine-project.org>.
20 namespace Doctrine\ORM\Query;
22 use Doctrine\ORM\EntityManager;
23 use Doctrine\ORM\Mapping\ClassMetadataInfo;
26 * A ResultSetMappingBuilder uses the EntityManager to automatically populate entity fields
28 * @author Michael Ridgway <mcridgway@gmail.com>
31 class ResultSetMappingBuilder extends ResultSetMapping
39 * @param EntityManager
41 public function __construct(EntityManager $em)
47 * Adds a root entity and all of its fields to the result set.
49 * @param string $class The class name of the root entity.
50 * @param string $alias The unique alias to use for the root entity.
51 * @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName)
53 public function addRootEntityFromClassMetadata($class, $alias, $renamedColumns = array())
55 $this->addEntityResult($class, $alias);
56 $this->addAllClassFields($class, $alias, $renamedColumns);
60 * Adds a joined entity and all of its fields to the result set.
62 * @param string $class The class name of the joined entity.
63 * @param string $alias The unique alias to use for the joined entity.
64 * @param string $parentAlias The alias of the entity result that is the parent of this joined result.
65 * @param object $relation The association field that connects the parent entity result with the joined entity result.
66 * @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName)
68 public function addJoinedEntityFromClassMetadata($class, $alias, $parentAlias, $relation, $renamedColumns = array())
70 $this->addJoinedEntityResult($class, $alias, $parentAlias, $relation);
71 $this->addAllClassFields($class, $alias, $renamedColumns);
75 * Adds all fields of the given class to the result set mapping (columns and meta fields)
77 protected function addAllClassFields($class, $alias, $renamedColumns = array())
79 $classMetadata = $this->em->getClassMetadata($class);
80 if ($classMetadata->isInheritanceTypeSingleTable() || $classMetadata->isInheritanceTypeJoined()) {
81 throw new \InvalidArgumentException('ResultSetMapping builder does not currently support inheritance.');
83 $platform = $this->em->getConnection()->getDatabasePlatform();
84 foreach ($classMetadata->getColumnNames() as $columnName) {
85 $propertyName = $classMetadata->getFieldName($columnName);
86 if (isset($renamedColumns[$columnName])) {
87 $columnName = $renamedColumns[$columnName];
89 $columnName = $platform->getSQLResultCasing($columnName);
90 if (isset($this->fieldMappings[$columnName])) {
91 throw new \InvalidArgumentException("The column '$columnName' conflicts with another column in the mapper.");
93 $this->addFieldResult($alias, $columnName, $propertyName);
95 foreach ($classMetadata->associationMappings as $associationMapping) {
96 if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
97 foreach ($associationMapping['joinColumns'] as $joinColumn) {
98 $columnName = $joinColumn['name'];
99 $renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName;
100 $renamedColumnName = $platform->getSQLResultCasing($renamedColumnName);
101 if (isset($this->metaMappings[$renamedColumnName])) {
102 throw new \InvalidArgumentException("The column '$renamedColumnName' conflicts with another column in the mapper.");
104 $this->addMetaResult($alias, $renamedColumnName, $columnName);
112 * Adds the mappings of the results of native SQL queries to the result set.
114 * @param ClassMetadataInfo $class
115 * @param array $queryMapping
116 * @return ResultSetMappingBuilder
118 public function addNamedNativeQueryMapping(ClassMetadataInfo $class, array $queryMapping)
120 if (isset($queryMapping['resultClass'])) {
121 return $this->addNamedNativeQueryResultClassMapping($class, $queryMapping['resultClass']);
124 return $this->addNamedNativeQueryResultSetMapping($class, $queryMapping['resultSetMapping']);
128 * Adds the class mapping of the results of native SQL queries to the result set.
130 * @param ClassMetadataInfo $class
131 * @param string $resultClassName
132 * @return ResultSetMappingBuilder
134 public function addNamedNativeQueryResultClassMapping(ClassMetadataInfo $class, $resultClassName)
137 $classMetadata = $this->em->getClassMetadata($resultClassName);
138 $shortName = $classMetadata->reflClass->getShortName();
139 $alias = strtolower($shortName[0]).'0';
141 $this->addEntityResult($class->name, $alias);
143 if ($classMetadata->discriminatorColumn) {
144 $discriminatorColumn = $classMetadata->discriminatorColumn;
145 $this->setDiscriminatorColumn($alias, $discriminatorColumn['name']);
146 $this->addMetaResult($alias, $discriminatorColumn['name'], $discriminatorColumn['fieldName']);
149 foreach ($classMetadata->getColumnNames() as $key => $columnName) {
150 $propertyName = $classMetadata->getFieldName($columnName);
151 $this->addFieldResult($alias, $columnName, $propertyName);
154 foreach ($classMetadata->associationMappings as $associationMapping) {
155 if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
156 foreach ($associationMapping['joinColumns'] as $joinColumn) {
157 $columnName = $joinColumn['name'];
158 $this->addMetaResult($alias, $columnName, $columnName, $classMetadata->isIdentifier($columnName));
167 * Adds the result set mapping of the results of native SQL queries to the result set.
169 * @param ClassMetadataInfo $class
170 * @param string $resultSetMappingName
171 * @return ResultSetMappingBuilder
173 public function addNamedNativeQueryResultSetMapping(ClassMetadataInfo $class, $resultSetMappingName)
176 $resultMapping = $class->getSqlResultSetMapping($resultSetMappingName);
177 $rooShortName = $class->reflClass->getShortName();
178 $rootAlias = strtolower($rooShortName[0]) . $counter;
181 if (isset($resultMapping['entities'])) {
182 foreach ($resultMapping['entities'] as $key => $entityMapping) {
183 $classMetadata = $this->em->getClassMetadata($entityMapping['entityClass']);
185 if ($class->reflClass->name == $classMetadata->reflClass->name) {
186 $this->addEntityResult($classMetadata->name, $rootAlias);
187 $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $rootAlias);
189 $shortName = $classMetadata->reflClass->getShortName();
190 $joinAlias = strtolower($shortName[0]) . ++ $counter;
191 $associations = $class->getAssociationsByTargetClass($classMetadata->name);
193 foreach ($associations as $relation => $mapping) {
194 $this->addJoinedEntityResult($mapping['targetEntity'], $joinAlias, $rootAlias, $relation);
195 $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $joinAlias);
202 if (isset($resultMapping['columns'])) {
203 foreach ($resultMapping['columns'] as $entityMapping) {
204 $this->addScalarResult($entityMapping['name'], $entityMapping['name']);
212 * Adds the entity result mapping of the results of native SQL queries to the result set.
214 * @param ClassMetadataInfo $classMetadata
215 * @param array $entityMapping
216 * @param string $alias
217 * @return ResultSetMappingBuilder
219 public function addNamedNativeQueryEntityResultMapping(ClassMetadataInfo $classMetadata, array $entityMapping, $alias)
221 if (isset($entityMapping['discriminatorColumn']) && $entityMapping['discriminatorColumn']) {
222 $discriminatorColumn = $entityMapping['discriminatorColumn'];
223 $this->setDiscriminatorColumn($alias, $discriminatorColumn);
224 $this->addMetaResult($alias, $discriminatorColumn, $discriminatorColumn);
227 if (isset($entityMapping['fields']) && !empty($entityMapping['fields'])) {
228 foreach ($entityMapping['fields'] as $field) {
229 $fieldName = $field['name'];
232 if(strpos($fieldName, '.')){
233 list($relation, $fieldName) = explode('.', $fieldName);
236 if (isset($classMetadata->associationMappings[$relation])) {
238 $associationMapping = $classMetadata->associationMappings[$relation];
239 $joinAlias = $alias.$relation;
240 $parentAlias = $alias;
242 $this->addJoinedEntityResult($associationMapping['targetEntity'], $joinAlias, $parentAlias, $relation);
243 $this->addFieldResult($joinAlias, $field['column'], $fieldName);
245 $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name);
248 if(!isset($classMetadata->fieldMappings[$fieldName])) {
249 throw new \InvalidArgumentException("Entity '".$classMetadata->name."' has no field '".$fieldName."'. ");
251 $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name);
256 foreach ($classMetadata->getColumnNames() as $columnName) {
257 $propertyName = $classMetadata->getFieldName($columnName);
258 $this->addFieldResult($alias, $columnName, $propertyName);