NativeQueryBuilder::andWhere()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
/**
4
 * This file is part of the Kdyby (http://www.kdyby.org)
5
 *
6
 * Copyright (c) 2008 Filip Procházka ([email protected])
7
 *
8
 * For the full copyright and license information, please view the file license.txt that was distributed with this source code.
9
 */
10
11
namespace Kdyby\Doctrine;
12
13
use Doctrine;
14
use Kdyby;
15
use Nette;
16
17
18
19
/**
20
 * @author Filip Procházka <[email protected]>
21
 *
22
 * @method NativeQueryBuilder setParameter($key, $value, $type = null)
23
 * @method NativeQueryBuilder setParameters(array $params, array $types = [])
24
 * @method NativeQueryBuilder setFirstResult($firstResult)
25
 * @method NativeQueryBuilder setMaxResults($maxResults)
26
 * @method NativeQueryBuilder select($select = NULL)
27
 * @method NativeQueryBuilder addSelect($select = NULL)
28
 * @method NativeQueryBuilder delete($delete = null, $alias = null)
29
 * @method NativeQueryBuilder update($update = null, $alias = null)
30
 * @method NativeQueryBuilder groupBy($groupBy)
31
 * @method NativeQueryBuilder addGroupBy($groupBy)
32
 * @method NativeQueryBuilder having($having)
33
 * @method NativeQueryBuilder andHaving($having)
34
 * @method NativeQueryBuilder orHaving($having)
35
 * @method NativeQueryBuilder orderBy($sort, $order = null)
36
 * @method NativeQueryBuilder addOrderBy($sort, $order = null)
37
 */
38
class NativeQueryBuilder extends Doctrine\DBAL\Query\QueryBuilder
39
{
40
41
	use \Kdyby\StrictObjects\Scream;
42
43
	/**
44
	 * @var Mapping\ResultSetMappingBuilder
45
	 */
46
	private $rsm;
47
48
	/**
49
	 * @var Doctrine\ORM\EntityManager
50
	 */
51
	private $em;
52
53
	/**
54
	 * @var int
55
	 */
56
	private $defaultRenameMode = Doctrine\ORM\Query\ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT;
57
58
59
60
	public function __construct(Doctrine\ORM\EntityManager $em)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
61
	{
62
		parent::__construct($em->getConnection());
63
		$this->em = $em;
64
	}
65
66
67
68
	/**
69
	 * @return NativeQueryWrapper
70
	 */
71
	public function getQuery()
72
	{
73
		$query = new Doctrine\ORM\NativeQuery($this->em);
74
		$query->setResultSetMapping($this->getResultSetMapper());
75
		$query->setParameters($this->getParameters());
76
77
		$wrapped = new NativeQueryWrapper($query);
78
		$wrapped->setFirstResult($this->getFirstResult());
79
		$wrapped->setMaxResults($this->getMaxResults());
80
81
		$hasSelect = (bool)$this->getQueryPart('select');
82
		if (!$hasSelect && $this->getType() === self::SELECT) {
83
			$select = $this->getResultSetMapper()->generateSelectClause();
84
			$this->select($select ?: '*');
85
		}
86
87
		$query->setSQL($this->getSQL());
88
89
		$this->setFirstResult($wrapped->getFirstResult());
90
		$this->setMaxResults($wrapped->getMaxResults());
91
92
		if (!$hasSelect && $this->getType() === self::SELECT) {
93
			$this->resetQueryPart('select');
94
		}
95
96
		$rsm = $this->getResultSetMapper();
97
		if (empty($rsm->fieldMappings) && empty($rsm->scalarMappings)) {
98
			throw new InvalidStateException("No field or columns mapping found, please configure the ResultSetMapper and some fields.");
99
		}
100
101
		return $wrapped;
102
	}
103
104
105
106
	/**
107
	 * @param int $defaultRenameMode
108
	 * @return NativeQueryBuilder
109
	 */
110
	public function setDefaultRenameMode($defaultRenameMode)
111
	{
112
		if ($this->rsm !== NULL) {
113
			throw new InvalidStateException("It's too late for changing rename mode for ResultSetMappingBuilder, it has already been created. Call this method earlier.");
114
		}
115
116
		$this->defaultRenameMode = $defaultRenameMode;
117
		return $this;
118
	}
119
120
121
122
	public function getResultSetMapper()
123
	{
124
		if ($this->rsm === NULL) {
125
			$this->rsm = new Mapping\ResultSetMappingBuilder($this->em, $this->defaultRenameMode);
126
		}
127
128
		return $this->rsm;
129
	}
130
131
132
133
	/**
134
	 * @param string $tableAlias
135
	 * @param string|array $columns
136
	 * @return NativeQueryBuilder
137
	 */
138
	public function addColumn($tableAlias, $columns)
139
	{
140
		$rsm = $this->getResultSetMapper();
141
142
		$args = func_get_args();
143
		array_shift($args); // shit tableAlias
144
145
		$class = $this->em->getClassMetadata($rsm->aliasMap[$tableAlias]);
146
147
		foreach (is_array($columns) ? $columns : $args as $column) {
148
			try {
149
				$field = $class->getFieldForColumn($column);
150
				if ($class->hasField($field)) {
151
					$type = $class->getTypeOfField($field);
152
153
				} else {
154
					$type = $class->hasAssociation($field) ? 'integer' : 'string';
155
				}
156
157
			} catch (Doctrine\ORM\Mapping\MappingException $e) {
158
				$type = 'string';
159
160
				if ($class->discriminatorColumn['fieldName'] === $column) {
161
					$type = $class->discriminatorColumn['type'];
162
				}
163
			}
164
165
			$this->addSelect("{$tableAlias}.{$column} as {$tableAlias}_{$column}");
166
			$rsm->addScalarResult("{$tableAlias}_{$column}", "{$tableAlias}_{$column}", $type);
167
		}
168
169
		return $this;
170
	}
171
172
173
174
	public function addSelect($select = NULL)
175
	{
176
		$selects = is_array($select) ? $select : func_get_args();
177
		foreach ($selects as &$arg) {
178
			if ($arg instanceof Doctrine\DBAL\Query\QueryBuilder) {
179
				$arg = '(' . $arg->getSQL() . ')';
180
			}
181
		}
182
183
		return parent::addSelect($selects);
184
	}
185
186
187
188
	/**
189
	 * {@inheritdoc}
190
	 */
191
	public function from($from, $alias = NULL)
192
	{
193
		return parent::from($this->addTableResultMapping($from, $alias), $alias);
194
	}
195
196
197
198
	/**
199
	 * {@inheritdoc}
200
	 * @return NativeQueryBuilder
201
	 */
202
	public function join($fromAlias, $join, $alias, $condition = null)
203
	{
204
		return call_user_func_array([$this, 'innerJoin'], func_get_args());
205
	}
206
207
208
209
	/**
210
	 * {@inheritdoc}
211
	 * @return NativeQueryBuilder
212
	 */
213
	public function innerJoin($fromAlias, $join, $alias, $condition = null)
214
	{
215
		if ($condition !== NULL) {
216
			list($condition) = array_values(Helpers::separateParameters($this, array_slice(func_get_args(), 3)));
217
		}
218
219
		return parent::innerJoin($fromAlias, $this->addTableResultMapping($join, $alias, $fromAlias), $alias, $condition);
220
	}
221
222
223
224
	/**
225
	 * {@inheritdoc}
226
	 * @return NativeQueryBuilder
227
	 */
228
	public function leftJoin($fromAlias, $join, $alias, $condition = null)
229
	{
230
		if ($condition !== NULL) {
231
			list($condition) = array_values(Helpers::separateParameters($this, array_slice(func_get_args(), 3)));
232
		}
233
234
		return parent::leftJoin($fromAlias, $this->addTableResultMapping($join, $alias, $fromAlias), $alias, $condition);
235
	}
236
237
238
239
	/**
240
	 * {@inheritdoc}
241
	 * @return NativeQueryBuilder
242
	 */
243
	public function rightJoin($fromAlias, $join, $alias, $condition = null)
244
	{
245
		if ($condition !== NULL) {
246
			list($condition) = array_values(Helpers::separateParameters($this, array_slice(func_get_args(), 3)));
247
		}
248
249
		return parent::leftJoin($fromAlias, $this->addTableResultMapping($join, $alias, $fromAlias), $alias, $condition);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (leftJoin() instead of rightJoin()). Are you sure this is correct? If so, you might want to change this to $this->leftJoin().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
250
	}
251
252
253
254
	/**
255
	 * @param string $table
256
	 * @param string|null $alias
257
	 * @param string $joinedFrom
258
	 * @throws \Doctrine\ORM\Mapping\MappingException
259
	 * @return string
260
	 */
261
	protected function addTableResultMapping($table, $alias, $joinedFrom = NULL)
262
	{
263
		$rsm = $this->getResultSetMapper();
264
		$class = $relation = NULL;
265
266
		if (substr_count($table, '\\')) {
267
			$class = $this->em->getClassMetadata($table);
268
			$table = $class->getTableName();
269
270
		} elseif (isset($rsm->aliasMap[$joinedFrom])) {
271
			$fromClass = $this->em->getClassMetadata($rsm->aliasMap[$joinedFrom]);
272
273
			foreach (array_merge([$fromClass->getName()], $fromClass->subClasses) as $fromClass) {
274
				$fromClass = $this->em->getClassMetadata($fromClass);
275
276
				if ($fromClass->hasAssociation($table)) {
277
					$class = $this->em->getClassMetadata($fromClass->getAssociationTargetClass($table));
278
					$relation = $fromClass->getAssociationMapping($table);
279
					$table = $class->getTableName();
280
					break;
281
282
				} else {
283
					foreach ($fromClass->getAssociationMappings() as $mapping) {
284
						$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
285
						if ($targetClass->getTableName() === $table) {
286
							$class = $targetClass;
287
							$relation = $mapping;
288
							$table = $class->getTableName();
289
							break 2;
290
						}
291
					}
292
				}
293
			}
294
295
		} else {
296
			/** @var Kdyby\Doctrine\Mapping\ClassMetadata $class */
297
			foreach ($this->em->getMetadataFactory()->getAllMetadata() as $class) {
298
				if ($class->getTableName() === $table) {
299
					break;
300
				}
301
			}
302
		}
303
304
		if (!$class instanceof Doctrine\ORM\Mapping\ClassMetadata || $class->getTableName() !== $table) {
305
			return $table;
306
		}
307
308
		if ($alias === NULL && ($joinedFrom === NULL || $relation !== NULL)) {
309
			throw new InvalidArgumentException('Parameter alias is required');
310
		}
311
312
		if ($joinedFrom === NULL) {
313
			$rsm->addEntityResult($class->getName(), $alias);
314
315
		} elseif ($relation !== NULL) {
316
			$rsm->addJoinedEntityResult($class->getName(), $alias, $joinedFrom, $relation);
317
		}
318
319
		return $class->getTableName();
320
	}
321
322
323
324
	/**
325
	 * {@inheritdoc}
326
	 * @return NativeQueryBuilder
327
	 */
328
	public function where($predicates)
329
	{
330
		return call_user_func_array('parent::where', Helpers::separateParameters($this, func_get_args()));
331
	}
332
333
334
335
	/**
336
	 * {@inheritdoc}
337
	 * @return NativeQueryBuilder
338
	 */
339
	public function andWhere($where)
340
	{
341
		return call_user_func_array('parent::andWhere', Helpers::separateParameters($this, func_get_args()));
342
	}
343
344
345
346
	/**
347
	 * {@inheritdoc}
348
	 * @return NativeQueryBuilder
349
	 */
350
	public function orWhere($where)
351
	{
352
		return call_user_func_array('parent::orWhere', Helpers::separateParameters($this, func_get_args()));
353
	}
354
355
}
356