From: Cameron Ball Date: Fri, 19 Sep 2014 12:32:32 +0000 (+0800) Subject: Nicer implementation of query builder and query constraints. X-Git-Url: https://git.cameron1729.xyz/?a=commitdiff_plain;h=8dce9fb60d4dab968c70d6420961aa74a1a5a355;p=rock.divinelegy.git Nicer implementation of query builder and query constraints. --- diff --git a/Controllers/IndexController.php b/Controllers/IndexController.php index 8b4ba2a..101d71b 100644 --- a/Controllers/IndexController.php +++ b/Controllers/IndexController.php @@ -28,7 +28,7 @@ class IndexController implements IDivineController $queryConstraints = new SimfileQueryConstraints(); $queryConstraints->stepsHaveRating(15); - $simfiles = $this->_simfileRepository->findByTitle('a', $queryConstraints); + $simfiles = $this->_simfileRepository->findByTitle('a'); foreach($simfiles as $simfile) { diff --git a/DataAccess/DataMapper/DataMapper.php b/DataAccess/DataMapper/DataMapper.php index 9d1611b..b33923c 100644 --- a/DataAccess/DataMapper/DataMapper.php +++ b/DataAccess/DataMapper/DataMapper.php @@ -4,6 +4,7 @@ namespace DataAccess\DataMapper; use Domain\Entities\IDivineEntity; use DataAccess\DataMapper\IDataMapper; +use DataAccess\Queries\IQueryBuilder; use DataAccess\DataMapper\Helpers\AbstractPopulationHelper; use ReflectionClass; use PDO; @@ -22,12 +23,14 @@ class DataMapper implements IDataMapper $options = array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); - $this->_db = new PDO($dsn, $username, null, $options); + $this->_db = new PDO($dsn, $username, $password, $options); $this->_maps = include $maps; } - public function map($entityName, $queryString = 'SELECT * FROM %s') + public function map($entityName, IQueryBuilder $queryBuilder) { + $queryString = $queryBuilder->buildQuery(); + $statement = $this->_db->prepare(sprintf($queryString, $this->_maps[$entityName]['table'] )); diff --git a/DataAccess/DataMapper/IDataMapper.php b/DataAccess/DataMapper/IDataMapper.php index 001db54..dec2895 100644 --- a/DataAccess/DataMapper/IDataMapper.php +++ b/DataAccess/DataMapper/IDataMapper.php @@ -2,7 +2,7 @@ namespace DataAccess\DataMapper; -use DataAccess\Queries\IQueryConstraints; +use DataAccess\Queries\IQueryBuilder; use Domain\Entities\IDivineEntity; interface IDataMapper @@ -10,7 +10,7 @@ interface IDataMapper //TODO: Table is the wrong name. We actually give the implementation the entity name and it finds the table from the maps. //find in table based on constraints and return it as entity - public function map($entityName, $queryString); + public function map($entityName, IQueryBuilder $queryBuilder); //insert/update entity in table public function save(IDivineEntity $entity); //remove entity from table diff --git a/DataAccess/Queries/IQueryBuilder.php b/DataAccess/Queries/IQueryBuilder.php new file mode 100644 index 0000000..777cf15 --- /dev/null +++ b/DataAccess/Queries/IQueryBuilder.php @@ -0,0 +1,18 @@ +applyJoinClause() + ->applyWhereClauses() + ->applyLimitClause(); + + return $this->_queryString; + } + + public function setBaseQuery($baseQuery) + { + $this->_queryString = $baseQuery; + } + + public function where($columnName, $operator, $value) + { + $this->_whereClauses[$columnName] = array('operator' => $operator, 'value' => $value); + return $this; + } + + public function limit($start, $end = null) + { + if($end) + { + $this->_limitClause = sprintf(' LIMIT %u,%u', $start, $end); + return $this; + } + + $this->_limitClause = sprintf(' LIMIT %u', $start); + + return $this; + } + + public function join($type, $tableA, $columnA, $tableB, $columnB) + { + $this->_joinClause = sprintf(' %s JOIN %s ON %s.%s = %s.%s', $type, $tableB, $tableA, $columnA, $tableB, $columnB); + return $this; + } + + private function applyJoinClause() + { + $this->_queryString .= $this->_joinClause; + return $this; + } + + private function applyWhereClauses() + { + $this->_queryString .= ' WHERE '; + + foreach($this->_whereClauses as $columnName => $columnValue) + { + switch(gettype($columnValue['value'])) + { + case 'integer': + $this->_queryString .= sprintf("%s%s%u", $columnName, $columnValue['operator'], $columnValue['value']) . ' AND '; + break; + case 'string': + $this->_queryString .= sprintf("%s %s '%s'", $columnName, $columnValue['operator'], $columnValue['value']) . ' AND '; + break; + } + + } + + $this->_queryString = rtrim($this->_queryString, ' AND '); + return $this; + } + + private function applyLimitClause() + { + $this->_queryString .= $this->_limitClause; + return $this; + } + +} \ No newline at end of file diff --git a/DataAccess/Queries/QueryBuilderFactory.php b/DataAccess/Queries/QueryBuilderFactory.php new file mode 100644 index 0000000..189a341 --- /dev/null +++ b/DataAccess/Queries/QueryBuilderFactory.php @@ -0,0 +1,14 @@ +_queryBuilder = $queryBuilder; + + $this->applyStepsRating() + ->applyBgChanges() + ->applyFgChanges(); + } + public function hasFgChanges($bool) { - return $this->where('fg_changes', '=', (int)$bool); + $this->_fgChanges = (int)$bool; + return $this; } public function hasBgChanges($bool) { - return $this->where('bg_changes', '=', (int)$bool); + $this->_bgChanges = (int)$bool; + return $this; } public function stepsHaveRating($rating) { - return $this->join('INNER', 'simfiles', 'id', 'steps', 'simfile_id') - ->where('steps.rating', '=', $rating); + $this->_stepRating = $rating; + return $this; } public function hasDifficulty($difficulty){} @@ -27,4 +44,33 @@ class SimfileQueryConstraints extends QueryConstraints implements ISimfileQueryC { return; } + + private function applyFgChanges() + { + if($this->_fgChanges) { + $this->_queryBuilder->where('fg_changes', '=', $this->_fgChanges); + } + + return $this; + } + + private function applyBgChanges() + { + if($this->_bgChanges) { + $this->_queryBuilder->where('bg_changes', '=', $this->_bgChanges); + } + + return $this; + } + + private function applyStepsRating() + { + if($this->_stepRating) + { + $this->_queryBuilder->join('INNER', 'simfiles', 'id', 'steps', 'simfile_id') + ->where('steps.rating', '=', $this->_stepRating); + } + + return $this; + } } diff --git a/DataAccess/StepMania/SimfileRepository.php b/DataAccess/StepMania/SimfileRepository.php index 02d7c29..7cd8522 100644 --- a/DataAccess/StepMania/SimfileRepository.php +++ b/DataAccess/StepMania/SimfileRepository.php @@ -4,6 +4,7 @@ namespace DataAccess\StepMania; use DataAccess\StepMania\ISimfileRepository; use DataAccess\DataMapper\IDataMapper; +use DataAccess\Queries\IQueryBuilderFactory; use DataAccess\Queries\StepMania\ISimfileQueryConstraints; use Domain\Entities\StepMania\ISimfile; @@ -11,9 +12,11 @@ use Domain\Entities\StepMania\ISimfile; class SimfileRepository implements ISimfileRepository { private $_dataMapper; + private $_queryBuilderFactory; - public function __construct(IDataMapper $dataMapper) { + public function __construct(IDataMapper $dataMapper, IQueryBuilderFactory $queryBuilderFactory) { $this->_dataMapper = $dataMapper; + $this->_queryBuilderFactory = $queryBuilderFactory; } public function findById($id) { @@ -42,26 +45,15 @@ class SimfileRepository implements ISimfileRepository public function findByTitle($title, ISimfileQueryConstraints $constraints = NULL) { - //TODO: Should I inject a factory, and then make $constraints if it isn't given? + $queryBuilder = $this->_queryBuilderFactory->createInstance(); + $queryBuilder->where('title', 'LIKE', "%%$title%%"); + if($constraints) { - $queryString = $constraints->where('title', 'LIKE', "%%$title%%") //TODO: Should I make a like method that handles adding the %% ? - ->applyTo('SELECT * from %s'); - } else { - //It would avoid this, or rather I could put this in the constraints class - $queryString = "SELECT * FROM %s WHERE title LIKE '%$title%'"; + $constraints->applyTo($queryBuilder); } - - //is it better to pass in constraints object? - //could have a default "select * from %s" in the constraints object which could be overwritten via a method. - //-no more need for applyTo, just go $constratints->getQuery - //maybe it should no longer be constraints but instead queryBuilder - - /** - * have this class contain a queryBuilderFactory and then have constraintsClass - * go in through methods which act on the query, adding in constraints. - */ - return $this->_dataMapper->map('Simfile', $queryString); + + return $this->_dataMapper->map('Simfile', $queryBuilder); } public function findByArtist($artist){} diff --git a/config/DI.php b/config/DI.php index 3f12b93..b1dbecc 100644 --- a/config/DI.php +++ b/config/DI.php @@ -18,5 +18,5 @@ return [ 'DataAccess\StepMania\ISimfileRepository' => DI\object('DataAccess\StepMania\SimfileRepository'), 'DataAccess\DataMapper\IDataMapper' => DI\object('DataAccess\DataMapper\DataMapper') ->constructor(DI\link('datamapper.maps')), - + 'DataAccess\Queries\IQueryBuilderFactory' => DI\object('DataAccess\Queries\QueryBuilderFactory') ];