Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for joins #175

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lib/Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ public function collectionClass()

/**
* Entity manager class for storing information and meta-data about entities
*
* @param string $entityName
* @return \Spot\Entity\Manager
*/
public function entityManager()
public function entityManager($entityName = null)
{
$entityName = $this->entity();
if (!$entityName) {
$entityName = $this->entity();
}
if (!isset(self::$entityManager[$entityName])) {
self::$entityManager[$entityName] = new Entity\Manager($entityName);
}
Expand Down
183 changes: 176 additions & 7 deletions lib/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace Spot;

use Doctrine\DBAL\Types\Type;

/**
* Query Object - Used to build adapter-independent queries PHP-style
*
Expand Down Expand Up @@ -95,6 +93,13 @@ class Query implements \Countable, \IteratorAggregate, \ArrayAccess, \JsonSerial
*/
protected static $_whereOperatorObjects = [];

/**
* For future use
* Store the type of relation with the selected mapper
* @var
*/
protected $mapping;

/**
* Constructor Method
*
Expand Down Expand Up @@ -209,6 +214,59 @@ public function select()
return $this;
}

/**
* Join (passthrough to DBAL QueryBuilder)
* @param string $fromAlias
* @param string $entityName
* @param string $alias
* @param null $condition
* @return $this
*/
public function join($fromAlias, $entityName, $alias, $condition = null)
{
return $this->makeJoin(__FUNCTION__, $fromAlias, $entityName, $alias, $condition);

}
/**
* Inner Join (passthrough to DBAL QueryBuilder)
* @param string $fromAlias
* @param string $entityName
* @param string $alias
* @param null $condition
* @return $this
*/
public function innerJoin($fromAlias, $entityName, $alias, $condition = null)
{
return $this->makeJoin(__FUNCTION__, $fromAlias, $entityName, $alias, $condition);

}
/**
* Left Join (passthrough to DBAL QueryBuilder)
* @param string $fromAlias
* @param string $entityName
* @param string $alias
* @param null $condition
* @return $this
*/
public function leftJoin($fromAlias, $entityName, $alias, $condition = null)
{
return $this->makeJoin(__FUNCTION__, $fromAlias, $entityName, $alias, $condition);

}
/**
* Right Join (passthrough to DBAL QueryBuilder)
* @param string $fromAlias
* @param string $entityName
* @param string $alias
* @param null $condition
* @return $this
*/
public function rightJoin($fromAlias, $entityName, $alias, $condition = null)
{
return $this->makeJoin(__FUNCTION__, $fromAlias, $entityName, $alias, $condition);

}

/**
* Delete (passthrough to DBAL QueryBuilder)
*
Expand Down Expand Up @@ -347,10 +405,11 @@ public function whereSql($sql)
*
* @param array $where Array of conditions for this clause
* @param bool $useAlias
* @param string $entityName
* @return array SQL fragment strings for WHERE clause
* @throws Exception
*/
private function parseWhereToSQLFragments(array $where, $useAlias = true)
private function parseWhereToSQLFragments(array $where, $useAlias = true, $entityName=null)
{
$builder = $this->builder();

Expand Down Expand Up @@ -383,9 +442,14 @@ private function parseWhereToSQLFragments(array $where, $useAlias = true)

// Prefix column name with alias
if ($useAlias === true) {
$col = $this->fieldWithAlias($col);
$col = $this->fieldWithAlias($col, true, $entityName);
}

if ( $this->stringIsExistingField($entityName, $value) ){
$value = function () use ($value){
return $value;
};
}
$sqlFragments[] = $operatorCallable($builder, $col, $value);
}

Expand Down Expand Up @@ -708,18 +772,25 @@ public function escapeIdentifier($identifier)
* Get field name with table alias appended
* @param string $field
* @param bool $escaped
* @param string $entityName
* @return string
*/
public function fieldWithAlias($field, $escaped = true)
public function fieldWithAlias($field, $escaped = true, $entityName = null)
{
$fieldInfo = $this->_mapper->entityManager()->fields();
$fieldInfo = $this->_mapper->entityManager($entityName)->fields();

//extract table alias if present
list($field, $table) = $this->extractTableAndFieldFromString($field);
// Determine real field name (column alias support)
if (isset($fieldInfo[$field])) {
$field = $fieldInfo[$field]['column'];
}

$field = $this->_tableName . '.' . $field;
if (!$table) {
$table = $this->_mapper->entityManager($entityName)->table();
}

$field = $table . '.' . $field;

return $escaped ? $this->escapeIdentifier($field) : $field;
}
Expand Down Expand Up @@ -810,4 +881,102 @@ public function __call($method, $args)
throw new \BadMethodCallException("Method '" . __CLASS__ . "::" . $method . "' not found");
}
}

