[Beeframework-svn] SF.net SVN: beeframework:[258] trunk
Brought to you by:
b_hartmann,
m_plomer
|
From: <m_p...@us...> - 2014-10-15 18:59:11
|
Revision: 258
http://sourceforge.net/p/beeframework/code/258
Author: m_plomer
Date: 2014-10-15 18:59:03 +0000 (Wed, 15 Oct 2014)
Log Message:
-----------
- refactored DaoBase hierarchy
- fixed parameteralignment in BeanCreationException::__construct()
Added Paths:
-----------
trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php
trunk/framework/Bee/Persistence/Doctrine2/SimpleDao.php
Property Changed:
----------------
trunk/libs/
Added: trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php
===================================================================
--- trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php (rev 0)
+++ trunk/framework/Bee/Persistence/Doctrine2/GenericDaoBase.php 2014-10-15 18:59:03 UTC (rev 258)
@@ -0,0 +1,284 @@
+<?php
+namespace Bee\Persistence\Doctrine2;
+
+use Bee\Persistence\IOrderAndLimitHolder;
+use Bee\Persistence\IRestrictionHolder;
+use Bee\Utils\Strings;
+use Doctrine\ORM\QueryBuilder;
+use UnexpectedValueException;
+
+/**
+ * Class GenericDaoBase
+ * @package Bee\Persistence\Doctrine2
+ */
+abstract class GenericDaoBase extends DaoBase {
+
+ const ALIAS_MATCHER = '#^([a-zA-Z0-9_]{2,})\.#';
+
+ /**
+ * @var callable
+ */
+ private $idRestrictor;
+
+ /**
+ * @var array
+ */
+ private $aliases;
+
+ /**
+ * @var array
+ *
+ * todo: this is only for one-time use during a request. should be ok for MOST cases...
+ */
+ private $addedAliases = array();
+
+ /**
+ * @var array
+ */
+ private $joins = array();
+
+ /**
+ * @var array
+ */
+ private $restrictions = array();
+
+ /**
+ * @var array
+ */
+ private $defaultOrderMapping = array();
+
+ /**
+ * @param mixed $id
+ * @throws UnexpectedValueException
+ * @return mixed
+ */
+ public function getById($id) {
+ if(!is_callable($this->idRestrictor)) {
+ $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;
+ });
+
+ $where = implode(' AND ', $whereParts);
+ $this->idRestrictor = function(QueryBuilder $qb, $id) use ($where) {
+ $qb->where($where)->setParameters($id);
+ };
+ } else {
+ $where = $baseEntityAlias . '.' . $idFields . ' = :id';
+ $this->idRestrictor = function(QueryBuilder $qb, $id) use ($where) {
+ $qb->where($where)->setParameter('id', $id);
+ };
+ }
+ }
+
+ $this->idRestrictor($qb = $this->getBaseQuery(), $id);
+ return $this->getSingleResult($qb);
+ }
+
+ /**
+ * @param IRestrictionHolder $restrictionHolder
+ * @param IOrderAndLimitHolder $orderAndLimitHolder
+ * @param array $defaultOrderMapping
+ * @return array
+ *
+ * @deprecated use executeListQuery() instead
+ */
+ public function getList(IRestrictionHolder $restrictionHolder = null, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null) {
+ return $this->executeListQuery($this->getBaseQuery(), $restrictionHolder, $orderAndLimitHolder, $defaultOrderMapping, null);
+ }
+
+ /**
+ * @param string $expr
+ */
+ protected function addAliasForExpression(QueryBuilder $queryBuilder, $expr) {
+ if(preg_match(self::ALIAS_MATCHER, $expr, $matches)) {
+ $this->addAlias($queryBuilder, $matches[1]);
+ }
+ }
+
+ /**
+ * @param QueryBuilder $queryBuilder
+ * @param string $alias
+ */
+ protected function addAlias(QueryBuilder $queryBuilder, $alias) {
+ if(!$this->containsAlias($alias)) {
+ $this->addedAliases[$alias] = true;
+ $this->addAliasForExpression($queryBuilder, $this->aliases[$alias]);
+ $queryBuilder->leftJoin($this->aliases[$alias], $alias);
+ }
+ }
+
+ /**
+ * @param $alias
+ * @return boolean
+ */
+ protected function containsAlias($alias) {
+ // todo: Alias presence could in theory also be detected by examining the query builders DQL parts. Feasibility / performance?
+ // pros: more thorough and consistent
+ // cons: more overhead?
+ return $alias == $this->getEntityAlias() || array_key_exists($alias, $this->addedAliases) || array_key_exists($alias, $this->getJoins());
+ }
+
+ public function executeListQuery(QueryBuilder $queryBuilder, IRestrictionHolder $restrictionHolder = null, IOrderAndLimitHolder $orderAndLimitHolder = null, array $defaultOrderMapping = null, $hydrationMode = null) {
+ if(!is_null($restrictionHolder)) {
+ if(Strings::hasText($restrictionHolder->getFilterString())) {
+ foreach($restrictionHolder->getFilterableFields() as $field) {
+ $this->addAliasForExpression($queryBuilder, $field);
+ }
+ }
+ if(count($restrictionHolder->getFieldRestrictions()) > 0) {
+ foreach($restrictionHolder->getFieldRestrictions() as $field => $value) {
+ $this->addAliasForExpression($queryBuilder, $field);
+ }
+ }
+ }
+
+ if(!is_null($orderAndLimitHolder)) {
+ if(count($orderAndLimitHolder->getOrderMapping()) > 0) {
+ foreach($orderAndLimitHolder->getOrderMapping() as $field => $dir) {
+ $this->addAliasForExpression($queryBuilder, $field);
+ }
+ }
+ }
+
+ return parent::executeListQuery($queryBuilder, $restrictionHolder, $orderAndLimitHolder, $defaultOrderMapping ?: $this->getDefaultOrderMapping(), $hydrationMode ?: $this->getHydrationMode());
+ }
+
+ /**
+ * @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);
+ $qb = $this->getEntityManager()->createQueryBuilder()->select($baseEntityAlias)->from($this->getEntity(), $baseEntityAlias);
+ $this->addJoinsToBaseQuery($qb);
+ $this->addRestrictionsToBaseQuery($qb);
+ return $qb;
+ }
+
+ /**
+ * @param QueryBuilder $q
+ */
+ protected function addJoinsToBaseQuery(QueryBuilder $q) {
+ foreach($this->joins as $alias => $relation) {
+ $q->addSelect($alias)->leftJoin($relation, $alias);
+ }
+ }
+
+ /**
+ * @param QueryBuilder $q
+ */
+ protected function addRestrictionsToBaseQuery(QueryBuilder $q) {
+ foreach($this->restrictions as $restriction) {
+ $q->andWhere($restriction);
+ }
+ }
+
+ /**
+ * @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();
+
+ // =================================================================================================================
+ // == GETTERS & SETTERS ============================================================================================
+ // =================================================================================================================
+
+ /**
+ * @return array
+ */
+ public function getAliases() {
+ return $this->aliases;
+ }
+
+ /**
+ * @param array $aliases
+ */
+ public function setAliases(array $aliases) {
+ $this->aliases = $aliases;
+ }
+
+ /**
+ * @param array $joins
+ */
+ public function setJoins(array $joins) {
+ $this->joins = $joins;
+ }
+
+ /**
+ * @return array
+ */
+ public function getJoins() {
+ return $this->joins;
+ }
+
+ /**
+ * @param array $restrictions
+ */
+ public function setRestrictions(array $restrictions) {
+ $this->restrictions = $restrictions;
+ }
+
+ /**
+ * @return array
+ */
+ public function getDefaultOrderMapping() {
+ return $this->defaultOrderMapping;
+ }
+
+ /**
+ * @param array $defaultOrderMapping
+ */
+ public function setDefaultOrderMapping(array $defaultOrderMapping) {
+ $this->defaultOrderMapping = $defaultOrderMapping;
+ }
+}
\ No newline at end of file
Added: trunk/framework/Bee/Persistence/Doctrine2/SimpleDao.php
===================================================================
--- trunk/framework/Bee/Persistence/Doctrine2/SimpleDao.php (rev 0)
+++ trunk/framework/Bee/Persistence/Doctrine2/SimpleDao.php 2014-10-15 18:59:03 UTC (rev 258)
@@ -0,0 +1,87 @@
+<?php
+namespace Bee\Persistence\Doctrine2;
+
+/**
+ * Class GenericDao - provides generic CRUD/L operations for a given entity class. The entity class name must be
+ * configured via the $entity property.
+ *
+ * @package Bee\Persistence\Doctrine2
+ */
+class SimpleDao extends GenericDaoBase {
+
+ /**
+ * @var string
+ */
+ private $entity;
+
+ /**
+ * @return string|array
+ */
+ protected function getIdFieldName() {
+ $classMetadata = $this->getEntityManager()->getClassMetadata($this->getEntity());
+ $idFields = $classMetadata->getIdentifierFieldNames();
+ return count($idFields) > 1 ? $idFields : $idFields[0];
+ }
+
+ // =================================================================================================================
+ // == CRUD operations : create / update ============================================================================
+ // =================================================================================================================
+
+ /**
+ * @param mixed $entity
+ * @param bool $flush
+ * @return mixed
+ */
+ public function persist($entity, $flush = true) {
+ $this->prePersist($entity);
+ $this->getEntityManager()->persist($entity);
+ $this->postPersist($entity);
+ if ($flush) {
+ $this->getEntityManager()->flush();
+ }
+ return $entity;
+ }
+
+ protected function prePersist($entity) {
+ }
+
+ protected function postPersist($entity) {
+ }
+
+ // =================================================================================================================
+ // == CRUD operations : delete =====================================================================================
+ // =================================================================================================================
+ /**
+ * @param $entity
+ * @param bool $flush
+ * @return void
+ */
+ public function delete($entity, $flush = true) {
+ $this->preDelete($entity);
+ $this->getEntityManager()->remove($entity);
+ if ($flush) {
+ $this->getEntityManager()->flush();
+ }
+ }
+
+ protected function preDelete($entity) {
+ }
+
+ // =================================================================================================================
+ // == GETTERS & SETTERS ============================================================================================
+ // =================================================================================================================
+
+ /**
+ * @return string
+ */
+ public function getEntity() {
+ return $this->entity;
+ }
+
+ /**
+ * @param string $entity
+ */
+ public function setEntity($entity) {
+ $this->entity = $entity;
+ }
+}
\ No newline at end of file
Index: trunk/libs
===================================================================
--- trunk/libs 2014-10-15 00:20:24 UTC (rev 257)
+++ trunk/libs 2014-10-15 18:59:03 UTC (rev 258)
Property changes on: trunk/libs
___________________________________________________________________
Modified: svn:externals
## -1,2 +1 ##
-log4php-2.1.0 https://svn.apache.org/repos/asf/logging/log4php/tags/apache-log4php-2.1.0/src/main/php
php-aop http://php-aop.googlecode.com/svn/trunk/aop
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|