Вход Регистрация
Файл: concrete5.7.5.6/concrete/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php
Строк: 783
<?php
/*
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the MIT license. For more information, see
 * <http://www.doctrine-project.org>.
 */

namespace DoctrineORM;

use 
DoctrineCommonUtilClassUtils;
use 
DoctrineCommonCollectionsArrayCollection;

use 
DoctrineDBALTypesType;
use 
DoctrineDBALCacheQueryCacheProfile;

use 
DoctrineORMQueryQueryException;
use 
DoctrineORMORMInvalidArgumentException;

/**
 * Base contract for ORM queries. Base class for Query and NativeQuery.
 *
 * @link    www.doctrine-project.org
 * @since   2.0
 * @author  Benjamin Eberlei <kontakt@beberlei.de>
 * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author  Jonathan Wage <jonwage@gmail.com>
 * @author  Roman Borschel <roman@code-factory.org>
 * @author  Konsta Vesterinen <kvesteri@cc.hut.fi>
 */
abstract class AbstractQuery
{
    
/* Hydration mode constants */

    /**
     * Hydrates an object graph. This is the default behavior.
     */
    
const HYDRATE_OBJECT 1;

    
/**
     * Hydrates an array graph.
     */
    
const HYDRATE_ARRAY 2;

    
/**
     * Hydrates a flat, rectangular result set with scalar values.
     */
    
const HYDRATE_SCALAR 3;

    
/**
     * Hydrates a single scalar value.
     */
    
const HYDRATE_SINGLE_SCALAR 4;

    
/**
     * Very simple object hydrator (optimized for performance).
     */
    
const HYDRATE_SIMPLEOBJECT 5;

    
/**
     * The parameter map of this query.
     *
     * @var DoctrineCommonCollectionsArrayCollection
     */
    
protected $parameters;

    
/**
     * The user-specified ResultSetMapping to use.
     *
     * @var DoctrineORMQueryResultSetMapping
     */
    
protected $_resultSetMapping;

    
/**
     * The entity manager used by this query object.
     *
     * @var DoctrineORMEntityManager
     */
    
protected $_em;

    
/**
     * The map of query hints.
     *
     * @var array
     */
    
protected $_hints = array();

    
/**
     * The hydration mode.
     *
     * @var integer
     */
    
protected $_hydrationMode self::HYDRATE_OBJECT;

    
/**
     * @param DoctrineDBALCacheQueryCacheProfile
     */
    
protected $_queryCacheProfile;

    
/**
     * Whether or not expire the result cache.
     *
     * @var boolean
     */
    
protected $_expireResultCache false;

    
/**
     * @param DoctrineDBALCacheQueryCacheProfile
     */
    
protected $_hydrationCacheProfile;

    
/**
     * Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
     *
     * @param DoctrineORMEntityManager $em
     */
    
public function __construct(EntityManager $em)
    {
        
$this->_em $em;
        
$this->parameters = new ArrayCollection();
    }

    
/**
     * Gets the SQL query that corresponds to this query object.
     * The returned SQL syntax depends on the connection driver that is used
     * by this query object at the time of this method call.
     *
     * @return string SQL query
     */
    
abstract public function getSQL();

    
/**
     * Retrieves the associated EntityManager of this Query instance.
     *
     * @return DoctrineORMEntityManager
     */
    
public function getEntityManager()
    {
        return 
$this->_em;
    }

    
/**
     * Frees the resources used by the query object.
     *
     * Resets Parameters, Parameter Types and Query Hints.
     *
     * @return void
     */
    
public function free()
    {
        
$this->parameters = new ArrayCollection();

        
$this->_hints = array();
    }

    
/**
     * Get all defined parameters.
     *
     * @return DoctrineCommonCollectionsArrayCollection The defined query parameters.
     */
    
public function getParameters()
    {
        return 
$this->parameters;
    }

    
/**
     * Gets a query parameter.
     *
     * @param mixed $key The key (index or name) of the bound parameter.
     *
     * @return mixed The value of the bound parameter.
     */
    
public function getParameter($key)
    {
        
$filteredParameters $this->parameters->filter(
            function (
$parameter) use ($key)
            {
                
// Must not be identical because of string to integer conversion
                
return ($key == $parameter->getName());
            }
        );

        return 
count($filteredParameters) ? $filteredParameters->first() : null;
    }

    
/**
     * Sets a collection of query parameters.
     *
     * @param DoctrineCommonCollectionsArrayCollection|array $parameters
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function setParameters($parameters)
    {
        
// BC compatibility with 2.3-
        
if (is_array($parameters)) {
            
$parameterCollection = new ArrayCollection();

            foreach (
$parameters as $key => $value) {
                
$parameter = new QueryParameter($key$value);

                
$parameterCollection->add($parameter);
            }

            
$parameters $parameterCollection;
        }

        
$this->parameters $parameters;

        return 
$this;
    }

    
/**
     * Sets a query parameter.
     *
     * @param string|int  $key   The parameter position or name.
     * @param mixed       $value The parameter value.
     * @param string|null $type  The parameter type. If specified, the given value will be run through
     *                           the type conversion of this type. This is usually not needed for
     *                           strings and numeric types.
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function setParameter($key$value$type null)
    {
        
$filteredParameters $this->parameters->filter(
            function (
$parameter) use ($key)
            {
                
// Must not be identical because of string to integer conversion
                
return ($key == $parameter->getName());
            }
        );

        if (
count($filteredParameters)) {
            
$parameter $filteredParameters->first();
            
$parameter->setValue($value$type);

            return 
$this;
        }

        
$parameter = new QueryParameter($key$value$type);

        
$this->parameters->add($parameter);

        return 
$this;
    }

    
/**
     * Processes an individual parameter value.
     *
     * @param mixed $value
     *
     * @return array
     *
     * @throws ORMInvalidArgumentException
     */
    
public function processParameterValue($value)
    {
        if (
is_array($value)) {
            foreach (
$value as $key => $paramValue) {
                
$paramValue  $this->processParameterValue($paramValue);
                
$value[$key] = is_array($paramValue) ? reset($paramValue) : $paramValue;
            }

            return 
$value;
        }

        if (
is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
            
$value $this->_em->getUnitOfWork()->getSingleIdentifierValue($value);

            if (
$value === null) {
                throw 
ORMInvalidArgumentException::invalidIdentifierBindingEntity();
            }
        }

        if (
$value instanceof MappingClassMetadata) {
            return 
$value->name;
        }

        return 
$value;
    }

    
/**
     * Sets the ResultSetMapping that should be used for hydration.
     *
     * @param DoctrineORMQueryResultSetMapping $rsm
     *
     * @return DoctrineORMAbstractQuery
     */
    
public function setResultSetMapping(QueryResultSetMapping $rsm)
    {
        
$this->translateNamespaces($rsm);
        
$this->_resultSetMapping $rsm;

        return 
$this;
    }

    
/**
     * Allows to translate entity namespaces to full qualified names.
     *
     * @param QueryResultSetMapping $rsm
     *
     * @return void
     */
    
private function translateNamespaces(QueryResultSetMapping $rsm)
    {
        
$entityManager $this->_em;

        
$translate = function ($alias) use ($entityManager) {
            return 
$entityManager->getClassMetadata($alias)->getName();
        };

        
$rsm->aliasMap array_map($translate$rsm->aliasMap);
        
$rsm->declaringClasses array_map($translate$rsm->declaringClasses);
    }

    
/**
     * Set a cache profile for hydration caching.
     *
     * If no result cache driver is set in the QueryCacheProfile, the default
     * result cache driver is used from the configuration.
     *
     * Important: Hydration caching does NOT register entities in the
     * UnitOfWork when retrieved from the cache. Never use result cached
     * entities for requests that also flush the EntityManager. If you want
     * some form of caching with UnitOfWork registration you should use
     * {@see AbstractQuery::setResultCacheProfile()}.
     *
     * @example
     * $lifetime = 100;
     * $resultKey = "abc";
     * $query->setHydrationCacheProfile(new QueryCacheProfile());
     * $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey));
     *
     * @param DoctrineDBALCacheQueryCacheProfile $profile
     *
     * @return DoctrineORMAbstractQuery
     */
    
public function setHydrationCacheProfile(QueryCacheProfile $profile null)
    {
        if ( ! 
$profile->getResultCacheDriver()) {
            
$resultCacheDriver $this->_em->getConfiguration()->getHydrationCacheImpl();
            
$profile $profile->setResultCacheDriver($resultCacheDriver);
        }

        
$this->_hydrationCacheProfile $profile;

        return 
$this;
    }

    
/**
     * @return DoctrineDBALCacheQueryCacheProfile
     */
    
public function getHydrationCacheProfile()
    {
        return 
$this->_hydrationCacheProfile;
    }

    
/**
     * Set a cache profile for the result cache.
     *
     * If no result cache driver is set in the QueryCacheProfile, the default
     * result cache driver is used from the configuration.
     *
     * @param DoctrineDBALCacheQueryCacheProfile $profile
     *
     * @return DoctrineORMAbstractQuery
     */
    
public function setResultCacheProfile(QueryCacheProfile $profile null)
    {
        if ( ! 
$profile->getResultCacheDriver()) {
            
$resultCacheDriver $this->_em->getConfiguration()->getResultCacheImpl();
            
$profile $profile->setResultCacheDriver($resultCacheDriver);
        }

        
$this->_queryCacheProfile $profile;

        return 
$this;
    }

    
/**
     * Defines a cache driver to be used for caching result sets and implicitly enables caching.
     *
     * @param DoctrineCommonCacheCache|null $resultCacheDriver Cache driver
     *
     * @return DoctrineORMAbstractQuery
     *
     * @throws ORMException
     */
    
public function setResultCacheDriver($resultCacheDriver null)
    {
        if (
$resultCacheDriver !== null && ! ($resultCacheDriver instanceof DoctrineCommonCacheCache)) {
            throw 
ORMException::invalidResultCacheDriver();
        }

        
$this->_queryCacheProfile $this->_queryCacheProfile
            
$this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
            : new 
QueryCacheProfile(0null$resultCacheDriver);

        return 
$this;
    }

    
/**
     * Returns the cache driver used for caching result sets.
     *
     * @deprecated
     *
     * @return DoctrineCommonCacheCache Cache driver
     */
    
public function getResultCacheDriver()
    {
        if (
$this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
            return 
$this->_queryCacheProfile->getResultCacheDriver();
        }

        return 
$this->_em->getConfiguration()->getResultCacheImpl();
    }

    
/**
     * Set whether or not to cache the results of this query and if so, for
     * how long and which ID to use for the cache entry.
     *
     * @param boolean $bool
     * @param integer $lifetime
     * @param string  $resultCacheId
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function useResultCache($bool$lifetime null$resultCacheId null)
    {
        if (
$bool) {
            
$this->setResultCacheLifetime($lifetime);
            
$this->setResultCacheId($resultCacheId);

            return 
$this;
        }

        
$this->_queryCacheProfile null;

        return 
$this;
    }

    
/**
     * Defines how long the result cache will be active before expire.
     *
     * @param integer $lifetime How long the cache entry is valid.
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function setResultCacheLifetime($lifetime)
    {
        
$lifetime = ($lifetime !== null) ? (int) $lifetime 0;

        
$this->_queryCacheProfile $this->_queryCacheProfile
            
$this->_queryCacheProfile->setLifetime($lifetime)
            : new 
QueryCacheProfile($lifetimenull$this->_em->getConfiguration()->getResultCacheImpl());

        return 
$this;
    }

    
/**
     * Retrieves the lifetime of resultset cache.
     *
     * @deprecated
     *
     * @return integer
     */
    
public function getResultCacheLifetime()
    {
        return 
$this->_queryCacheProfile $this->_queryCacheProfile->getLifetime() : 0;
    }

    
/**
     * Defines if the result cache is active or not.
     *
     * @param boolean $expire Whether or not to force resultset cache expiration.
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function expireResultCache($expire true)
    {
        
$this->_expireResultCache $expire;

        return 
$this;
    }

    
/**
     * Retrieves if the resultset cache is active or not.
     *
     * @return boolean
     */
    
public function getExpireResultCache()
    {
        return 
$this->_expireResultCache;
    }

    
/**
     * @return QueryCacheProfile
     */
    
public function getQueryCacheProfile()
    {
        return 
$this->_queryCacheProfile;
    }

    
/**
     * Change the default fetch mode of an association for this query.
     *
     * $fetchMode can be one of ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY
     *
     * @param string $class
     * @param string $assocName
     * @param int    $fetchMode
     *
     * @return AbstractQuery
     */
    
public function setFetchMode($class$assocName$fetchMode)
    {
        if (
$fetchMode !== MappingClassMetadata::FETCH_EAGER) {
            
$fetchMode MappingClassMetadata::FETCH_LAZY;
        }

        
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;

        return 
$this;
    }

    
/**
     * Defines the processing mode to be used during hydration / result set transformation.
     *
     * @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
     *                               One of the Query::HYDRATE_* constants.
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function setHydrationMode($hydrationMode)
    {
        
$this->_hydrationMode $hydrationMode;

        return 
$this;
    }

    
/**
     * Gets the hydration mode currently used by the query.
     *
     * @return integer
     */
    
public function getHydrationMode()
    {
        return 
$this->_hydrationMode;
    }

    
/**
     * Gets the list of results for the query.
     *
     * Alias for execute(null, $hydrationMode = HYDRATE_OBJECT).
     *
     * @param int $hydrationMode
     *
     * @return array
     */
    
public function getResult($hydrationMode self::HYDRATE_OBJECT)
    {
        return 
$this->execute(null$hydrationMode);
    }

    
/**
     * Gets the array of results for the query.
     *
     * Alias for execute(null, HYDRATE_ARRAY).
     *
     * @return array
     */
    
public function getArrayResult()
    {
        return 
$this->execute(nullself::HYDRATE_ARRAY);
    }

    
/**
     * Gets the scalar results for the query.
     *
     * Alias for execute(null, HYDRATE_SCALAR).
     *
     * @return array
     */
    
public function getScalarResult()
    {
        return 
$this->execute(nullself::HYDRATE_SCALAR);
    }

    
/**
     * Get exactly one result or null.
     *
     * @param int $hydrationMode
     *
     * @return mixed
     *
     * @throws NonUniqueResultException
     */
    
public function getOneOrNullResult($hydrationMode null)
    {
        
$result $this->execute(null$hydrationMode);

        if (
$this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
            return 
null;
        }

        if ( ! 
is_array($result)) {
            return 
$result;
        }

        if (
count($result) > 1) {
            throw new 
NonUniqueResultException;
        }

        return 
array_shift($result);
    }

    
/**
     * Gets the single result of the query.
     *
     * Enforces the presence as well as the uniqueness of the result.
     *
     * If the result is not unique, a NonUniqueResultException is thrown.
     * If there is no result, a NoResultException is thrown.
     *
     * @param integer $hydrationMode
     *
     * @return mixed
     *
     * @throws NonUniqueResultException If the query result is not unique.
     * @throws NoResultException        If the query returned no result.
     */
    
public function getSingleResult($hydrationMode null)
    {
        
$result $this->execute(null$hydrationMode);

        if (
$this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
            throw new 
NoResultException;
        }

        if ( ! 
is_array($result)) {
            return 
$result;
        }

        if (
count($result) > 1) {
            throw new 
NonUniqueResultException;
        }

        return 
array_shift($result);
    }

    
/**
     * Gets the single scalar result of the query.
     *
     * Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
     *
     * @return mixed
     *
     * @throws QueryException If the query result is not unique.
     */
    
public function getSingleScalarResult()
    {
        return 
$this->getSingleResult(self::HYDRATE_SINGLE_SCALAR);
    }

    
/**
     * Sets a query hint. If the hint name is not recognized, it is silently ignored.
     *
     * @param string $name  The name of the hint.
     * @param mixed  $value The value of the hint.
     *
     * @return DoctrineORMAbstractQuery
     */
    
public function setHint($name$value)
    {
        
$this->_hints[$name] = $value;

        return 
$this;
    }

    
/**
     * Gets the value of a query hint. If the hint name is not recognized, FALSE is returned.
     *
     * @param string $name The name of the hint.
     *
     * @return mixed The value of the hint or FALSE, if the hint name is not recognized.
     */
    
public function getHint($name)
    {
        return isset(
$this->_hints[$name]) ? $this->_hints[$name] : false;
    }

    
/**
     * Check if the query has a hint
     *
     * @param  string $name The name of the hint
     *
     * @return bool False if the query does not have any hint
     */
    
public function hasHint($name)
    {
        return isset(
$this->_hints[$name]);
    }

    
/**
     * Return the key value map of query hints that are currently set.
     *
     * @return array
     */
    
public function getHints()
    {
        return 
$this->_hints;
    }

    
/**
     * Executes the query and returns an IterableResult that can be used to incrementally
     * iterate over the result.
     *
     * @param ArrayCollection|array|null $parameters    The query parameters.
     * @param integer|null               $hydrationMode The hydration mode to use.
     *
     * @return DoctrineORMInternalHydrationIterableResult
     */
    
public function iterate($parameters null$hydrationMode null)
    {
        if (
$hydrationMode !== null) {
            
$this->setHydrationMode($hydrationMode);
        }

        if ( ! empty(
$parameters)) {
            
$this->setParameters($parameters);
        }

        
$stmt $this->_doExecute();

        return 
$this->_em->newHydrator($this->_hydrationMode)->iterate(
            
$stmt$this->_resultSetMapping$this->_hints
        
);
    }

    
/**
     * Executes the query.
     *
     * @param ArrayCollection|array|null $parameters Query parameters.
     * @param integer|null               $hydrationMode Processing mode to be used during the hydration process.
     *
     * @return mixed
     */
    
public function execute($parameters null$hydrationMode null)
    {
        if (
$hydrationMode !== null) {
            
$this->setHydrationMode($hydrationMode);
        }

        if ( ! empty(
$parameters)) {
            
$this->setParameters($parameters);
        }

        
$setCacheEntry = function() {};

        if (
$this->_hydrationCacheProfile !== null) {
            list(
$cacheKey$realCacheKey) = $this->getHydrationCacheId();

            
$queryCacheProfile $this->getHydrationCacheProfile();
            
$cache             $queryCacheProfile->getResultCacheDriver();
            
$result            $cache->fetch($cacheKey);

            if (isset(
$result[$realCacheKey])) {
                return 
$result[$realCacheKey];
            }

            if ( ! 
$result) {
                
$result = array();
            }

            
$setCacheEntry = function($data) use ($cache$result$cacheKey$realCacheKey$queryCacheProfile) {
                
$result[$realCacheKey] = $data;

                
$cache->save($cacheKey$result$queryCacheProfile->getLifetime());
            };
        }

        
$stmt $this->_doExecute();

        if (
is_numeric($stmt)) {
            
$setCacheEntry($stmt);

            return 
$stmt;
        }

        
$data $this->_em->newHydrator($this->_hydrationMode)->hydrateAll(
            
$stmt$this->_resultSetMapping$this->_hints
        
);

        
$setCacheEntry($data);

        return 
$data;
    }

    
/**
     * Get the result cache id to use to store the result set cache entry.
     * Will return the configured id if it exists otherwise a hash will be
     * automatically generated for you.
     *
     * @return array ($key, $hash)
     */
    
protected function getHydrationCacheId()
    {
        
$parameters = array();

        foreach (
$this->getParameters() as $parameter) {
            
$parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue());
        }

        
$sql                    $this->getSQL();
        
$queryCacheProfile      $this->getHydrationCacheProfile();
        
$hints                  $this->getHints();
        
$hints['hydrationMode'] = $this->getHydrationMode();

        
ksort($hints);