/**
* Store the mapping of tables and mapper
* @param string $type
* @param array $data
*/
private function addMapping($type, array $data)
{
$type = (string)$type;
$this->mapping[$type] = $data;
}

/**
* Add a join of type $type
* @param string $type
* @param string $fromAlias
* @param string $entityName
* @param string $alias
* @param string $condition
* @return $this
*/
public function makeJoin($type, $fromAlias, $entityName, $alias, $condition)
{
$joinTable = $this->mapper()->getMapper($entityName)->table();
// $conditionString = (string)$condition;

$this->addMapping(
'join',
array(
$fromAlias => array(
'joinTable' => $joinTable,
'joinAlias' => $alias,
'joinEntity' => $entityName,

),
)
);
// $testCondition = explode('=', $condition);
$conditionString = implode(' AND ', $this->parseWhereToSQLFragments($condition, true, $entityName));
// $conditionString = implode(' =', $condition);
//@FIXME: now parameters are double escaped, because the initial are double escaped also :(
$this->builder()->$type(
$this->escapeIdentifier($fromAlias),
$this->escapeIdentifier($joinTable),
$this->escapeIdentifier($alias),
$conditionString
);

return $this;
}

/**
* Extract data from string, for strings which contains "point"
* @Example: table.field
* @param $string
* @return array
*/
public function extractTableAndFieldFromString($string)
{
$pointPosition = strpos($string, '.');
if ($pointPosition !== false) {
$table = substr($string, 0, $pointPosition);
$field = substr($string, $pointPosition + 1);
} else {
$table = null;
$field = $string;
}

return [$field, $table];

}

/**
* Determine if the value is a existing field
* @param string $entityName
* @param string $value
* @return string
*/
public function stringIsExistingField($entityName, $value)
{
$field = '';
if (is_array($value)) {
return $field;
}
$fieldInfo = array_merge(
$this->_mapper->entityManager($entityName)->fields(),
$this->_mapper->entityManager()->fields()
);
$field = null;
//extract table alias if present
list($extractedField, $table) = $this->extractTableAndFieldFromString($value);
// Determine real field name (column alias support)
if (isset($fieldInfo[$extractedField])) {
$field = $fieldInfo[$extractedField]['column'];
}

return $field;
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/Equals.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public function __invoke(QueryBuilder $builder, $column, $value)
return $column . ' IS NULL';
}

if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return $column . ' = ' . $builder->createPositionalParameter($value);
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/FullText.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class FullText
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return 'MATCH(' . $column . ') AGAINST (' . $builder->createPositionalParameter($value) . ')';
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/FullTextBoolean.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class FullTextBoolean
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return 'MATCH(' . $column . ') AGAINST (' . $builder->createPositionalParameter($value) . ' IN BOOLEAN MODE)';
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/GreaterThan.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class GreaterThan
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return $column . ' > ' . $builder->createPositionalParameter($value);
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/GreaterThanOrEqual.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class GreaterThanOrEqual
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return $column . ' >= ' . $builder->createPositionalParameter($value);
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/In.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public function __invoke(QueryBuilder $builder, $column, $value)
throw new Exception("Use of IN operator expects value to be array. Got " . gettype($value) . ".");
}

if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return $column . ' IN (' . $builder->createPositionalParameter($value, Connection::PARAM_STR_ARRAY) . ')';
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/LessThan.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class LessThan
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' < ' . $value();
}

return $column . ' < ' . $builder->createPositionalParameter($value);
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/LessThanOrEqual.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class LessThanOrEqual
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' <= ' . $value();
}

return $column . ' <= ' . $builder->createPositionalParameter($value);
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/Like.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class Like
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return $column . ' LIKE ' . $builder->createPositionalParameter($value);
}
}
7 changes: 6 additions & 1 deletion lib/Query/Operator/Not.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@ class Not
public function __invoke(QueryBuilder $builder, $column, $value)
{
if (is_array($value) && !empty($value)) {
return $column . ' NOT IN (' . $builder->createPositionalParameter($value, Connection::PARAM_STR_ARRAY) . ')';
return $column . ' NOT IN (' . $builder->createPositionalParameter($value,
Connection::PARAM_STR_ARRAY) . ')';
}

if ($value === null || (is_array($value) && empty($value))) {
return $column . ' IS NOT NULL';
}

if ($value instanceof \Closure) {
return $column . ' = ' . $value();
}

return $column . ' != ' . $builder->createPositionalParameter($value);
}
}
4 changes: 4 additions & 0 deletions lib/Query/Operator/RegExp.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class RegExp
*/
public function __invoke(QueryBuilder $builder, $column, $value)
{
if ($value instanceof \Closure) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be done at a higher level since all these are the same? i.e. do this before passing in the $value to the type classes.

return $column . ' = ' . $value();
}

return $column . ' REGEXP ' . $builder->createPositionalParameter($value);
}
}
1 change: 1 addition & 0 deletions test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test
Loading