123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- <?php
- /*
- * This file is part of the symfony package.
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- * (c) Jonathan H. Wage <jonwage@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Sonata\DoctrineORMAdminBundle\Datagrid;
- use Doctrine\ORM\QueryBuilder;
- use Doctrine\ORM\Query;
- use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
- /**
- * This class try to unify the query usage with Doctrine
- */
- class ProxyQuery implements ProxyQueryInterface
- {
- protected $queryBuilder;
- protected $sortBy;
- protected $sortOrder;
- protected $parameterUniqueId;
- protected $entityJoinAliases;
- /**
- * @param mixed $queryBuilder
- */
- public function __construct($queryBuilder)
- {
- $this->queryBuilder = $queryBuilder;
- $this->uniqueParameterId = 0;
- $this->entityJoinAliases = array();
- }
- /**
- * {@inheritdoc}
- */
- public function execute(array $params = array(), $hydrationMode = null)
- {
- // always clone the original queryBuilder
- $queryBuilder = clone $this->queryBuilder;
- // todo : check how doctrine behave, potential SQL injection here ...
- if ($this->getSortBy()) {
- $sortBy = $this->getSortBy();
- if (strpos($sortBy, '.') === false) { // add the current alias
- $sortBy = $queryBuilder->getRootAlias() . '.' . $sortBy;
- }
- $queryBuilder->addOrderBy($sortBy, $this->getSortOrder());
- }
- return $this->getFixedQueryBuilder($queryBuilder)->getQuery()->execute($params, $hydrationMode);
- }
- /**
- * This method alters the query to return a clean set of object with a working
- * set of Object
- *
- * @param \Doctrine\ORM\QueryBuilder $queryBuilder
- *
- * @return \Doctrine\ORM\QueryBuilder
- */
- private function getFixedQueryBuilder(QueryBuilder $queryBuilder)
- {
- $queryBuilderId = clone $queryBuilder;
- // step 1 : retrieve the targeted class
- $from = $queryBuilderId->getDQLPart('from');
- $class = $from[0]->getFrom();
- // step 2 : retrieve the column id
- $idName = current($queryBuilderId->getEntityManager()->getMetadataFactory()->getMetadataFor($class)->getIdentifierFieldNames());
- // step 3 : retrieve the different subjects id
- $select = sprintf('%s.%s', $queryBuilderId->getRootAlias(), $idName);
- $queryBuilderId->resetDQLPart('select');
- $queryBuilderId->add('select', 'DISTINCT ' . $select);
- //for SELECT DISTINCT, ORDER BY expressions must appear in select list
- /* Consider
- SELECT DISTINCT x FROM tab ORDER BY y;
- For any particular x-value in the table there might be many different y
- values. Which one will you use to sort that x-value in the output?
- */
- // todo : check how doctrine behave, potential SQL injection here ...
- if ($this->getSortBy()) {
- $sortBy = $this->getSortBy();
- if (strpos($sortBy, '.') === false) { // add the current alias
- $sortBy = $queryBuilderId->getRootAlias() . '.' . $sortBy;
- }
- $sortBy .= ' AS __order_by';
- $queryBuilderId->addSelect($sortBy);
- }
- $results = $queryBuilderId->getQuery()->execute(array(), Query::HYDRATE_ARRAY);
- $idx = array();
- $connection = $queryBuilder->getEntityManager()->getConnection();
- foreach ($results as $id) {
- $idx[] = $connection->quote($id[$idName]);
- }
- // step 4 : alter the query to match the targeted ids
- if (count($idx) > 0) {
- $queryBuilder->andWhere(sprintf('%s IN (%s)', $select, implode(',', $idx)));
- $queryBuilder->setMaxResults(null);
- $queryBuilder->setFirstResult(null);
- }
- return $queryBuilder;
- }
- /**
- * {@inheritdoc}
- */
- public function __call($name, $args)
- {
- return call_user_func_array(array($this->queryBuilder, $name), $args);
- }
- /**
- * {@inheritdoc}
- */
- public function __get($name)
- {
- return $this->queryBuilder->$name;
- }
- /**
- * {@inheritdoc}
- */
- public function setSortBy($parentAssociationMappings, $fieldMapping)
- {
- $alias = $this->entityJoin($parentAssociationMappings);
- $this->sortBy = $alias . '.' . $fieldMapping['fieldName'];
- }
- /**
- * {@inheritdoc}
- */
- public function getSortBy()
- {
- return $this->sortBy;
- }
- /**
- * {@inheritdoc}
- */
- public function setSortOrder($sortOrder)
- {
- $this->sortOrder = $sortOrder;
- }
- /**
- * {@inheritdoc}
- */
- public function getSortOrder()
- {
- return $this->sortOrder;
- }
- /**
- * {@inheritdoc}
- */
- public function getSingleScalarResult()
- {
- $query = $this->queryBuilder->getQuery();
- return $query->getSingleScalarResult();
- }
- /**
- * {@inheritdoc}
- */
- public function __clone()
- {
- $this->queryBuilder = clone $this->queryBuilder;
- }
- /**
- * @return mixed
- */
- public function getQueryBuilder()
- {
- return $this->queryBuilder;
- }
- /**
- * {@inheritdoc}
- */
- public function setFirstResult($firstResult)
- {
- $this->queryBuilder->setFirstResult($firstResult);
- }
- /**
- * {@inheritdoc}
- */
- public function getFirstResult()
- {
- $this->queryBuilder->getFirstResult();
- }
- /**
- * {@inheritdoc}
- */
- public function setMaxResults($maxResults)
- {
- $this->queryBuilder->setMaxResults($maxResults);
- }
- /**
- * {@inheritdoc}
- */
- public function getMaxResults()
- {
- $this->queryBuilder->getMaxResults();
- }
- /**
- * {@inheritdoc}
- */
- public function getUniqueParameterId()
- {
- return $this->uniqueParameterId++;
- }
- /**
- * {@inheritdoc}
- */
- public function entityJoin(array $associationMappings)
- {
- $alias = $this->queryBuilder->getRootAlias();
- $newAlias = 's';
- foreach ($associationMappings as $associationMapping) {
- $newAlias .= '_' . $associationMapping['fieldName'];
- if (!in_array($newAlias, $this->entityJoinAliases)) {
- $this->entityJoinAliases[] = $newAlias;
- $this->queryBuilder->leftJoin(sprintf('%s.%s', $alias, $associationMapping['fieldName']), $newAlias);
- }
- $alias = $newAlias;
- }
- return $alias;
- }
- }
|