diff --git a/README.md b/README.md index 1376cbe..63de53f 100644 --- a/README.md +++ b/README.md @@ -262,19 +262,6 @@ namespace App\Model; class Posts extends \InitPHP\Database\Model { - /** - * Only if you don't have global connectivity. - * - * @var array|string[] - */ - protected array $connection = [ - 'dsn' => '', // Database connection address. - 'username' => '', // Username with required privileges in the database. - 'password' => '', // The password of the database user. - 'charset' => 'utf8mb4', // The character set to use in the database. - 'collation' => 'utf8mb4_general_ci', // Collection set to use in database - ]; - /** * If not specified, \InitPHP\Database\Entity::class is used by default. * diff --git a/src/Database.php b/src/Database.php index 3e56981..d032133 100644 --- a/src/Database.php +++ b/src/Database.php @@ -7,7 +7,7 @@ * @author Muhammet ŞAFAK * @copyright Copyright © 2022 Muhammet ŞAFAK * @license ./LICENSE MIT - * @version 2.0.7 + * @version 2.1 * @link https://www.muhammetsafak.com.tr */ @@ -295,29 +295,6 @@ final public function escape_str($value) return false; } - /** - * @param string $key - * @param string|int|float|bool|null $value - * @return $this - */ - final public function setParameter(string $key, $value): self - { - Parameters::set($key, $value); - return $this; - } - - /** - * @param array $parameters - * @return $this - */ - final public function setParameters(array $parameters = []): self - { - foreach ($parameters as $key => $value) { - Parameters::set($key, $value); - } - return $this; - } - /** * @param string $sqlQuery * @param array $parameters @@ -358,7 +335,7 @@ final public function query(string $sqlQuery, array $parameters = []): Result case self::ARRAY: return $this->_last->asArray(); case self::ENTITY: - return $this->_last->asEntity(); + return $this->_last->asEntity($this->_credentials['entity'] ?? Entity::class); case self::OBJECT: return $this->_last->asObject(); case self::LAZY: diff --git a/src/Entity.php b/src/Entity.php index b5db202..fbbd912 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -18,9 +18,9 @@ class Entity { - private array $_Attributes = []; + protected array $__attributes = []; - private array $_OriginalAttributes = []; + protected array $__attributesOriginal = []; public function __construct(?array $data = []) { @@ -35,10 +35,10 @@ public function __call($name, $arguments) switch (\substr($name, 0, 3)) { case 'get': $attr = Helper::camelCaseToSnakeCase(\substr($name, 3, -9)); - return $this->_Attributes[$attr] ?? null; + return $this->__attributes[$attr] ?? null; case 'set': $attr = Helper::camelCaseToSnakeCase(\substr($name, 3, -9)); - return $this->_Attributes[$attr] = $arguments[0]; + return $this->__attributes[$attr] = $arguments[0]; default: throw new \RuntimeException('There is no "' . $name . '" method.'); } @@ -51,7 +51,7 @@ public function __set($name, $value) $this->{$methodName}($value); return $value; } - return $this->_Attributes[$name] = $value; + return $this->__attributes[$name] = $value; } public function __get($name) @@ -60,29 +60,29 @@ public function __get($name) if(\method_exists($this, $methodName)){ return $this->{$methodName}(); } - return $this->_Attributes[$name] ?? null; + return $this->__attributes[$name] ?? null; } public function __isset($name) { - return isset($this->_Attributes[$name]); + return isset($this->__attributes[$name]); } public function __unset($name) { - if(isset($this->_Attributes[$name])){ - unset($this->_Attributes[$name]); + if(isset($this->__attributes[$name])){ + unset($this->__attributes[$name]); } } public function __debugInfo() { - return $this->_Attributes; + return $this->__attributes; } public function toArray(): array { - return $this->_Attributes; + return $this->__attributes; } public function getAttributes(): array @@ -109,7 +109,7 @@ protected function fill(?array $data = null): self protected function syncOriginal(): self { - $this->_OriginalAttributes = $this->_Attributes; + $this->__attributesOriginal = $this->__attributes; return $this; } diff --git a/src/Helpers/Helper.php b/src/Helpers/Helper.php index 1984bc5..763b866 100644 --- a/src/Helpers/Helper.php +++ b/src/Helpers/Helper.php @@ -7,7 +7,7 @@ * @author Muhammet ŞAFAK * @copyright Copyright © 2022 Muhammet ŞAFAK * @license ./LICENSE MIT - * @version 2.0.8 + * @version 2.1 * @link https://www.muhammetsafak.com.tr */ @@ -59,7 +59,7 @@ public static function isSQLParameterOrFunction($value): bool return ((\is_string($value)) && ( $value === '?' || (bool)\preg_match('/^:[\w]+$/', $value) - || (bool)\preg_match('/^[a-zA-Z_\.]+$/', $value) + || (bool)\preg_match('/^[a-zA-Z_]+[\.]+[a-zA-Z_]+$/', $value) || (bool)\preg_match('/^[a-zA-Z_]+\(\)$/', $value) )) || ($value instanceof Raw) || \is_int($value); } diff --git a/src/Model.php b/src/Model.php index da8d38c..1c67637 100644 --- a/src/Model.php +++ b/src/Model.php @@ -7,9 +7,10 @@ * @author Muhammet ŞAFAK * @copyright Copyright © 2022 Muhammet ŞAFAK * @license ./LICENSE MIT - * @version 2.0.8 + * @version 2.1 * @link https://www.muhammetsafak.com.tr */ +declare(strict_types=1); namespace InitPHP\Database; @@ -226,6 +227,7 @@ public function __construct() $credentials['updatable'] = $this->updatable ?? true; $credentials['deletable'] = $this->deletable ?? true; $credentials['writable'] = $this->writable ?? true; + $credentials['return'] = $this->return ?? self::ENTITY; parent::__construct($credentials); } diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php index 659c1da..780509c 100644 --- a/src/QueryBuilder.php +++ b/src/QueryBuilder.php @@ -7,16 +7,15 @@ * @author Muhammet ŞAFAK * @copyright Copyright © 2022 Muhammet ŞAFAK * @license ./LICENSE MIT - * @version 2.0.8 + * @version 2.1 * @link https://www.muhammetsafak.com.tr */ +declare(strict_types=1); namespace InitPHP\Database; -use InitPHP\Database\Helpers\{Helper, Parameters, Validation}; -use InitPHP\Database\Exceptions\QueryBuilderException; -use InitPHP\Database\Exceptions\QueryGeneratorException; -use \InitPHP\Database\Exceptions\ValueException; +use \InitPHP\Database\Helpers\{Helper, Parameters}; +use \InitPHP\Database\Exceptions\{QueryBuilderException, QueryGeneratorException, ValueException}; class QueryBuilder { @@ -65,6 +64,29 @@ public function exportQB(): array return $this->_STRUCTURE; } + /** + * @param string $key + * @param string|int|float|bool|null $value + * @return $this + */ + final public function setParameter(string $key, $value): self + { + Parameters::set($key, $value); + return $this; + } + + /** + * @param array $parameters + * @return $this + */ + final public function setParameters(array $parameters = []): self + { + foreach ($parameters as $key => $value) { + Parameters::set($key, $value); + } + return $this; + } + /** * @param string|Raw ...$columns * @return $this @@ -368,7 +390,7 @@ final public function join($table, $onStmt = null, string $type = 'INNER'): self $this->_STRUCTURE['join'][$table] = 'NATURAL JOIN ' . $table; break; default: - $this->_STRUCTURE['join'][$table] = $type . ' JOIN ' . $table . ' ON ' . $onStmt; + $this->_STRUCTURE['join'][$table] = \trim(($type . ' JOIN ' . $table . ' ON ' . $onStmt)); } return $this; } @@ -1124,6 +1146,23 @@ final public function raw(string $rawQuery): Raw return new Raw($rawQuery); } + final public function subQuery(\Closure $closure, ?string $alias = null, bool $isIntervalQuery = true): Raw + { + $queryBuilder = new self(); + \call_user_func_array($closure, [$queryBuilder]); + + if ($alias !== null && $isIntervalQuery !== TRUE) { + throw new QueryBuilderException('To define alias to a subquery, it must be an inner query.'); + } + + $rawQuery = ($isIntervalQuery === TRUE ? '(' : '') + . $queryBuilder->generateSelectQuery() + . ($isIntervalQuery === TRUE ? ')' : '') + . ($alias !== null ? ' AS ' . $alias : ''); + + return $this->raw($rawQuery); + } + final public function generateInsertQuery(): string { if (!empty($this->_STRUCTURE['table'])) { @@ -1533,7 +1572,7 @@ private function whereOrHavingStatementPrepare($column, $value, string $mark = ' } $values[] = Helper::isSQLParameterOrFunction($val) ? $val : Parameters::add($column, $val); } - $value = \implode(', ', \array_unique($values)); + $value = '(' . \implode(', ', \array_unique($values)) . ')'; } elseif (Helper::isSQLParameterOrFunction($value)) { $value = (string)$value; }else{ @@ -1541,7 +1580,7 @@ private function whereOrHavingStatementPrepare($column, $value, string $mark = ' } return $column . ($searchMark === 'NOTIN' ? ' NOT ' : ' ') - . 'IN (' . $value . ')'; + . 'IN ' . $value; case 'FINDINSET': case 'NOTFINDINSET': if(\is_array($value)){ diff --git a/tests/QueryBuilderUnitTest.php b/tests/QueryBuilderUnitTest.php index 230e384..ee1bc94 100644 --- a/tests/QueryBuilderUnitTest.php +++ b/tests/QueryBuilderUnitTest.php @@ -420,4 +420,33 @@ public function testJoinClosureGive() $this->db->reset(); } + public function testSubQuery() + { + Parameters::reset(); + $this->db->select('u.name') + ->from('users AS u') + ->in('u.id', $this->db->subQuery(function (QueryBuilder $builder) { + $builder->select('id') + ->from('roles') + ->where('name', 'admin'); + })); + $expected = 'SELECT u.name FROM users AS u WHERE u.id IN (SELECT id FROM roles WHERE name = :name)'; + $this->assertEquals($expected, $this->db->generateSelectQuery()); + $this->db->reset(); + + + Parameters::reset(); + $this->db->select('u.name, p.title') + ->from('users AS u') + ->join($this->db->subQuery(function (QueryBuilder $builder) { + $builder->select('id, title, user_id') + ->from('posts') + ->where('user_id', 5); + }, 'p'), 'p.user_id = u.id', ''); + + $expected = 'SELECT u.name, p.title FROM users AS u JOIN (SELECT id, title, user_id FROM posts WHERE user_id = 5) AS p ON p.user_id = u.id WHERE 1'; + $this->assertEquals($expected, $this->db->generateSelectQuery()); + $this->db->reset(); + } + }