        return 
$queryCacheProfile->generateCacheKeys($sql$parameters$hints);
    }

    
/**
     * Set the result cache id to use to store the result set cache entry.
     * If this is not explicitly set by the developer then a hash is automatically
     * generated for you.
     *
     * @param string $id
     *
     * @return DoctrineORMAbstractQuery This query instance.
     */
    
public function setResultCacheId($id)
    {
        
$this->_queryCacheProfile $this->_queryCacheProfile
            
$this->_queryCacheProfile->setCacheKey($id)
            : new 
QueryCacheProfile(0$id$this->_em->getConfiguration()->getResultCacheImpl());

        return 
$this;
    }

    
/**
     * Get the result cache id to use to store the result set cache entry if set.
     *
     * @deprecated
     *
     * @return string
     */
    
public function getResultCacheId()
    {
        return 
$this->_queryCacheProfile $this->_queryCacheProfile->getCacheKey() : null;
    }

    
/**
     * Executes the query and returns a the resulting Statement object.
     *
     * @return DoctrineDBALDriverStatement The executed database statement that holds the results.
     */
    
abstract protected function _doExecute();

    
/**
     * Cleanup Query resource when clone is called.
     *
     * @return void
     */
    
public function __clone()
    {
        
$this->parameters = new ArrayCollection();

        
$this->_hints = array();
    }
}
Онлайн: 0
Реклама