From 66468c51e80801e73d2c069767060d9c095ea01a Mon Sep 17 00:00:00 2001 From: David James Wyly Date: Sat, 29 Sep 2018 01:49:51 -0600 Subject: [PATCH 1/4] wip --- src/Rxn/Orm/Builder.php | 55 ------- src/Rxn/Orm/Builder/Column.php | 22 +++ src/Rxn/Orm/Builder/Command.php | 110 ++++++++++++++ src/Rxn/Orm/Builder/Query.php | 34 +++-- src/Rxn/Orm/Builder/Query/From.php | 19 +-- src/Rxn/Orm/Builder/Query/Join.php | 55 +++---- src/Rxn/Orm/Builder/Query/On.php | 23 +++ src/Rxn/Orm/Builder/Query/Select.php | 29 ++-- src/Rxn/Orm/Builder/Query/Where.php | 4 +- src/Rxn/Orm/Builder/QueryParser.php | 149 ------------------- src/Rxn/Orm/Builder/Table.php | 33 ++++ src/Rxn/Orm/Tests/Builder/Query/JoinTest.php | 5 +- 12 files changed, 250 insertions(+), 288 deletions(-) create mode 100644 src/Rxn/Orm/Builder/Column.php create mode 100644 src/Rxn/Orm/Builder/Command.php create mode 100644 src/Rxn/Orm/Builder/Query/On.php delete mode 100644 src/Rxn/Orm/Builder/QueryParser.php create mode 100644 src/Rxn/Orm/Builder/Table.php diff --git a/src/Rxn/Orm/Builder.php b/src/Rxn/Orm/Builder.php index 221969c..feb76f4 100644 --- a/src/Rxn/Orm/Builder.php +++ b/src/Rxn/Orm/Builder.php @@ -21,17 +21,6 @@ abstract class Builder */ public $table_aliases = []; - /** - * @param string $reference - * - * @return string - */ - protected function cleanReference(string $reference): string - { - $filtered_reference = $this->filterReference($reference); - return $this->escapeReference($filtered_reference); - } - protected function cleanValue(string $value): string { return "'$value'"; @@ -47,55 +36,11 @@ function changeKey(&$array, $old_key, $new_key) return array_combine($keys, $array); } - /** - * @param string $operand - * - * @return string - */ - protected function filterReference(string $operand): string - { - $operand = preg_replace('#[\`\s]#', '', $operand); - preg_match('#[\p{L}\_\.\-\`0-9]+#', $operand, $matches); - if (isset($matches[0])) { - return $matches[0]; - } - return ''; - } - - /** - * @param string $operand - * - * @return string - */ - protected function escapeReference(string $operand): string - { - $exploded_operand = explode('.', $operand); - if (count($exploded_operand) === 2) { - return "`{$exploded_operand[0]}`.`{$exploded_operand[1]}`"; - } - return "`$operand`"; - } - - - protected function isAssociative(array $array) - { - if ([] === $array) { - return false; - } - ksort($array); - return array_keys($array) !== range(0, count($array) - 1); - } - protected function addCommandWithModifiers($command, $modifiers, $key) { $this->commands[$command][$key] = $modifiers; } - protected function addCommand($command, $value) - { - $this->commands[$command][] = $value; - } - protected function loadCommands(Builder $builder) { $this->commands = array_merge_recursive((array)$this->commands, (array)$builder->commands); diff --git a/src/Rxn/Orm/Builder/Column.php b/src/Rxn/Orm/Builder/Column.php new file mode 100644 index 0000000..9330d5c --- /dev/null +++ b/src/Rxn/Orm/Builder/Column.php @@ -0,0 +1,22 @@ +column = $column; + $this->alias = $alias; + } +} diff --git a/src/Rxn/Orm/Builder/Command.php b/src/Rxn/Orm/Builder/Command.php new file mode 100644 index 0000000..ac16569 --- /dev/null +++ b/src/Rxn/Orm/Builder/Command.php @@ -0,0 +1,110 @@ +filterReference($reference); + //return $this->escapeReference($filtered_reference); + return $filtered_reference; + } + + protected function addColumn($column, $alias = null) + { + list($column, $table, $database) = $this->listColumnTableDatabase($column); + + $key = null; + if (!empty($column)) { + $key = $column; + if (!empty($alias)) { + $key = $alias; + } + } + + $table = $this->addTable($table, null, $database); + + $table->columns[$key] = new Column($column, $alias); + } + + protected function addTable($table, $alias = null, $database = null) + { + $this->tables[$table] = new Table($table, $alias, $database); + return $this->tables[$table]; + } + + protected function listColumnTableDatabase($reference) + { + preg_match('#\`?(\p{L}+)\`?\.\`?(\p{L}+)\`?#', $reference, $matches); + if (isset($matches[1]) && isset($matches[2]) && !isset($matches[3])) { + $table = $matches[1]; + $column = $matches[2]; + return [$column, $table, null]; + } elseif (isset($matches[3])) { + $database = $matches[1]; + $table = $matches[2]; + $column = $matches[3]; + return [$column, $table, $database]; + } + $column = $reference; + return [$column, null, null]; + } + + /** + * @param string $operand + * + * @return string + */ + protected function escapeReference(string $operand): string + { + $exploded_operands = explode('.', $operand); + + $operands = []; + foreach ($exploded_operands as $exploded_operand) { + $operands[] = "`$exploded_operand`"; + } + return implode(".", $operands); + } + + /** + * @param string $operand + * + * @return string + */ + protected function filterReference(string $operand): string + { + $operand = preg_replace('#[\`\s]#', '', $operand); + preg_match('#[\p{L}\_\.\-\`0-9]+#', $operand, $matches); + if (isset($matches[0])) { + return $matches[0]; + } + return ''; + } +} diff --git a/src/Rxn/Orm/Builder/Query.php b/src/Rxn/Orm/Builder/Query.php index 61b2396..b82b208 100644 --- a/src/Rxn/Orm/Builder/Query.php +++ b/src/Rxn/Orm/Builder/Query.php @@ -10,6 +10,22 @@ class Query extends Builder { + + /** + * @var Select + */ + public $select; + + /** + * @var From + */ + public $from; + + /** + * @var Join[] + */ + public $joins; + /** * @param array $columns * @param bool $distinct @@ -18,9 +34,8 @@ class Query extends Builder */ public function select(array $columns = ['*'], $distinct = false): Query { - $select = new Select(); - $select->set($columns, $distinct); - $this->loadCommands($select); + $this->select = new Select(); + $this->select->set($columns, $distinct); return $this; } @@ -32,10 +47,8 @@ public function select(array $columns = ['*'], $distinct = false): Query */ public function from(string $table, string $alias = null): Query { - $from = new From(); - $from->set($table, $alias); - $this->loadCommands($from); - $this->loadTableAliases($from); + $this->from = new From(); + $this->from->set($table, $alias); return $this; } @@ -52,9 +65,7 @@ public function joinCustom(string $table, callable $callable, string $alias = nu { $join = new Join(); $join->set($table, $callable, $alias, $type); - $this->loadCommands($join); - $this->loadBindings($join); - $this->loadTableAliases($join); + $this->joins[] = $join; return $this; } @@ -98,9 +109,6 @@ public function innerJoin( ): Query { return $this->joinCustom($table, function (Join $join) use ($first_operand, $operator, $second_operand, $alias) { - if (!empty($alias)) { - $join->as($alias); - } $join->on($first_operand, $operator, $second_operand); }, $alias, 'inner'); } diff --git a/src/Rxn/Orm/Builder/Query/From.php b/src/Rxn/Orm/Builder/Query/From.php index ef4dd11..fd3f460 100644 --- a/src/Rxn/Orm/Builder/Query/From.php +++ b/src/Rxn/Orm/Builder/Query/From.php @@ -2,19 +2,14 @@ namespace Rxn\Orm\Builder\Query; -use Rxn\Orm\Builder\Query; +use Rxn\Orm\Builder\Command; -class From extends Query { +class From extends Command +{ - public function set(string $table, string $alias = null) { - $escaped_table = $this->escapeReference($table); - if (empty($alias)) { - $value = $escaped_table; - } else { - $escaped_alias = $this->escapeReference($alias); - $value = "$escaped_table AS $escaped_alias"; - $this->table_aliases[$table] = $alias; - } - $this->addCommand('FROM', $value); + public function set(string $table, string $alias = null, $database = null) + { + $this->command = 'FROM'; + $this->addTable($table, $alias, $database); } } diff --git a/src/Rxn/Orm/Builder/Query/Join.php b/src/Rxn/Orm/Builder/Query/Join.php index ecdfae4..bf7055d 100644 --- a/src/Rxn/Orm/Builder/Query/Join.php +++ b/src/Rxn/Orm/Builder/Query/Join.php @@ -2,9 +2,10 @@ namespace Rxn\Orm\Builder\Query; -use Rxn\Orm\Builder; +use Rxn\Orm\Builder\Command; +use Rxn\Orm\Builder\Table; -class Join extends Builder +class Join extends Command { const JOIN_COMMANDS = [ 'inner' => 'INNER JOIN', @@ -13,64 +14,42 @@ class Join extends Builder ]; /** - * @var string + * @var Table[] */ - public $table; - - /** - * @var string - */ - public $alias; + public $tables; /** * @var */ - public $modifiers; + public $command; /** - * @var + * @var On[]|Where[] */ - public $bindings; + public $commands; public function set(string $table, callable $callable, string $alias = null, string $type = 'inner') { if (!array_key_exists($type, self::JOIN_COMMANDS)) { throw new \Exception(""); } - $this->table = $table; - $this->addAlias($alias); - $command = self::JOIN_COMMANDS[$type]; + $this->command = self::JOIN_COMMANDS[$type]; + $this->addTable($table,$alias); call_user_func($callable, $this); - $this->addBindings($this->bindings); - $this->addCommandWithModifiers($command, $this->modifiers, $table); - } - - - public function as(string $alias) { - $this->alias = $alias; - $clean_alias = $this->cleanReference($alias); - if (!in_array($clean_alias, (array)$this->modifiers['AS'])) { - $this->modifiers['AS'][] = $clean_alias; - $this->table_aliases[$this->table] = $alias; - } + public function on(string $first_operand, string $operator, $second_operand) { + $command = new On($first_operand, $operator, $second_operand); + $this->commands[] = $command; return $this; } - public function on(string $first, string $condition, $second) { - $first = $this->cleanReference($first); - $second = $this->cleanReference($second); - $value = "$first $condition $second"; - $this->modifiers['ON'][] = $value; + public function where(string $first_operand, string $operator, $second_operand) { + $command = new Where(); + $command->set($first_operand,$operator,$second_operand); + $this->commands[] = $command; return $this; } - private function addAlias($alias) { - if (!empty($alias)) { - $this->as($alias); - } - } - protected function addCommand($command, $value) { $this->commands[$command][] = $value; diff --git a/src/Rxn/Orm/Builder/Query/On.php b/src/Rxn/Orm/Builder/Query/On.php new file mode 100644 index 0000000..747a927 --- /dev/null +++ b/src/Rxn/Orm/Builder/Query/On.php @@ -0,0 +1,23 @@ +first_operand = $first_operand; + $this->operator = $operator; + $this->second_operand = $second_operand; + $this->addColumn($first_operand); + $this->addColumn($second_operand); + } +} diff --git a/src/Rxn/Orm/Builder/Query/Select.php b/src/Rxn/Orm/Builder/Query/Select.php index 3eb14be..5240524 100644 --- a/src/Rxn/Orm/Builder/Query/Select.php +++ b/src/Rxn/Orm/Builder/Query/Select.php @@ -2,14 +2,15 @@ namespace Rxn\Orm\Builder\Query; -use Rxn\Orm\Builder\Query; +use Rxn\Orm\Builder\Command; -class Select extends Query +class Select extends Command { /** - * @param array $columns - * @param bool $distinct + * @var string */ + public $command; + public function set(array $columns = ['*'], $distinct = false) { if ($columns === ['*'] @@ -21,6 +22,7 @@ public function set(array $columns = ['*'], $distinct = false) } else { $this->selectNumerical($columns, $distinct); } + return $this; } /** @@ -28,8 +30,9 @@ public function set(array $columns = ['*'], $distinct = false) */ public function selectAll($distinct = false) { - $command = ($distinct) ? 'SELECT DISTINCT' : 'SELECT'; - $this->addCommand($command, "*"); + $this->command = ($distinct) ? 'SELECT DISTINCT' : 'SELECT'; + $this->addColumn('*'); + $this->addClause('*'); } /** @@ -38,16 +41,10 @@ public function selectAll($distinct = false) */ public function selectAssociative(array $columns, $distinct = false) { - $command = ($distinct) ? 'SELECT DISTINCT' : 'SELECT'; - foreach ($columns as $reference => $alias) { - $reference = $this->cleanReference($reference); - if (empty($alias)) { - $value = $reference; - } else { - $alias = $this->cleanReference($alias); - $value = "$reference AS $alias"; - } - $this->addCommand($command, $value); + $this->command = ($distinct) ? 'SELECT DISTINCT' : 'SELECT'; + foreach ($columns as $column => $alias) { + $column = $this->cleanReference($column); + $this->addColumn($column, $alias); } } diff --git a/src/Rxn/Orm/Builder/Query/Where.php b/src/Rxn/Orm/Builder/Query/Where.php index 6cf1e34..89c971e 100644 --- a/src/Rxn/Orm/Builder/Query/Where.php +++ b/src/Rxn/Orm/Builder/Query/Where.php @@ -2,9 +2,9 @@ namespace Rxn\Orm\Builder\Query; -use Rxn\Orm\Builder\Query; +use Rxn\Orm\Builder\Command; -class Where extends Query +class Where extends Command { const WHERE_COMMANDS = [ diff --git a/src/Rxn/Orm/Builder/QueryParser.php b/src/Rxn/Orm/Builder/QueryParser.php deleted file mode 100644 index 8c27426..0000000 --- a/src/Rxn/Orm/Builder/QueryParser.php +++ /dev/null @@ -1,149 +0,0 @@ -builder = $builder; - } - - public function getSql() - { - $sql = ''; - $sql .= $this->select(); - $sql .= $this->from(); - $sql .= $this->innerJoin(); - $sql .= $this->leftJoin(); - $sql .= $this->rightJoin(); - $sql .= $this->where(); - $sql .= $this->or(); - return $sql; - } - - private function select() - { - if (!array_key_exists('SELECT', $this->builder->commands)) { - return ''; - } - - $select = $this->builder->commands['SELECT']; - if ($select == ['*']) { - return "SELECT * \r\n"; - } - return "SELECT \r\n " . implode(",\r\n ", $select) . " \r\n"; - } - - private function from() - { - if (!array_key_exists('FROM', $this->builder->commands)) { - return ''; - } - - $from = $this->builder->commands['FROM']; - return "FROM " . implode(",\r\n ", $from) . " \r\n"; - } - - private function innerJoin() - { - if (!array_key_exists('INNER JOIN', $this->builder->commands)) { - return ''; - } - return $this->join('INNER JOIN'); - } - - private function leftJoin() - { - if (!array_key_exists('LEFT JOIN', $this->builder->commands)) { - return ''; - } - return $this->join('LEFT JOIN'); - } - - private function rightJoin() - { - if (!array_key_exists('RIGHT JOIN', $this->builder->commands)) { - return ''; - } - return $this->join('RIGHT JOIN'); - } - - private function where() { - if (!array_key_exists('WHERE', $this->builder->commands)) { - return ''; - } - - $where = $this->builder->commands['WHERE']; - - $sql = ''; - $used_initial_where = false; - foreach ($where as $key => $value) { - if (is_numeric($key) && is_array($value)) { - // in a group - foreach ($value as $grouped_command => $commands) { - switch ($grouped_command) { - case 'WHERE': - $grouped_command = ($used_initial_where) ? 'AND' : 'WHERE'; - $used_initial_where = true; - $commands_imploded = implode(" \r\n AND ",$commands); - $sql .= "$grouped_command (\r\n $commands_imploded \r\n)\r\n"; - } - } - } - } - return $sql; - } - - private function or() { - if (!array_key_exists('WHERE', $this->builder->commands)) { - return ''; - } - - $where = $this->builder->commands['WHERE']; - - $sql = ''; - $used_initial_where = false; - foreach ($where as $key => $value) { - if (is_numeric($key) && is_array($value)) { - // in a group - foreach ($value as $grouped_command => $commands) { - switch ($grouped_command) { - case 'WHERE': - $grouped_command = ($used_initial_where) ? 'AND' : 'WHERE'; - $used_initial_where = true; - $commands_imploded = implode(" \r\n AND ",$commands); - $sql .= "$grouped_command (\r\n $commands_imploded \r\n)\r\n"; - } - } - } - } - return $sql; - } - - private function join($command) { - $inner_join = $this->builder->commands[$command]; - - $sql = ''; - foreach ($inner_join as $table => $conditions) { - $sql .= "$command `$table` "; - foreach ($conditions as $condition => $expressions) { - $sql .= "$condition "; - foreach ($expressions as $expression) { - $sql .= "$expression "; - } - } - $sql .= "\r\n"; - } - return $sql; - } - - -} diff --git a/src/Rxn/Orm/Builder/Table.php b/src/Rxn/Orm/Builder/Table.php new file mode 100644 index 0000000..fbc6fca --- /dev/null +++ b/src/Rxn/Orm/Builder/Table.php @@ -0,0 +1,33 @@ +table = $table; + $this->alias = $alias; + $this->database = $database; + } +} diff --git a/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php b/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php index 844fdd0..77f3690 100644 --- a/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php +++ b/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php @@ -12,7 +12,7 @@ public function testJoin() { $query = new Query(); $query->select(['users.id' => 'user_id']) - ->from('users') + ->from('users','o') ->join('orders', 'orders.user_id', '=', 'users.id', 'o') ->join('invoices', 'invoices.id', '=', 'orders.invoice_id', 'i') ->where('users.first_name', '=', 'David', function (Where $where) { @@ -25,8 +25,7 @@ public function testJoin() $where->and('users.last_name2', '=', 'Andrews', function (Where $where) { $where->or('users.last_name2', '=', 'Andrews, III'); }); - }) - ->build(); + }); $this->assertEquals('`users`.`id` AS `user_id`', $query->commands['SELECT'][0]); From 8affea3c7f3d20ea7a94c1ada477704bafc82232 Mon Sep 17 00:00:00 2001 From: David James Wyly Date: Sat, 29 Sep 2018 01:56:18 -0600 Subject: [PATCH 2/4] commands are now in one array --- src/Rxn/Orm/Builder/Query.php | 26 +++++++++----------------- src/Rxn/Orm/Builder/Query/Join.php | 8 ++++---- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/Rxn/Orm/Builder/Query.php b/src/Rxn/Orm/Builder/Query.php index b82b208..a126953 100644 --- a/src/Rxn/Orm/Builder/Query.php +++ b/src/Rxn/Orm/Builder/Query.php @@ -12,19 +12,9 @@ class Query extends Builder { /** - * @var Select + * @var Command[] */ - public $select; - - /** - * @var From - */ - public $from; - - /** - * @var Join[] - */ - public $joins; + public $commands; /** * @param array $columns @@ -34,8 +24,9 @@ class Query extends Builder */ public function select(array $columns = ['*'], $distinct = false): Query { - $this->select = new Select(); - $this->select->set($columns, $distinct); + $select = new Select(); + $select->set($columns, $distinct); + $this->commands[] = $select; return $this; } @@ -47,8 +38,9 @@ public function select(array $columns = ['*'], $distinct = false): Query */ public function from(string $table, string $alias = null): Query { - $this->from = new From(); - $this->from->set($table, $alias); + $from = new From(); + $from->set($table, $alias); + $this->commands[] = $from; return $this; } @@ -65,7 +57,7 @@ public function joinCustom(string $table, callable $callable, string $alias = nu { $join = new Join(); $join->set($table, $callable, $alias, $type); - $this->joins[] = $join; + $this->commands[] = $join; return $this; } diff --git a/src/Rxn/Orm/Builder/Query/Join.php b/src/Rxn/Orm/Builder/Query/Join.php index bf7055d..ba25ab8 100644 --- a/src/Rxn/Orm/Builder/Query/Join.php +++ b/src/Rxn/Orm/Builder/Query/Join.php @@ -14,14 +14,14 @@ class Join extends Command ]; /** - * @var Table[] + * @var */ - public $tables; + public $command; /** - * @var + * @var Table[] */ - public $command; + public $tables; /** * @var On[]|Where[] From 38cf4f31b36533a6b01623f0389309181f0112fb Mon Sep 17 00:00:00 2001 From: David James Wyly Date: Sat, 29 Sep 2018 02:37:05 -0600 Subject: [PATCH 3/4] getting closer --- src/Rxn/Orm/Builder.php | 46 +------- src/Rxn/Orm/Builder/Command.php | 42 ++++++++ src/Rxn/Orm/Builder/Query.php | 19 +--- src/Rxn/Orm/Builder/Query/From.php | 1 + src/Rxn/Orm/Builder/Query/Join.php | 2 + src/Rxn/Orm/Builder/Query/{ => Join}/On.php | 2 +- src/Rxn/Orm/Builder/Query/Where.php | 104 ++++++++++++++++--- src/Rxn/Orm/Tests/Builder/Query/JoinTest.php | 2 +- 8 files changed, 144 insertions(+), 74 deletions(-) rename src/Rxn/Orm/Builder/Query/{ => Join}/On.php (93%) diff --git a/src/Rxn/Orm/Builder.php b/src/Rxn/Orm/Builder.php index feb76f4..58d1cc7 100644 --- a/src/Rxn/Orm/Builder.php +++ b/src/Rxn/Orm/Builder.php @@ -2,6 +2,7 @@ namespace Rxn\Orm; +use Rxn\Orm\Builder\Command; use Rxn\Orm\Builder\QueryParser; abstract class Builder @@ -41,18 +42,13 @@ protected function addCommandWithModifiers($command, $modifiers, $key) $this->commands[$command][$key] = $modifiers; } - protected function loadCommands(Builder $builder) - { - $this->commands = array_merge_recursive((array)$this->commands, (array)$builder->commands); - } - - protected function loadGroupCommands(Builder $builder, $type) { - $this->commands[$type][] = $builder->commands; + protected function loadGroupCommands(Command $command, $type) { + $this->commands[$type][] = $command; } - protected function loadBindings(Builder $builder) + protected function loadBindings(Command $command) { - $this->bindings = array_merge((array)$this->bindings, (array)$builder->bindings); + $this->bindings = array_merge((array)$this->bindings, (array)$command->bindings); } protected function loadTableAliases(Builder $builder) @@ -65,38 +61,6 @@ protected function getCommands() return $this->commands; } - protected function addBindings($key_values) - { - if (empty($key_values)) { - return null; - } - foreach ($key_values as $value) { - $this->addBinding($value); - } - } - - protected function addBinding($value) - { - $this->bindings[] = $value; - } - - protected function getOperandBindings($operand): array - { - if (is_array($operand)) { - $bindings = []; - $parsed_array = []; - if (empty($bindings)) { - foreach ($operand as $value) { - $parsed_array[] = '?'; - $bindings[] = $value; - } - return ['(' . implode(",", $parsed_array) . ')', $bindings]; - } - } - - return ['?', [$operand]]; - } - public function build() { $parser = new QueryParser($this); $this->rawSql = $parser->getSql(); diff --git a/src/Rxn/Orm/Builder/Command.php b/src/Rxn/Orm/Builder/Command.php index ac16569..be23a82 100644 --- a/src/Rxn/Orm/Builder/Command.php +++ b/src/Rxn/Orm/Builder/Command.php @@ -16,6 +16,11 @@ abstract class Command */ protected $tables = []; + /** + * @var array + */ + public $bindings = []; + protected function isAssociative(array $array) { if ($array === []) { @@ -107,4 +112,41 @@ protected function filterReference(string $operand): string } return ''; } + + /** + * @param $operand + * + * @return array + */ + protected function getOperandBindings($operand): array + { + if (is_array($operand)) { + $bindings = []; + $parsed_array = []; + if (empty($bindings)) { + foreach ($operand as $value) { + $parsed_array[] = '?'; + $bindings[] = $value; + } + return ['(' . implode(",", $parsed_array) . ')', $bindings]; + } + } + + return ['?', [$operand]]; + } + + protected function addBindings($key_values) + { + if (empty($key_values)) { + return null; + } + foreach ($key_values as $value) { + $this->addBinding($value); + } + } + + protected function addBinding($value) + { + $this->bindings[] = $value; + } } diff --git a/src/Rxn/Orm/Builder/Query.php b/src/Rxn/Orm/Builder/Query.php index a126953..1675e55 100644 --- a/src/Rxn/Orm/Builder/Query.php +++ b/src/Rxn/Orm/Builder/Query.php @@ -24,9 +24,7 @@ class Query extends Builder */ public function select(array $columns = ['*'], $distinct = false): Query { - $select = new Select(); - $select->set($columns, $distinct); - $this->commands[] = $select; + $this->commands[] = (new Select())->set($columns, $distinct); return $this; } @@ -38,9 +36,7 @@ public function select(array $columns = ['*'], $distinct = false): Query */ public function from(string $table, string $alias = null): Query { - $from = new From(); - $from->set($table, $alias); - $this->commands[] = $from; + $this->commands[] = (new From())->set($table, $alias); return $this; } @@ -55,9 +51,7 @@ public function from(string $table, string $alias = null): Query */ public function joinCustom(string $table, callable $callable, string $alias = null, string $type = 'inner'): Query { - $join = new Join(); - $join->set($table, $callable, $alias, $type); - $this->commands[] = $join; + $this->commands[] = (new Join())->set($table, $callable, $alias, $type); return $this; } @@ -195,12 +189,7 @@ public function where( ): Query { $where = new Where(); $where->set($first_operand, $operator, $second_operand, $callback, $type); - if (!is_null($callback)) { - $group = $where::WHERE_COMMANDS[$type]; - $this->loadGroupCommands($where, $group); - } else { - $this->loadCommands($where); - } + $this->commands[] = $where; $this->loadBindings($where); return $this; } diff --git a/src/Rxn/Orm/Builder/Query/From.php b/src/Rxn/Orm/Builder/Query/From.php index fd3f460..4878901 100644 --- a/src/Rxn/Orm/Builder/Query/From.php +++ b/src/Rxn/Orm/Builder/Query/From.php @@ -11,5 +11,6 @@ public function set(string $table, string $alias = null, $database = null) { $this->command = 'FROM'; $this->addTable($table, $alias, $database); + return $this; } } diff --git a/src/Rxn/Orm/Builder/Query/Join.php b/src/Rxn/Orm/Builder/Query/Join.php index ba25ab8..8106d8a 100644 --- a/src/Rxn/Orm/Builder/Query/Join.php +++ b/src/Rxn/Orm/Builder/Query/Join.php @@ -3,6 +3,7 @@ namespace Rxn\Orm\Builder\Query; use Rxn\Orm\Builder\Command; +use Rxn\Orm\Builder\Query\Join\On; use Rxn\Orm\Builder\Table; class Join extends Command @@ -35,6 +36,7 @@ public function set(string $table, callable $callable, string $alias = null, str $this->command = self::JOIN_COMMANDS[$type]; $this->addTable($table,$alias); call_user_func($callable, $this); + return $this; } public function on(string $first_operand, string $operator, $second_operand) { diff --git a/src/Rxn/Orm/Builder/Query/On.php b/src/Rxn/Orm/Builder/Query/Join/On.php similarity index 93% rename from src/Rxn/Orm/Builder/Query/On.php rename to src/Rxn/Orm/Builder/Query/Join/On.php index 747a927..ed770e5 100644 --- a/src/Rxn/Orm/Builder/Query/On.php +++ b/src/Rxn/Orm/Builder/Query/Join/On.php @@ -1,6 +1,6 @@ 'WHERE', - 'and' => 'WHERE', - 'or' => 'OR', + 'where' => 'WHERE', + 'and' => 'AND', + 'or' => 'OR', + 'in' => 'IN', + 'not in' => 'NOT IN', + 'is null' => 'IS NULL', + 'is not null' => 'IS NOT NULL', ]; const WHERE_OPERATORS = [ @@ -30,6 +34,17 @@ class Where extends Command '>=', ]; + public $command = 'WHERE'; + + public $first_operand; + public $operator; + public $second_operand; + + /** + * @var Command[] + */ + public $commands; + public function set( string $first_operand, string $operator, @@ -37,34 +52,91 @@ public function set( callable $callback = null, string $type = 'where' ) { + $this->command = self::WHERE_COMMANDS[$type]; + $this->operator = $operator; $this->validateType($type); if ($this->isReference($first_operand) && $this->isReference($second_operand) ) { - $first_operand = $this->cleanReference($first_operand); - $second_operand = $this->cleanReference($second_operand); + $this->first_operand = $this->cleanReference($first_operand); + $this->second_operand = $this->cleanReference($second_operand); } elseif ($this->isReference($first_operand) && !$this->isReference($second_operand) ) { - $first_operand = $this->cleanReference($first_operand); - list($second_operand, $bindings) = $this->getOperandBindings($second_operand); + $this->first_operand = $this->cleanReference($first_operand); + list($this->second_operand, $bindings) = $this->getOperandBindings($second_operand); $this->addBindings($bindings); } elseif (!$this->isReference($first_operand) && $this->isReference($second_operand) ) { - list($first_operand, $bindings) = $this->getOperandBindings($first_operand); + list($this->first_operand, $bindings) = $this->getOperandBindings($first_operand); $this->addBindings($bindings); - $second_operand = $this->cleanReference($second_operand); + $this->second_operand = $this->cleanReference($second_operand); } - $value = "$first_operand $operator $second_operand"; if (!is_null($callback)) { - $command = self::WHERE_COMMANDS['where']; - $this->addCommand($command, $value); call_user_func($callback, $this); - } else { - $command = self::WHERE_COMMANDS[$type]; - $this->addCommand($command, $value); } + return $this; + } + + public function and ( + string $first_operand, + string $operator, + string $second_operand, + callable $callback = null, + string $type = 'and' + ) { + $this->commands[] = (new Where())->set($first_operand, $operator, $second_operand, $callback, $type); + } + + public function or ( + string $first_operand, + string $operator, + string $second_operand, + callable $callback = null, + string $type = 'or' + ) { + $this->commands[] = (new Where())->set($first_operand, $operator, $second_operand, $callback, $type); + } + + public function in( + string $first_operand, + string $operator, + string $second_operand, + callable $callback = null, + string $type = 'in' + ) { + $this->commands[] = (new Where())->setIn($first_operand, $operator, $second_operand, $callback, $type); + } + + public function notIn( + string $first_operand, + string $operator, + string $second_operand, + callable $callback = null, + string $type = 'not in' + ) { + $this->commands[] = (new Where())->setIn($first_operand, $operator, $second_operand, $callback, $type); + } + + public function isNull( + string $first_operand, + string $operator, + string $second_operand, + callable $callback = null, + string $type = 'not in' + ) { + $this->commands[] = (new Where())->setIsNull($first_operand, $operator, $second_operand, $callback, $type); + } + + public function isNotNull( + string $first_operand, + string $operator, + string $second_operand, + callable $callback = null, + string $type = 'not in' + ) { + $this->commands[] = (new Where())->setIsNull($first_operand, $operator, $second_operand, $callback, $type); } public function setIn( @@ -87,7 +159,7 @@ public function setIn( } } - public function setNull(string $operand, callable $callback = null, string $type = 'where', $not = false) + public function setIsNull(string $operand, callable $callback = null, string $type = 'where', $not = false) { $this->validateType($type); $operand = $this->cleanReference($operand); diff --git a/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php b/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php index 77f3690..9be6f9f 100644 --- a/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php +++ b/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php @@ -18,7 +18,7 @@ public function testJoin() ->where('users.first_name', '=', 'David', function (Where $where) { $where->and('users.last_name', '=', 'Wyly'); }) - ->where('users.first_name', '=', 'Lance', function (Where $where) { + ->and('users.first_name', '=', 'Lance', function (Where $where) { $where->and('users.last_name', '=', 'Badger'); }) ->or('users.first_name2', '=', 'Joseph', function (Where $where) { From 05b3966e43271898dbef6dad6b41b0a83eb78128 Mon Sep 17 00:00:00 2001 From: David James Wyly Date: Sat, 29 Sep 2018 15:15:22 -0600 Subject: [PATCH 4/4] more progress --- src/Rxn/Orm/Builder/Command.php | 4 +- src/Rxn/Orm/Builder/Query.php | 182 ++++++------- src/Rxn/Orm/Builder/Query/From.php | 2 +- src/Rxn/Orm/Builder/Query/Join.php | 48 +++- src/Rxn/Orm/Builder/Query/Join/On.php | 14 +- src/Rxn/Orm/Builder/Query/Select.php | 9 +- src/Rxn/Orm/Builder/Query/Where.php | 256 +++++++++++-------- src/Rxn/Orm/Tests/Builder/Query/JoinTest.php | 10 +- 8 files changed, 285 insertions(+), 240 deletions(-) diff --git a/src/Rxn/Orm/Builder/Command.php b/src/Rxn/Orm/Builder/Command.php index be23a82..75a4ec1 100644 --- a/src/Rxn/Orm/Builder/Command.php +++ b/src/Rxn/Orm/Builder/Command.php @@ -9,7 +9,7 @@ abstract class Command /** * @var string */ - public $command; + protected $command; /** * @var array @@ -19,7 +19,7 @@ abstract class Command /** * @var array */ - public $bindings = []; + protected $bindings = []; protected function isAssociative(array $array) { diff --git a/src/Rxn/Orm/Builder/Query.php b/src/Rxn/Orm/Builder/Query.php index 1675e55..15579d8 100644 --- a/src/Rxn/Orm/Builder/Query.php +++ b/src/Rxn/Orm/Builder/Query.php @@ -24,7 +24,7 @@ class Query extends Builder */ public function select(array $columns = ['*'], $distinct = false): Query { - $this->commands[] = (new Select())->set($columns, $distinct); + $this->commands[] = (new Select())->select($columns, $distinct); return $this; } @@ -36,7 +36,7 @@ public function select(array $columns = ['*'], $distinct = false): Query */ public function from(string $table, string $alias = null): Query { - $this->commands[] = (new From())->set($table, $alias); + $this->commands[] = (new From())->from($table, $alias); return $this; } @@ -51,16 +51,17 @@ public function from(string $table, string $alias = null): Query */ public function joinCustom(string $table, callable $callable, string $alias = null, string $type = 'inner'): Query { - $this->commands[] = (new Join())->set($table, $callable, $alias, $type); + $this->commands[] = (new Join())->join($table, $callable, $alias, $type); return $this; } /** - * @param string $table - * @param string $first_operand - * @param string $operator - * @param string|array $second_operand - * @param string $alias + * @param string $table + * @param string $operand_1 + * @param string $operator + * @param string|array $operand_2 + * @param string $alias + * @param callable|null $callback * * @return Query * @throws \Exception @@ -68,68 +69,76 @@ public function joinCustom(string $table, callable $callable, string $alias = nu */ public function join( string $table, - string $first_operand, + string $operand_1, string $operator, - $second_operand, - string $alias = null + $operand_2, + string $alias = null, + callable $callback = null ): Query { - return $this->innerJoin($table, $first_operand, $operator, $second_operand, $alias); + return $this->innerJoin($table, $operand_1, $operator, $operand_2, $alias, $callback); } /** - * @param string $table - * @param string $first_operand - * @param string $operator - * @param string|array $second_operand - * @param string|null $alias + * @param string $table + * @param string $operand_1 + * @param string $operator + * @param string|array $operand_2 + * @param string|null $alias + * @param callable|null $callback * * @return Query * @throws \Exception */ public function innerJoin( string $table, - string $first_operand, + string $operand_1, string $operator, - $second_operand, - string $alias = null + $operand_2, + string $alias = null, + callable $callback = null ): Query { return $this->joinCustom($table, - function (Join $join) use ($first_operand, $operator, $second_operand, $alias) { - $join->on($first_operand, $operator, $second_operand); + function (Join $join) use ($operand_1, $operator, $operand_2, $alias, $callback) { + $join->on($operand_1, $operator, $operand_2); + if (!is_null($callback)) { + call_user_func($callback, $join); + } }, $alias, 'inner'); } /** - * @param string $table - * @param string $first_operand - * @param string $operator - * @param string|array $second_operand - * @param string $alias + * @param string $table + * @param string $operand_1 + * @param string $operator + * @param string|array $operand_2 + * @param string $alias + * @param callable|null $callback * * @return Query * @throws \Exception */ public function leftJoin( string $table, - string $first_operand, + string $operand_1, string $operator, - $second_operand, - string $alias + $operand_2, + string $alias, + callable $callback = null ): Query { return $this->joinCustom($table, - function (Join $join) use ($first_operand, $operator, $second_operand, $alias) { - if (!empty($alias)) { - $join->as($alias); + function (Join $join) use ($operand_1, $operator, $operand_2, $alias, $callback) { + $join->on($operand_1, $operator, $operand_2); + if (!is_null($callback)) { + call_user_func($callback, $join); } - $join->on($first_operand, $operator, $second_operand); }, $alias, 'left'); } /** * @param string $table - * @param string $first_operand + * @param string $operand_1 * @param string $operator - * @param string|array $second_operand + * @param string|array $operand_2 * @param string $alias * * @return Query @@ -137,18 +146,14 @@ function (Join $join) use ($first_operand, $operator, $second_operand, $alias) { */ public function rightJoin( string $table, - string $first_operand, + string $operand_1, string $operator, - $second_operand, + $operand_2, string $alias ): Query { - return $this->joinCustom($table, - function (Join $join) use ($first_operand, $operator, $second_operand, $alias) { - if (!empty($alias)) { - $join->as($alias); - } - $join->on($first_operand, $operator, $second_operand); - }, $alias, 'right'); + return $this->joinCustom($table, function (Join $join) use ($operand_1, $operator, $operand_2, $alias) { + $join->on($operand_1, $operator, $operand_2); + }, $alias, 'right'); } /** @@ -181,54 +186,30 @@ public function whereId($id, string $id_key = 'id', callable $callback = null, s } public function where( - string $first_operand, + string $operand_1, string $operator, - string $second_operand, + string $operand_2, callable $callback = null, string $type = 'where' ): Query { - $where = new Where(); - $where->set($first_operand, $operator, $second_operand, $callback, $type); - $this->commands[] = $where; - $this->loadBindings($where); + $this->commands[] = (new Where())->where($operand_1, $operator, $operand_2, $callback, $type); return $this; } - /** - * @param string $operand - * @param array $values - * @param callable|null $callback - * @param string $type - * @param bool $not - * - * @return Query - */ public function whereIn( string $operand, - array $values, + array $operands, callable $callback = null, string $type = 'where', $not = false ) { - $where = new Where(); - $where->setIn($operand, $values, $callback, $type, $not); - $this->loadCommands($where); - $this->loadBindings($where); + $this->commands[] = (new Where())->in($operand, $operands, $callback, $type, $not); return $this; } - /** - * @param string $operand - * @param string|array $values - * @param callable|null $callback - * @param string $type - * - * @return Query - * @throws \Exception - */ - public function whereNotIn(string $operand, array $values, callable $callback = null, string $type = 'where') + public function whereNotIn(string $operand, array $operands, callable $callback = null, string $type = 'where') { - return $this->whereIn($operand, $values, $callback, $type, true); + return $this->whereIn($operand, $operands, $callback, $type, true); } /** @@ -241,10 +222,7 @@ public function whereNotIn(string $operand, array $values, callable $callback = */ public function whereIsNull(string $operand, callable $callback = null, $type = 'where', $not = false) { - $where = new Where(); - $where->setNull($operand, $callback, $type, $not); - $this->loadCommands($where); - $this->loadBindings($where); + $this->commands[] = (new Where())->isNull($operand, $callback, $type, $not); return $this; } @@ -261,37 +239,29 @@ public function whereIsNotNull(string $operand, callable $callback = null, $type } /** - * @param string $first_operand + * @param string $operand_1 * @param string $operator - * @param string $second_operand + * @param string $operand_2 * @param callable|null $callback * * @return Query */ - public function and ( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null - ): Query { - return $this->andWhere($first_operand, $operator, $second_operand, $callback); + public function and (string $operand_1, string $operator, string $operand_2, callable $callback = null): Query + { + return $this->andWhere($operand_1, $operator, $operand_2, $callback); } /** - * @param string $first_operand + * @param string $operand_1 * @param string $operator - * @param string $second_operand + * @param string $operand_2 * @param callable|null $callback * * @return Query */ - public function andWhere( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null - ): Query { - return $this->where($first_operand, $operator, $second_operand, $callback, 'and'); + public function andWhere(string $operand_1, string $operator, string $operand_2, callable $callback = null): Query + { + return $this->where($operand_1, $operator, $operand_2, $callback, 'and'); } /** @@ -342,29 +312,29 @@ public function andWhereIsNotNull(string $operand, callable $callback = null) } /** - * @param string $first_operand + * @param string $operand_1 * @param string $operator - * @param $second_operand + * @param $operand_2 * @param callable|null $callback * * @return Query */ - public function or (string $first_operand, string $operator, $second_operand, callable $callback = null): Query + public function or (string $operand_1, string $operator, $operand_2, callable $callback = null): Query { - return $this->orWhere($first_operand, $operator, $second_operand, $callback); + return $this->orWhere($operand_1, $operator, $operand_2, $callback); } /** - * @param string $first_operand + * @param string $operand_1 * @param string $operator - * @param $second_operand + * @param $operand_2 * @param callable|null $callback * * @return Query */ - public function orWhere(string $first_operand, string $operator, $second_operand, callable $callback = null): Query + public function orWhere(string $operand_1, string $operator, $operand_2, callable $callback = null): Query { - return $this->where($first_operand, $operator, $second_operand, $callback, 'or'); + return $this->where($operand_1, $operator, $operand_2, $callback, 'or'); } /** diff --git a/src/Rxn/Orm/Builder/Query/From.php b/src/Rxn/Orm/Builder/Query/From.php index 4878901..3319d54 100644 --- a/src/Rxn/Orm/Builder/Query/From.php +++ b/src/Rxn/Orm/Builder/Query/From.php @@ -7,7 +7,7 @@ class From extends Command { - public function set(string $table, string $alias = null, $database = null) + public function from(string $table, string $alias = null, $database = null) { $this->command = 'FROM'; $this->addTable($table, $alias, $database); diff --git a/src/Rxn/Orm/Builder/Query/Join.php b/src/Rxn/Orm/Builder/Query/Join.php index 8106d8a..55ed1c1 100644 --- a/src/Rxn/Orm/Builder/Query/Join.php +++ b/src/Rxn/Orm/Builder/Query/Join.php @@ -29,26 +29,58 @@ class Join extends Command */ public $commands; - public function set(string $table, callable $callable, string $alias = null, string $type = 'inner') { + /** + * @param string $table + * @param callable $callable + * @param string|null $alias + * @param string $type + * + * @return $this + * @throws \Exception + */ + public function join(string $table, callable $callable, string $alias = null, string $type = 'inner') + { if (!array_key_exists($type, self::JOIN_COMMANDS)) { throw new \Exception(""); } $this->command = self::JOIN_COMMANDS[$type]; - $this->addTable($table,$alias); + $this->addTable($table, $alias); call_user_func($callable, $this); return $this; } - public function on(string $first_operand, string $operator, $second_operand) { - $command = new On($first_operand, $operator, $second_operand); + public function on(string $operand_1, string $operator, $operand_2) + { + $command = new On($operand_1, $operator, $operand_2); $this->commands[] = $command; return $this; } - public function where(string $first_operand, string $operator, $second_operand) { - $command = new Where(); - $command->set($first_operand,$operator,$second_operand); - $this->commands[] = $command; + public function where( + string $operand_1, + string $operator, + string $operand_2, + string $type = 'and', + callable $callback = null + ): Command { + $this->commands[] = (new Where())->where($operand_1, $operator, $operand_2, $callback, $type); + return $this; + } + + public function whereIn( + string $operand, + array $operands, + string $type = 'and', + $not = false, + callable $callback = null + ) { + $this->commands[] = (new Where())->in($operand, $operands, $callback, $type, $not); + return $this; + } + + public function whereIsNull(string $operand, $type = 'and', $not = false, callable $callback = null) + { + $this->commands[] = (new Where())->isNull($operand, $callback, $type, $not); return $this; } diff --git a/src/Rxn/Orm/Builder/Query/Join/On.php b/src/Rxn/Orm/Builder/Query/Join/On.php index ed770e5..9241f99 100644 --- a/src/Rxn/Orm/Builder/Query/Join/On.php +++ b/src/Rxn/Orm/Builder/Query/Join/On.php @@ -8,16 +8,16 @@ class On extends Command { public $command = 'ON'; - public $first_operand; + public $operand_1; public $operator; - public $second_operand; + public $operand_2; - public function __construct(string $first_operand, $operator, $second_operand) + public function __construct(string $operand_1, $operator, $operand_2) { - $this->first_operand = $first_operand; + $this->operand_1 = $operand_1; $this->operator = $operator; - $this->second_operand = $second_operand; - $this->addColumn($first_operand); - $this->addColumn($second_operand); + $this->operand_2 = $operand_2; + $this->addColumn($operand_1); + $this->addColumn($operand_2); } } diff --git a/src/Rxn/Orm/Builder/Query/Select.php b/src/Rxn/Orm/Builder/Query/Select.php index 5240524..568f14d 100644 --- a/src/Rxn/Orm/Builder/Query/Select.php +++ b/src/Rxn/Orm/Builder/Query/Select.php @@ -11,7 +11,13 @@ class Select extends Command */ public $command; - public function set(array $columns = ['*'], $distinct = false) + /** + * @param array $columns + * @param bool $distinct + * + * @return $this + */ + public function select(array $columns = ['*'], $distinct = false) { if ($columns === ['*'] || empty($columns) @@ -32,7 +38,6 @@ public function selectAll($distinct = false) { $this->command = ($distinct) ? 'SELECT DISTINCT' : 'SELECT'; $this->addColumn('*'); - $this->addClause('*'); } /** diff --git a/src/Rxn/Orm/Builder/Query/Where.php b/src/Rxn/Orm/Builder/Query/Where.php index 29a2b36..7d4e672 100644 --- a/src/Rxn/Orm/Builder/Query/Where.php +++ b/src/Rxn/Orm/Builder/Query/Where.php @@ -8,21 +8,15 @@ class Where extends Command { const WHERE_COMMANDS = [ - 'where' => 'WHERE', - 'and' => 'AND', - 'or' => 'OR', - 'in' => 'IN', - 'not in' => 'NOT IN', - 'is null' => 'IS NULL', - 'is not null' => 'IS NOT NULL', + 'where' => 'WHERE', + 'and' => 'AND', + 'or' => 'OR', ]; const WHERE_OPERATORS = [ '=', '!=', '<>', - 'IN', - 'NOT IN', 'LIKE', 'NOT LIKE', 'BETWEEN', @@ -34,153 +28,191 @@ class Where extends Command '>=', ]; - public $command = 'WHERE'; + protected $command = 'WHERE'; - public $first_operand; - public $operator; - public $second_operand; + /** + * @var string + */ + protected $operand_1; + + /** + * @var string + */ + protected $operator; + + /** + * @var string|array + */ + protected $operand_2; /** * @var Command[] */ - public $commands; + protected $commands; - public function set( - string $first_operand, + /** + * @param string $operand_1 + * @param string $operator + * @param string $operand_2 + * @param callable|null $callback + * @param string $type + * + * @return $this + * @throws \Exception + */ + public function where( + string $operand_1, string $operator, - string $second_operand, + string $operand_2, callable $callback = null, string $type = 'where' - ) { - $this->command = self::WHERE_COMMANDS[$type]; - $this->operator = $operator; + ): Where { $this->validateType($type); - if ($this->isReference($first_operand) - && $this->isReference($second_operand) - ) { - $this->first_operand = $this->cleanReference($first_operand); - $this->second_operand = $this->cleanReference($second_operand); - } elseif ($this->isReference($first_operand) - && !$this->isReference($second_operand) - ) { - $this->first_operand = $this->cleanReference($first_operand); - list($this->second_operand, $bindings) = $this->getOperandBindings($second_operand); + $this->validateOperator($operator); + + $this->command = self::WHERE_COMMANDS[$type]; + + if ($this->isReference($operand_1)) { + $this->operand_1 = $this->cleanReference($operand_1); + } else { + list($this->operand_1, $bindings) = $this->getOperandBindings($operand_1); $this->addBindings($bindings); - } elseif (!$this->isReference($first_operand) - && $this->isReference($second_operand) - ) { - list($this->first_operand, $bindings) = $this->getOperandBindings($first_operand); + } + + $this->operator = $operator; + + if ($this->isReference($operand_2)) { + $this->operand_2 = $this->cleanReference($operand_2); + } else { + list($this->operand_2, $bindings) = $this->getOperandBindings($operand_2); $this->addBindings($bindings); - $this->second_operand = $this->cleanReference($second_operand); } + if (!is_null($callback)) { call_user_func($callback, $this); } return $this; } - public function and ( - string $first_operand, - string $operator, - string $second_operand, + public function in( + string $operand, + array $operands, callable $callback = null, - string $type = 'and' - ) { - $this->commands[] = (new Where())->set($first_operand, $operator, $second_operand, $callback, $type); + $type = 'where', + $not = false + ): Where { + $this->validateType($type); + $this->command = self::WHERE_COMMANDS[$type]; + $this->operand_1 = $this->cleanReference($operand); + $this->operator = ($not) ? 'NOT IN' : 'IN'; + + $cleaned_operands = []; + foreach ($operands as $key => $unclean_operand) { + if ($this->isReference($unclean_operand)) { + $cleaned_operands[$key] = $this->cleanReference($unclean_operand); + } else { + $cleaned_operands[$key] = $unclean_operand; + } + } + $this->operand_2 = $cleaned_operands; + + if (!is_null($callback)) { + call_user_func($callback, $this); + } + return $this; } - public function or ( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null, - string $type = 'or' - ) { - $this->commands[] = (new Where())->set($first_operand, $operator, $second_operand, $callback, $type); + public function isNull(string $operand, callable $callback = null, $type = 'where', $not = false): Where + { + $this->validateType($type); + $this->command = self::WHERE_COMMANDS[$type]; + $this->operand_1 = $this->cleanReference($operand); + $this->operator = ($not) ? 'IS NOT NULL' : 'IS NULL'; + + if (!is_null($callback)) { + call_user_func($callback, $this); + } + return $this; } - public function in( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null, - string $type = 'in' - ) { - $this->commands[] = (new Where())->setIn($first_operand, $operator, $second_operand, $callback, $type); + public function and (string $operand_1, string $operator, string $operand_2, callable $callback = null): Where + { + $this->commands[] = (new Where())->where($operand_1, $operator, $operand_2, $callback, 'and'); + return $this; } - public function notIn( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null, - string $type = 'not in' - ) { - $this->commands[] = (new Where())->setIn($first_operand, $operator, $second_operand, $callback, $type); + public function andIn(string $operand, array $operands, callable $callback = null): Where + { + $this->commands[] = (new Where())->in($operand, $operands, $callback, 'and', false); + return $this; } - public function isNull( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null, - string $type = 'not in' - ) { - $this->commands[] = (new Where())->setIsNull($first_operand, $operator, $second_operand, $callback, $type); + public function andNotIn(string $operand, array $operands, callable $callback = null): Where + { + $this->commands[] = (new Where())->in($operand, $operands, $callback, 'and', true); + return $this; } - public function isNotNull( - string $first_operand, - string $operator, - string $second_operand, - callable $callback = null, - string $type = 'not in' - ) { - $this->commands[] = (new Where())->setIsNull($first_operand, $operator, $second_operand, $callback, $type); + public function andIsNull(string $operand, callable $callback = null): Where + { + $this->commands[] = (new Where())->isNull($operand, $callback, 'and', false); + return $this; } - public function setIn( - string $operand, - array $values, - callable $callback = null, - string $type = 'where', - $not = false - ) { - $this->validateType($type); - $operand = $this->cleanReference($operand); - $operator = ($not) ? 'NOT IN' : 'IN'; - list($value_list, $bindings) = $this->getOperandBindings($values); - $value = "$operand $operator $value_list"; - $command = self::WHERE_COMMANDS[$type]; - $this->addCommand($command, $value); - $this->addBindings($bindings); - if (!is_null($callback)) { - call_user_func($callback, $this); - } + public function andIsNotNull(string $operand, callable $callback = null): Where + { + $this->commands[] = (new Where())->isNull($operand, $callback, 'and', true); + return $this; } - public function setIsNull(string $operand, callable $callback = null, string $type = 'where', $not = false) + public function or (string $operand_1, string $operator, string $operand_2, callable $callback = null): Where { - $this->validateType($type); - $operand = $this->cleanReference($operand); - $operator = ($not) ? 'IS NOT NULL' : 'IS NULL'; - $value = "$operand $operator"; - $command = self::WHERE_COMMANDS[$type]; - $this->addCommand($command, $value); - if (!is_null($callback)) { - call_user_func($callback, $this); - } + $this->commands[] = (new Where())->where($operand_1, $operator, $operand_2, $callback, 'or'); + return $this; + } + + public function orIn(string $operand, array $operands, callable $callback = null): Where + { + $this->commands[] = (new Where())->in($operand, $operands, $callback, 'or', false); + return $this; + } + + public function orNotIn(string $operand, array $operands, callable $callback = null): Where + { + $this->commands[] = (new Where())->in($operand, $operands, $callback, 'or', true); + return $this; + } + + public function orIsNull(string $operand, callable $callback = null): Where + { + $this->commands[] = (new Where())->isNull($operand, $callback, 'or', false); + return $this; + } + + public function orIsNotNull(string $operand, callable $callback = null): Where + { + $this->commands[] = (new Where())->isNull($operand, $callback, 'or', true); + return $this; } private function validateType($type) { if (!array_key_exists($type, self::WHERE_COMMANDS)) { - throw new \Exception(""); + throw new \Exception("'$type' is not a valid WHERE command"); } } - private function isReference($operand) + private function validateOperator($operator) { + if (!in_array($operator, self::WHERE_OPERATORS)) { + throw new \Exception("'$operator' is not a valid WHERE operator"); + } + } + + private function isReference($operand): bool { + if (!is_string($operand)) { + return false; + } $result = explode('.', $operand); if (isset($result[1])) { return true; diff --git a/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php b/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php index 9be6f9f..3d80d93 100644 --- a/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php +++ b/src/Rxn/Orm/Tests/Builder/Query/JoinTest.php @@ -4,6 +4,7 @@ use PHPUnit\Framework\TestCase; use Rxn\Orm\Builder\Query; +use Rxn\Orm\Builder\Query\Join; use Rxn\Orm\Builder\Query\Where; final class JoinTest extends TestCase @@ -12,11 +13,16 @@ public function testJoin() { $query = new Query(); $query->select(['users.id' => 'user_id']) - ->from('users','o') - ->join('orders', 'orders.user_id', '=', 'users.id', 'o') + ->from('users', 'o') + ->leftJoin('orders', 'orders.user_id', '=', 'users.id', 'o', function (Join $join) { + $join->whereIsNull('users.test2','and',true, function (Where $where) { + $where->orIsNotNull('users.test3'); + }); + }) ->join('invoices', 'invoices.id', '=', 'orders.invoice_id', 'i') ->where('users.first_name', '=', 'David', function (Where $where) { $where->and('users.last_name', '=', 'Wyly'); + $where->andIn('users.type', [1, 2, 3]); }) ->and('users.first_name', '=', 'Lance', function (Where $where) { $where->and('users.last_name', '=', 'Badger');