[Beeframework-svn] SF.net SVN: beeframework:[299] trunk/framework/Bee
Brought to you by:
b_hartmann,
m_plomer
From: <m_p...@us...> - 2015-03-07 00:52:15
|
Revision: 299 http://sourceforge.net/p/beeframework/code/299 Author: m_plomer Date: 2015-03-07 00:52:12 +0000 (Sat, 07 Mar 2015) Log Message: ----------- Persistence: - DaoBase: rework Modified Paths: -------------- trunk/framework/Bee/Context/AbstractContext.php trunk/framework/Bee/Context/Config/Scope/SessionScope.php trunk/framework/Bee/MVC/HttpRequest.php trunk/framework/Bee/MVC/IHttpRequest.php trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php trunk/framework/Bee/Persistence/PaginationBase.php Added Paths: ----------- trunk/framework/Bee/Persistence/Doctrine2/PaginatingDao.php Removed Paths: ------------- trunk/framework/Bee/Persistence/Doctrine/ trunk/framework/Bee/Persistence/Doctrine2/AbstractGenericDao.php trunk/framework/Bee/Persistence/Doctrine2/DaoBase.php Modified: trunk/framework/Bee/Context/AbstractContext.php =================================================================== --- trunk/framework/Bee/Context/AbstractContext.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/Context/AbstractContext.php 2015-03-07 00:52:12 UTC (rev 299) @@ -649,7 +649,7 @@ * @throws BeanNotOfRequiredTypeException * @throws Exception */ - public function getBean($name, $requiredType = null) { + public function &getBean($name, $requiredType = null) { $beanName = $this->transformedBeanName($name); @@ -684,7 +684,7 @@ // @todo: catch IllegalStateException in case scope is not active (e.g. no session started...) // not needed for session, request, prototype scopes but maybe for fancy new scope implementations... - $scopedInstance = $scope->get($beanName, new AbstractContext_ObjectFactoryImpl($beanName, $localBeanDefinition, $this)); + $scopedInstance =& $scope->get($beanName, new AbstractContext_ObjectFactoryImpl($beanName, $localBeanDefinition, $this)); $bean = $this->getObjectForBeanInstance($scopedInstance, $name, $beanName, $localBeanDefinition); @@ -706,8 +706,8 @@ * @throws BeanIsNotAFactoryException * @return object the object to expose for the bean */ - protected function getObjectForBeanInstance( - $beanInstance, $name, $beanName, IBeanDefinition $mbd) { + protected function &getObjectForBeanInstance( + &$beanInstance, $name, $beanName, IBeanDefinition $mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory. if (ContextUtils::isFactoryDereference($name) && !($beanInstance instanceof IFactoryBean)) { Modified: trunk/framework/Bee/Context/Config/Scope/SessionScope.php =================================================================== --- trunk/framework/Bee/Context/Config/Scope/SessionScope.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/Context/Config/Scope/SessionScope.php 2015-03-07 00:52:12 UTC (rev 299) @@ -45,7 +45,7 @@ * @param IObjectFactory $objectFactory * @return mixed|Object */ - public function get($beanName, IObjectFactory $objectFactory) { + public function &get($beanName, IObjectFactory $objectFactory) { $beans =& $_SESSION[$this->id.self::SESSION_SCOPE_PREFIX]; $scopedObject =& $beans[$beanName]; if(is_null($scopedObject)) { Modified: trunk/framework/Bee/MVC/HttpRequest.php =================================================================== --- trunk/framework/Bee/MVC/HttpRequest.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/MVC/HttpRequest.php 2015-03-07 00:52:12 UTC (rev 299) @@ -223,4 +223,8 @@ public function getAjax() { return $this->ajax; } + + function __toString() { + return 'HttpRequest{' . $this->getMethod() . '|' . $this->getPathInfo() . '|ajax:' . $this->getAjax() . '}'; + } } Modified: trunk/framework/Bee/MVC/IHttpRequest.php =================================================================== --- trunk/framework/Bee/MVC/IHttpRequest.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/MVC/IHttpRequest.php 2015-03-07 00:52:12 UTC (rev 299) @@ -107,4 +107,9 @@ * @return bool */ public function getAjax(); + + /** + * @return string + */ + public function __toString(); } \ No newline at end of file Deleted: trunk/framework/Bee/Persistence/Doctrine2/AbstractGenericDao.php =================================================================== --- trunk/framework/Bee/Persistence/Doctrine2/AbstractGenericDao.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/Persistence/Doctrine2/AbstractGenericDao.php 2015-03-07 00:52:12 UTC (rev 299) @@ -1,130 +0,0 @@ -<?php -namespace Bee\Persistence\Doctrine2; -/* - * Copyright 2008-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -use Doctrine\ORM\Query; -use Doctrine\ORM\QueryBuilder; -use UnexpectedValueException; - -/** - * User: mp - * Date: 02.09.13 - * Time: 20:35 - */ - -abstract class AbstractGenericDao extends DaoBase { - - /** - * @param mixed $id - * @throws UnexpectedValueException - * @return mixed - */ - public function getById($id) { - $qb = $this->getBaseQuery(); - $this->applyWhereId($id, $qb); - return $this->getSingleResult($qb); - } - - /** - * @param QueryBuilder $qb - * @return mixed - */ - protected function getSingleResult(QueryBuilder $qb) { - $q = $qb->getQuery(); - $this->decorateQuery($q); - return $q->getSingleResult($this->getHydrationMode()); - } - - /** - * @param Query $q - */ - protected function decorateQuery(Query $q) { - } - - /** - * @return QueryBuilder - */ - protected function getBaseQuery() { - $baseEntityAlias = $this->getEntityAlias(); - $indexBy = count($this->getIdFieldName()) > 1 ? null : $baseEntityAlias . '.' . $this->getIdFieldName(); - return $this->getEntityManager()->createQueryBuilder()->select($baseEntityAlias) - ->from($this->getEntity(), $baseEntityAlias, $indexBy); - } - - /** - * @return string - */ - protected function getEntityAlias() { - return 'e'; - } - - /** - * @return null - */ - protected function getHydrationMode() { - return null; - } - - /** - * @return string - */ - public abstract function getEntity(); - - /** - * @return string|array - */ - protected function getIdFieldName() { - $classMetadata = $this->getEntityManager()->getClassMetadata($this->getEntity()); - $idFields = $classMetadata->getIdentifierFieldNames(); - return count($idFields) > 1 ? $idFields : $idFields[0]; - } - - /** - * @param mixed $id - * @param QueryBuilder $qb - * @throws \UnexpectedValueException - */ - protected function applyWhereId($id, QueryBuilder $qb) { - $idFields = $this->getIdFieldName(); - - $expectedDim = count($idFields); - $actualDim = count($id); - - // unpack single-valued id if necessary - if (is_array($id) && $actualDim === 1) { - $id = $id[0]; - } - - $baseEntityAlias = $this->getEntityAlias(); - if ($expectedDim > 1) { - // composite key - if ($actualDim === 1) { - $id = DaoUtils::explodeScalarId($id, $idFields); - } else if ($actualDim !== $expectedDim) { - throw new UnexpectedValueException('Dimension of given ID (' . count($id) . ') does not match expected dimension (' . count($idFields) . ').'); - } - - // here we can be sure that the dimensions match - both branches above would have thrown otherwise - $whereParts = array(); - array_walk($id, function ($value, $key) use ($baseEntityAlias, &$whereParts) { - $whereParts[] = $baseEntityAlias . '.' . $key . ' = ' . ':' . $key; - }); - $qb->where(implode(' AND ', $whereParts))->setParameters($id); - } else { - $qb->where($baseEntityAlias . '.' . $idFields . ' = :id')->setParameter('id', $id); - } - } -} Deleted: trunk/framework/Bee/Persistence/Doctrine2/DaoBase.php =================================================================== --- trunk/framework/Bee/Persistence/Doctrine2/DaoBase.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/Persistence/Doctrine2/DaoBase.php 2015-03-07 00:52:12 UTC (rev 299) @@ -1,171 +0,0 @@ -<?php -namespace Bee\Persistence\Doctrine2; - -/* - * Copyright 2008-2015 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -use Bee\Persistence\IOrderAndLimitHolder; -use Bee\Persistence\IRestrictionHolder; -use Bee\Utils\Strings; -use Doctrine\ORM\Query; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\Tools\Pagination\Paginator; -use Exception; - -/** - * User: mp - * Date: 05.05.13 - * Time: 17:26 - */ -class DaoBase extends EntityManagerHolder { - - /** - * @param QueryBuilder $queryBuilder - * @param IRestrictionHolder $restrictionHolder - * @param IOrderAndLimitHolder $orderAndLimitHolder - * @param array $defaultOrderMapping - * @param null $hydrationMode - * @return array - */ - public function executeListQuery(QueryBuilder $queryBuilder, IRestrictionHolder $restrictionHolder = null, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null, $hydrationMode = null) { - $this->applyFilterRestrictions($queryBuilder, $restrictionHolder); - $this->applyOrderMapping($queryBuilder, $orderAndLimitHolder, $defaultOrderMapping); - $q = $this->getQueryFromBuilder($queryBuilder); - if(!is_null($hydrationMode)) { - $q->setHydrationMode($hydrationMode); - } - return $this->getPaginatedOrderedResultFromQuery($q, $orderAndLimitHolder); - } - - /** - * @param QueryBuilder $qb - * @return Query - */ - protected function getQueryFromBuilder(QueryBuilder $qb) { - return $qb->getQuery(); - } - - /** - * todo: give this a proper name. This method ONLY applies the text filter (and is only ever intended to do so). All - * todo: other filters are use-case- (or at least entity-) specific. - * @param QueryBuilder $queryBuilder - * @param IRestrictionHolder $restrictionHolder - */ - protected final function applyFilterRestrictions(QueryBuilder &$queryBuilder, IRestrictionHolder $restrictionHolder = null) { - if (is_null($restrictionHolder)) { - return; - } - - if (!Strings::hasText($restrictionHolder->getFilterString())) { - return; - } - - $filterTokens = Strings::tokenizeToArray($restrictionHolder->getFilterString(), ' '); - foreach ($filterTokens as $no => $token) { - $andWhereString = ''; - $params = array(); - - $tokenName = 'filtertoken' . $no; - $params[$tokenName] = '%' . $token . '%'; - foreach ($restrictionHolder->getFilterableFields() as $fieldName) { - // $fieldName MUST BE A DOCTRINE NAME - if (Strings::hasText($andWhereString)) { - $andWhereString .= ' OR '; - } - - $andWhereString .= $fieldName . ' LIKE :' . $tokenName; - } - if (Strings::hasText($andWhereString)) { - $queryBuilder->andWhere($andWhereString); - - foreach ($params as $key => $value) { - $queryBuilder->setParameter($key, $value); - } - } - } - } - - /** - * @param QueryBuilder $queryBuilder - * @param IOrderAndLimitHolder $orderAndLimitHolder - * @param array $defaultOrderMapping - */ - protected final function applyOrderMapping(QueryBuilder &$queryBuilder, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null) { - if (is_null($defaultOrderMapping)) { - $defaultOrderMapping = array(); - } - if (is_null($orderAndLimitHolder)) { - $orderMapping = $defaultOrderMapping; - } else { - $orderMapping = count($orderAndLimitHolder->getOrderMapping()) > 0 ? $orderAndLimitHolder->getOrderMapping() : $defaultOrderMapping; - } - - foreach ($orderMapping as $orderField => $orderDir) { - $queryBuilder->addOrderBy($orderField, $orderDir); - } - } - - /** - * @param callback $func - * @throws Exception - * @return mixed - * - * @deprecated use EntityManagerHolder::transactional() instead - */ - public function doInTransaction($func) { - $this->getLog()->info('Begin transaction.'); - $this->getEntityManager()->beginTransaction(); - try { - $result = $func($this, $this->getLog()); - - $this->getLog()->info('Transaction committing...'); - - $this->getEntityManager()->commit(); - $this->getEntityManager()->flush(); - - $this->getLog()->info('Transaction committed!'); - return $result; - } catch (Exception $e) { - $this->getLog()->warn('Exception caught, rolling back!', $e); - $this->getEntityManager()->rollBack(); - throw $e; - } - } - - /** - * @param Query $q - * @param IOrderAndLimitHolder $orderAndLimitHolder - * @return array|Paginator - */ - protected function getPaginatedOrderedResultFromQuery(Query $q, IOrderAndLimitHolder $orderAndLimitHolder = null) { - if (!is_null($orderAndLimitHolder) && $orderAndLimitHolder->getPageSize() > 0) { - $q->setFirstResult($orderAndLimitHolder->getCurrentPage() * $orderAndLimitHolder->getPageSize()); - $q->setMaxResults($orderAndLimitHolder->getPageSize()); - $paginator = new JsonSerializablePaginator($q, $this->useWhereInPagination()); - $paginator->setUseOutputWalkers(false); - $orderAndLimitHolder->setResultCount(count($paginator)); - return $paginator; - } else { - return $q->getResult($q->getHydrationMode()); - } - } - - /** - * @return bool - */ - protected function useWhereInPagination() { - return true; - } -} Modified: trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php =================================================================== --- trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php 2015-03-07 00:52:12 UTC (rev 299) @@ -2,7 +2,6 @@ namespace Bee\Persistence\Doctrine2; use Bee\Persistence\IOrderAndLimitHolder; -use Bee\Persistence\IRestrictionHolder; use Bee\Utils\Assert; use Bee\Utils\Strings; use Doctrine\ORM\QueryBuilder; @@ -12,8 +11,11 @@ * Class GenericDaoBase * @package Bee\Persistence\Doctrine2 */ -abstract class GenericDaoBase extends DaoBase { +abstract class GenericDaoBase extends PaginatingDao { + const FILTER_STRING = 'filterString'; + const FILTER_STRING_FIELDS = 'filterStringFields'; + /** * @var callable */ @@ -121,71 +123,132 @@ } /** - * @param IRestrictionHolder $restrictionHolder + * @param mixed $filters * @param IOrderAndLimitHolder $orderAndLimitHolder * @param array $defaultOrderMapping * @return array */ - public function getList(IRestrictionHolder $restrictionHolder = null, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null) { - return $this->executeListQuery($this->getBaseQuery(), $restrictionHolder, $orderAndLimitHolder, $defaultOrderMapping, null); + public function getList($filters = null, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null, $hydrationMode = null) { + $qb = $this->getBaseQuery(); + $this->applyFilterRestrictions($qb, $filters); + return $this->executeListQuery($qb, $orderAndLimitHolder, $defaultOrderMapping ?: $this->getDefaultOrderMapping(), $hydrationMode ?: $this->getHydrationMode()); } /** - * @param QueryBuilder $queryBuilder - * @param IRestrictionHolder $restrictionHolder - * @param IOrderAndLimitHolder $orderAndLimitHolder - * @param array $defaultOrderMapping - * @param null $hydrationMode - * @return array + * @param null $entity + * @return QueryBuilder */ - public function executeListQuery(QueryBuilder $queryBuilder, IRestrictionHolder $restrictionHolder = null, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null, $hydrationMode = null) { - if (!is_null($restrictionHolder)) { - $internalFilterableFields = array(); - if (Strings::hasText($restrictionHolder->getFilterString())) { - $this->disaggregateAndInternalizeFieldList($restrictionHolder->getFilterableFields(), $internalFilterableFields, $queryBuilder); - } -// $internalFilters = array(); -// if (count($restrictionHolder->getFilters()) > 0) { -// $this->internalizeFieldValueMapping($restrictionHolder->getFilters(), $internalFilters, $queryBuilder); -// } - $restrictionHolder = new GenericDaoBase_RestrictionWrapper($restrictionHolder, $internalFilterableFields); + protected function getBaseQuery($entity = null) { + $baseEntityAlias = $this->getEntityAlias(); + $entity = $entity ?: $this->getEntity(); +// $indexBy = count($this->getIdFieldName()) > 1 ? null : $baseEntityAlias . '.' . $this->getIdFieldName(); +// return $this->getEntityManager()->createQueryBuilder()->select($baseEntityAlias) +// ->from($this->getEntity(), $baseEntityAlias, $indexBy); + $qb = $this->getEntityManager()->createQueryBuilder()->select($baseEntityAlias)->from($entity, $baseEntityAlias, $this->getIndexBy()); + $this->addJoinsToBaseQuery($qb); + $this->addRestrictionsToBaseQuery($qb); + return $qb; + } + + /** + * @param QueryBuilder $q + */ + protected function addJoinsToBaseQuery(QueryBuilder $q) { + foreach ($this->joins as $join) { + $this->internalizePathExpression($join, $q, true); } + } - if (!is_null($orderAndLimitHolder)) { - if (count($orderAndLimitHolder->getOrderMapping()) > 0) { - $internalMapping = array(); - $this->disaggregateAndInternalizeFieldValueMapping($orderAndLimitHolder->getOrderMapping(), $internalMapping, $queryBuilder); - $orderAndLimitHolder = new GenericDaoBase_OrderAndLimitWrapper($orderAndLimitHolder, $internalMapping); - } + /** + * @param QueryBuilder $q + */ + protected function addRestrictionsToBaseQuery(QueryBuilder $q) { + foreach ($this->restrictions as $restriction) { + $q->andWhere($restriction); } + } - return parent::executeListQuery($queryBuilder, $restrictionHolder, $orderAndLimitHolder, $defaultOrderMapping ?: $this->getDefaultOrderMapping(), $hydrationMode ?: $this->getHydrationMode()); + /** + * @param QueryBuilder $qb + * @return mixed + */ + protected function getSingleResult(QueryBuilder $qb) { + $q = $this->getQueryFromBuilder($qb); + return $q->getSingleResult($this->getHydrationMode()); } /** + * @return null|string + */ + protected function getHydrationMode() { + return null; + } + + /** + * @return string + */ + protected function getEntityAlias() { + return 'e'; + } + + /** + * @return mixed + */ + abstract protected function getIdFieldName(); + + /** + * @return string + */ + public abstract function getEntity(); + + /** + * @return null + */ + protected function getIndexBy() { + return null; + } + + // ================================================================================================================= + // == Field disaggregation and canonicalization ==================================================================== + // ================================================================================================================= + + /** + * @param QueryBuilder $queryBuilder + * @param array $orderMapping + * @return QueryBuilder + */ + protected function applyOrderMapping(QueryBuilder $queryBuilder, array $orderMapping = array()) { + return parent::applyOrderMapping($queryBuilder, $this->disaggregateAndInternalizeFieldValueMapping($orderMapping, $queryBuilder)); + } + + /** * @param array $externalFieldValueMapping * @param array $internalFieldValueMapping * @param QueryBuilder $queryBuilder + * @return array */ - protected final function disaggregateAndInternalizeFieldValueMapping(array $externalFieldValueMapping, array &$internalFieldValueMapping, QueryBuilder $queryBuilder) { + protected final function disaggregateAndInternalizeFieldValueMapping(array $externalFieldValueMapping, QueryBuilder $queryBuilder, array &$internalFieldValueMapping = array()) { foreach ($externalFieldValueMapping as $field => $value) { array_walk($this->getFieldDisaggregation($field), function ($field) use (&$internalFieldValueMapping, $queryBuilder, $value) { $internalFieldValueMapping[$this->internalizeFieldExpression($field, $queryBuilder)] = $value; }); } + return $internalFieldValueMapping; } /** * @param array $externalFieldList + * @param QueryBuilder $queryBuilder * @param array $internalFieldList - * @param QueryBuilder $queryBuilder + * @return array */ - protected final function disaggregateAndInternalizeFieldList(array $externalFieldList, array &$internalFieldList, QueryBuilder $queryBuilder) { + protected final function disaggregateAndInternalizeFieldList(array $externalFieldList, QueryBuilder $queryBuilder, array &$internalFieldList = array()) { foreach ($externalFieldList as $field) { $internalFieldList = array_merge($internalFieldList, array_map(function ($field) use (&$queryBuilder) { return $this->internalizeFieldExpression($field, $queryBuilder); }, $this->getFieldDisaggregation($field))); } + return $internalFieldList; } /** @@ -268,86 +331,72 @@ return $pathExpr; } - /** - * @param null $entity - * @return QueryBuilder - */ - protected function getBaseQuery($entity = null) { - $baseEntityAlias = $this->getEntityAlias(); - $entity = $entity ?: $this->getEntity(); -// $indexBy = count($this->getIdFieldName()) > 1 ? null : $baseEntityAlias . '.' . $this->getIdFieldName(); -// return $this->getEntityManager()->createQueryBuilder()->select($baseEntityAlias) -// ->from($this->getEntity(), $baseEntityAlias, $indexBy); - $qb = $this->getEntityManager()->createQueryBuilder()->select($baseEntityAlias)->from($entity, $baseEntityAlias, $this->getIndexBy()); - $this->addJoinsToBaseQuery($qb); - $this->addRestrictionsToBaseQuery($qb); - return $qb; - } + // ================================================================================================================= + // == Filtering helpers ============================================================================================ + // ================================================================================================================= /** - * @param QueryBuilder $q + * Apply the filter restrictions defined by the filters array to the given QueryBuilder. + * + * Intended to be overridden by subclasses. The default implementation only applies a string filter if defined. + * + * @param QueryBuilder $queryBuilder + * @param mixed $filters + * @return QueryBuilder for chaining */ - protected function addJoinsToBaseQuery(QueryBuilder $q) { - foreach ($this->joins as $join) { - $this->internalizePathExpression($join, $q, true); + protected function applyFilterRestrictions(QueryBuilder &$queryBuilder, $filters = null) { + if (!is_null($filters)) { + if(array_key_exists(self::FILTER_STRING, $filters) && Strings::hasText($filterString = $filters[self::FILTER_STRING])) { + $this->addStringFilterRestrictions($queryBuilder, $filterString, $filters[self::FILTER_STRING_FIELDS]); + } } + return $queryBuilder; } /** - * @param QueryBuilder $q + * @param QueryBuilder $queryBuilder + * @param string $filterString + * @param array $filterableFields + * @return QueryBuilder */ - protected function addRestrictionsToBaseQuery(QueryBuilder $q) { - foreach ($this->restrictions as $restriction) { - $q->andWhere($restriction); - } - } + protected function addStringFilterRestrictions(QueryBuilder $queryBuilder, $filterString, array $filterableFields = array()) { + if (Strings::hasText($filterString)) { + $filterableFields = $this->disaggregateAndInternalizeFieldList($filterableFields, $queryBuilder); - /** - * @param QueryBuilder $qb - * @return mixed - */ - protected function getSingleResult(QueryBuilder $qb) { - $q = $this->getQueryFromBuilder($qb); - return $q->getSingleResult($this->getHydrationMode()); - } + $filterTokens = Strings::tokenizeToArray($filterString, ' '); + foreach ($filterTokens as $no => $token) { + $andWhereString = ''; + $params = array(); - /** - * @return null|string - */ - protected function getHydrationMode() { - return null; - } + $tokenName = 'filtertoken' . $no; + $params[$tokenName] = '%' . $token . '%'; + foreach ($filterableFields as $fieldName) { + // $fieldName MUST BE A DOCTRINE NAME + if (Strings::hasText($andWhereString)) { + $andWhereString .= ' OR '; + } - /** - * @return string - */ - protected function getEntityAlias() { - return 'e'; - } + $andWhereString .= $fieldName . ' LIKE :' . $tokenName; + } + if (Strings::hasText($andWhereString)) { + $queryBuilder->andWhere($andWhereString); - /** - * @return mixed - */ - abstract protected function getIdFieldName(); - - /** - * @return string - */ - public abstract function getEntity(); - - /** - * @return null - */ - protected function getIndexBy() { - return null; + foreach ($params as $key => $value) { + $queryBuilder->setParameter($key, $value); + } + } + } + } + return $queryBuilder; } /** * @param QueryBuilder $queryBuilder * @param $filters * @param string $fieldPath + * @return QueryBuilder for chaining */ - protected function addCategoryRestrictions(QueryBuilder $queryBuilder, $filters, $fieldPath) { + protected final function addCategoryRestrictions(QueryBuilder $queryBuilder, $filters, $fieldPath) { if (array_key_exists($fieldPath, $filters)) { if (!is_array($catIds = $filters[$fieldPath])) { $catIds = array_filter(explode(',', $catIds)); @@ -356,6 +405,7 @@ $queryBuilder->andWhere($queryBuilder->expr()->in('IDENTITY(' . $this->internalizeFieldExpression($fieldPath, $queryBuilder) . ')', $catIds)); } } + return $queryBuilder; } /** @@ -363,12 +413,14 @@ * @param array $filters * @param string $fieldExpr * @param string $filterKey + * @return QueryBuilder for chaining */ - protected function addValueRestriction(QueryBuilder $queryBuilder, $filters, $fieldExpr, $filterKey = '') { + protected final function addValueRestriction(QueryBuilder $queryBuilder, $filters, $fieldExpr, $filterKey = '') { $filterKey = $filterKey ?: $fieldExpr; if (array_key_exists($filterKey, $filters) && $value = $filters[$filterKey]) { $queryBuilder->andWhere($this->internalizeFieldExpression($fieldExpr, $queryBuilder) . ' = :val')->setParameter('val', $value); } + return $queryBuilder; } // ================================================================================================================= @@ -456,107 +508,4 @@ } return array($aggregateFieldName); } -} - -class GenericDaoBase_OrderAndLimitWrapper implements IOrderAndLimitHolder { - - /** - * @var IOrderAndLimitHolder - */ - private $wrappedOrderAndLimitHolder; - - /** - * @var array - */ - private $internalOrderMapping; - - function __construct(IOrderAndLimitHolder $wrappedOrderAndLimitHolder, $internalOrderMapping) { - $this->wrappedOrderAndLimitHolder = $wrappedOrderAndLimitHolder; - $this->internalOrderMapping = $internalOrderMapping; - } - - /** - * @return array - */ - public function getOrderMapping() { - return $this->internalOrderMapping; - } - - /** - * @return int - */ - public function getPageSize() { - return $this->wrappedOrderAndLimitHolder->getPageSize(); - } - - /** - * @return int - */ - public function getPageCount() { - return $this->wrappedOrderAndLimitHolder->getPageCount(); - } - - /** - * @return int - */ - public function getCurrentPage() { - return $this->wrappedOrderAndLimitHolder->getCurrentPage(); - } - - /** - * @param $currentPage - */ - public function setCurrentPage($currentPage) { - $this->wrappedOrderAndLimitHolder->setCurrentPage($currentPage); - } - - /** - * @param int $resultCount - */ - public function setResultCount($resultCount) { - $this->wrappedOrderAndLimitHolder->setResultCount($resultCount); - } -} - -class GenericDaoBase_RestrictionWrapper implements IRestrictionHolder { - - /** - * @var IRestrictionHolder - */ - private $wrappedRestrictionHolder; - - /** - * @var array - */ - private $internalFilterableFields; - - /** - * @param $wrappedRestrictionHolder - * @param $internalFilterableFields - */ - function __construct(IRestrictionHolder $wrappedRestrictionHolder, array $internalFilterableFields/*, array $internalFilters*/) { - $this->wrappedRestrictionHolder = $wrappedRestrictionHolder; - $this->internalFilterableFields = $internalFilterableFields; - } - - /** - * @return array - */ - public function getFilterableFields() { - return $this->internalFilterableFields; - } - - /** - * @return array - */ - public function getFilterString() { - return $this->wrappedRestrictionHolder->getFilterString(); - } - - /** - * @return array - */ - public function getFilters() { - return $this->wrappedRestrictionHolder->getFilters(); - } } \ No newline at end of file Added: trunk/framework/Bee/Persistence/Doctrine2/PaginatingDao.php =================================================================== --- trunk/framework/Bee/Persistence/Doctrine2/PaginatingDao.php (rev 0) +++ trunk/framework/Bee/Persistence/Doctrine2/PaginatingDao.php 2015-03-07 00:52:12 UTC (rev 299) @@ -0,0 +1,124 @@ +<?php +namespace Bee\Persistence\Doctrine2; + +/* + * Copyright 2008-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use Bee\Persistence\IOrderAndLimitHolder; +use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\Tools\Pagination\Paginator; +use Exception; + +/** + * User: mp + * Date: 05.05.13 + * Time: 17:26 + */ +class PaginatingDao extends EntityManagerHolder { + + /** + * @param QueryBuilder $queryBuilder + * @param IOrderAndLimitHolder $orderAndLimitHolder + * @param array $defaultOrderMapping + * @param null $hydrationMode + * @return array + */ + protected final function executeListQuery(QueryBuilder $queryBuilder, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = array(), $hydrationMode = null) { + if (is_null($orderAndLimitHolder)) { + $orderMapping = $defaultOrderMapping; + } else { + $orderMapping = count($orderAndLimitHolder->getOrderMapping()) > 0 ? $orderAndLimitHolder->getOrderMapping() : $defaultOrderMapping; + } + $this->applyOrderMapping($queryBuilder, $orderMapping); + $q = $this->getQueryFromBuilder($queryBuilder); + if(!is_null($hydrationMode)) { + $q->setHydrationMode($hydrationMode); + } + return $this->getPaginatedOrderedResultFromQuery($q, $orderAndLimitHolder); + } + + /** + * @param QueryBuilder $qb + * @return Query + */ + protected function getQueryFromBuilder(QueryBuilder $qb) { + return $qb->getQuery(); + } + + /** + * @param QueryBuilder $queryBuilder + * @param array $orderMapping + * @return QueryBuilder + */ + protected function applyOrderMapping(QueryBuilder $queryBuilder, array $orderMapping = array()) { + foreach ($orderMapping as $orderField => $orderDir) { + $queryBuilder->addOrderBy($orderField, $orderDir); + } + return $queryBuilder; + } + + /** + * @param callback $func + * @throws Exception + * @return mixed + * + * @deprecated use EntityManagerHolder::transactional() instead + */ + public function doInTransaction($func) { + $this->getLog()->info('Begin transaction.'); + $this->getEntityManager()->beginTransaction(); + try { + $result = $func($this, $this->getLog()); + + $this->getLog()->info('Transaction committing...'); + + $this->getEntityManager()->commit(); + $this->getEntityManager()->flush(); + + $this->getLog()->info('Transaction committed!'); + return $result; + } catch (Exception $e) { + $this->getLog()->warn('Exception caught, rolling back!', $e); + $this->getEntityManager()->rollBack(); + throw $e; + } + } + + /** + * @param Query $q + * @param IOrderAndLimitHolder $orderAndLimitHolder + * @return array|Paginator + */ + protected function getPaginatedOrderedResultFromQuery(Query $q, IOrderAndLimitHolder $orderAndLimitHolder = null) { + if (!is_null($orderAndLimitHolder) && $orderAndLimitHolder->getPageSize() > 0) { + $q->setFirstResult($orderAndLimitHolder->getCurrentPage() * $orderAndLimitHolder->getPageSize()); + $q->setMaxResults($orderAndLimitHolder->getPageSize()); + $paginator = new JsonSerializablePaginator($q, $this->useWhereInPagination()); + $paginator->setUseOutputWalkers(false); + $orderAndLimitHolder->setResultCount(count($paginator)); + return $paginator; + } else { + return $q->getResult($q->getHydrationMode()); + } + } + + /** + * @return bool + */ + protected function useWhereInPagination() { + return true; + } +} Modified: trunk/framework/Bee/Persistence/PaginationBase.php =================================================================== --- trunk/framework/Bee/Persistence/PaginationBase.php 2015-03-05 17:00:03 UTC (rev 298) +++ trunk/framework/Bee/Persistence/PaginationBase.php 2015-03-07 00:52:12 UTC (rev 299) @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +use ArrayAccess; use JsonSerializable; /** @@ -25,33 +26,23 @@ */ abstract class PaginationBase implements IOrderAndLimitHolder, JsonSerializable { - /** - * @var int - */ - private $pageSize = 50; + /** + * @var ArrayAccess | array + */ + private $state = array(); /** - * @var int - */ - private $currentPage = 0; - - /** - * @var int - */ - private $resultCount; - - /** * @return int */ public function getPageSize() { - return $this->pageSize; + return $this->state['pageSize']; } /** * @param int $pageSize */ public function setPageSize($pageSize) { - $this->pageSize = intval($pageSize); + $this->state['pageSize'] = intval($pageSize); } /** @@ -65,7 +56,7 @@ * @return int */ public function getCurrentPage() { - return $this->currentPage; + return $this->state['currentPage']; } /** @@ -73,14 +64,14 @@ */ public function setCurrentPage($currentPage) { $currentPage = intval($currentPage); - $this->currentPage = $currentPage < 0 ? 0 : $currentPage; + $this->state['currentPage'] = $currentPage < 0 ? 0 : $currentPage; } /** * @param int $resultCount */ public function setResultCount($resultCount) { - $this->resultCount = intval($resultCount); + $this->state['resultCount'] = intval($resultCount); if($this->getCurrentPage() >= $this->getPageCount()) { $this->adjustCurrentPageOnOverflow(); } @@ -90,7 +81,7 @@ * @return int */ public function getResultCount() { - return $this->resultCount; + return $this->state['resultCount']; } /** @@ -102,6 +93,20 @@ } /** + * @return array|ArrayAccess + */ + public function getState() { + return $this->state; + } + + /** + * @param array|ArrayAccess $state + */ + public function setState($state) { + $this->state = $state; + } + + /** * @return array */ function jsonSerialize() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |