diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 0f0c189..0000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,20 +0,0 @@ -## Versions - - * Laravel: Run `php artisan --version` to show the version. - * PHP: Run `php --version` to show the version. - * Composer: Run `composer --version` to show the version. - * uepg/laravel-sybase: Get the version in `composer.lock`. - -## Expected behavior - -What should have happened? Please include as much detail as possible. - -## Actual behavior - -What actually happened? Please include as much detail as possible. - -## Steps to reproduce - -1. Step 1 -1. Step 2 -1. Step 3 diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md new file mode 100644 index 0000000..0d3d9bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -0,0 +1,39 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: nunomazer + +--- + +## Describe the bug + +A clear and concise description of what the bug is. + +## To Reproduce + +Steps to reproduce the behavior: +1. Step 01 +1. Step 02 +1. Step 03 +1. See error + +## Expected behavior + +A clear and concise description of what you expected to happen. + +## Screenshots + +If applicable, add screenshots to help explain your problem. If no have screenshots, delete the section `Screenshots`. + +## Versions + +* Laravel: Run `php artisan --version` to show the version. +* PHP: Run `php --version` to show the version. +* Composer: Run `composer --version` to show the version. +* uepg/laravel-sybase: Get the version in `composer.lock`. + +## Additional context + +Add any other context about the problem here. If no have additional information, delete the section `Additional information`. diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000..428ab72 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,24 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: nunomazer + +--- + +## Is your feature request related to a problem? Please describe. + +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. If no have alternatives, delete the section `Describe alternatives you've considered`. + +## Additional context + +Add any other context or screenshots about the feature request here. If no have additional information, delete the section `Additional information`. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index dcf3fa1..a941f26 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,14 @@ ## Changes - * Feature 1 - * Feature 2 - * Change 1 - * Change 2 - * Change 3 - * Deletion 1 - * Fix #123 - * ... +* Feature 1 +* Feature 2 +* Change 1 +* Change 2 +* Change 3 +* Deletion 1 +* Fix #123 +* ... + +## Additional information + +If no have additional information, delete the section `Additional information`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e6ac23..78d0310 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,6 @@ Fix #48, it was breaking extension - @nunomazer It's not necessary, no new behavior, ref #48 - @nunomazer - - ## [2.2 (2019-05-13)](https://github.com/uepg/laravel-sybase/compare/2.1.2...2.2) Merge pull request [#47](https://github.com/uepg/laravel-sybase/pull/47) from afgloeden/master diff --git a/README.md b/README.md index 394f5ef..42608cd 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Add the following entry to your aliases array in **config/app.php** file, option 'UepgBlueprint' => Uepg\LaravelSybase\Database\Schema\Blueprint::class, ``` -Update your **config/database.php's** default driver with the settings for the **sqlsrv** or your custom odbc. See the following example: +Update your **config/database.php's** default driver with the settings for the **sybase** or your custom odbc. See the following example: ```php getDriverName() === 'sqlsrv') { return parent::transaction($callback); } + $this->pdo->exec('BEGIN TRAN'); + // We'll simply execute the given callback within a try / catch block // and if we catch any exception we can rollback the transaction // so that none of the changes are persisted to the database. try { $result = $callback($this); + $this->pdo->exec('COMMIT TRAN'); } + // If we catch an exception, we will roll back so nothing gets messed // up in the database. Then we'll re-throw the exception so it can // be handled how the developer sees fit for their applications. catch (Exception $e) { $this->pdo->exec('ROLLBACK TRAN'); + throw $e; } + return $result; } @@ -109,32 +115,48 @@ protected function getDoctrineDriver() return new DoctrineDriver; } + /** + * Compile for select. + * + * @param \Illuminate\Database\Query\Builder $builder + * @param array $bindings + * @return array + */ private function compileForSelect(Builder $builder, $bindings) { $arrTables = []; + array_push($arrTables, $builder->from); + if (!empty($builder->joins)) { foreach ($builder->joins as $join) { array_push($arrTables, $join->table); } } + $newFormat = []; + foreach ($arrTables as $tables) { preg_match( "/(?:(?'table'.*)(?: as )(?'alias'.*))|(?'tables'.*)/", $tables, $alias ); + if (empty($alias['alias'])) { $tables = $alias['tables']; } else { $tables = $alias['table']; } + $queryString = $this->queryStringForSelect($tables); + $queryRes = $this->getPdo()->query($queryString); + $types[$tables] = $queryRes->fetchAll(PDO::FETCH_NAMED); foreach ($types[$tables] as &$row) { $tipos[strtolower($row['name'])] = $row['type']; + $tipos[strtolower($tables . '.' . $row['name'])] = $row['type']; if (!empty($alias['alias'])) { @@ -148,7 +170,7 @@ private function compileForSelect(Builder $builder, $bindings) { foreach ($builder->wheres as $w) { switch ($w['type']) { - case "Nested": + case 'Nested': $wheres += $w['query']->wheres; break; default: @@ -158,6 +180,7 @@ private function compileForSelect(Builder $builder, $bindings) { } $i = 0; + $wheresCount = count($wheres); for ($ind = 0; $ind < $wheresCount; $ind++) { @@ -182,6 +205,7 @@ private function compileForSelect(Builder $builder, $bindings) { } else { $newBinds[$i] = (string) $bindings[$i]; } + $i++; } } @@ -191,7 +215,9 @@ private function compileForSelect(Builder $builder, $bindings) { } $wheres = (array) $builder->wheres; + $i = 0; + $wheresCount = count($wheres); for ($ind = 0; $ind < $wheresCount; $ind++) { @@ -213,6 +239,7 @@ private function compileForSelect(Builder $builder, $bindings) { } else { $newBinds[$i] = (string) $bindings[$i]; } + $i++; } } @@ -221,9 +248,16 @@ private function compileForSelect(Builder $builder, $bindings) { return $newBinds; } + /** + * Query string for select. + * + * @param string $tables + * @return string + */ private function queryStringForSelect($tables) { $explicitDB = explode('..', $tables); + if (isset($explicitDB[1])) { return " SELECT @@ -281,8 +315,8 @@ private function queryStringForSelect($tables) * Set new bindings with specified column types to Sybase. * * @param string $query - * @param array $bindings - * @return mixed $newBinds + * @param array $bindings + * @return mixed $newBinds */ private function compileBindings($query, $bindings) { @@ -291,31 +325,32 @@ private function compileBindings($query, $bindings) } $bindings = $this->prepareBindings($bindings); + $newFormat = []; switch (explode(' ', $query)[0]) { - case "select": + case 'select': $builder = $this->queryGrammar->getBuilder(); if ($builder != NULL && $builder->wheres != NULL) { return $this->compileForSelect($builder, $bindings); } else { return $bindings; } - case "insert": + case 'insert': preg_match( "/(?'tables'.*) \((?'attributes'.*)\) values/i", $query, $matches ); break; - case "update": + case 'update': preg_match( "/(?'tables'.*) set (?'attributes'.*)/i", $query, $matches ); break; - case "delete": + case 'delete': preg_match( "/(?'tables'.*) where (?'attributes'.*)/i", $query, @@ -335,13 +370,17 @@ private function compileBindings($query, $bindings) if (is_array($desQuery['tables'])) { $desQuery['tables'] = implode($desQuery['tables'], ' '); } + if (is_array($desQuery['attributes'])) { $desQuery['attributes'] = implode($desQuery['attributes'], ' '); } unset($matches); + unset($queryType); + preg_match_all("/\[([^\]]*)\]/", $desQuery['attributes'], $arrQuery); + preg_match_all( "/\[([^\]]*)\]/", str_replace("].[].[", '..', $desQuery['tables']), @@ -349,8 +388,11 @@ private function compileBindings($query, $bindings) ); $arrQuery = $arrQuery[1]; + $arrTables = $arrTables[1]; + $ind = 0; + $numTables = count($arrTables); if ($numTables == 1) { @@ -366,17 +408,22 @@ private function compileBindings($query, $bindings) if ($numTables > 1) { $table = $campos; } + if (!array_key_exists($table, $newFormat)) { $queryRes = $this->getPdo()->query( $this->queryStringForCompileBindings($table) ); + $types[$table] = $queryRes->fetchAll(PDO::FETCH_ASSOC); + for ($k = 0; $k < count($types[$table]); $k++) { $types[$table][ $types[$table][$k]['name'] ] = $types[$table][$k]; + unset($types[$table][$k]); } + $newFormat[$table] = []; } } @@ -389,6 +436,7 @@ private function compileBindings($query, $bindings) 'binding' => $ind ] ); + if ( in_array( strtolower($types[$table][$campos]['type']), @@ -406,6 +454,7 @@ private function compileBindings($query, $bindings) } else { array_push($newFormat[$table], ['campo' => $campos]); } + $ind++; } } @@ -413,9 +462,16 @@ private function compileBindings($query, $bindings) return $newBinds; } + /** + * Query string for compile bindings. + * + * @param string $table + * @return string + */ private function queryStringForCompileBindings($table) { $explicitDB = explode('..', $table); + if (isset($explicitDB[1])) { return " SELECT @@ -471,11 +527,11 @@ private function queryStringForCompileBindings($table) /** * Set new bindings with specified column types to Sybase. - * Poderia compilar novamente dos bindings usando os PDO::PARAM, porém, - * não tem nenhuma constante que lide com decimais, logo, a única maneira - * seria colocando PDO::PARAM_STR, que colocaria plicas. - * Detalhes: - * http://stackoverflow.com/questions/2718628/pdoparam-for-type-decimal + * + * It could compile again from bindings using PDO::PARAM, however, it has + * no constants that deal with decimals, so the only way would be to put + * PDO::PARAM_STR, which would put quotes. + * @link http://stackoverflow.com/questions/2718628/pdoparam-for-type-decimal * * @param string $query * @param array $bindings @@ -483,14 +539,19 @@ private function queryStringForCompileBindings($table) */ private function compileNewQuery($query, $bindings) { - $newQuery = ""; + $newQuery = ''; + $bindings = $this->compileBindings($query, $bindings); + $partQuery = explode("?", $query); + for ($i = 0; $i < count($partQuery); $i++) { $newQuery .= $partQuery[$i]; + if ($i < count($bindings)) { if (is_string($bindings[$i])) { $bindings[$i] = str_replace("'", "''", $bindings[$i]); + $newQuery .= "'" . $bindings[$i] . "'"; } else { if (!is_null($bindings[$i])) { @@ -501,45 +562,68 @@ private function compileNewQuery($query, $bindings) } } } - $newQuery = str_replace( "[]", '', $newQuery); + + $newQuery = str_replace( '[]', '', $newQuery); + return $newQuery; } - public function compileOffset($offset, $query, $bindings = array(), $me) + /** + * Compile offset. + * + * @param int $offset + * @param string $query + * @param array $bindings + * @param \Uepg\LaravelSybase\Database\Connection $me + * @return string + */ + public function compileOffset($offset, $query, $bindings = [], $me) { $limit = $this->queryGrammar->getBuilder()->limit; - $from = explode(" ", $this->queryGrammar->getBuilder()->from)[0]; + + $from = explode(' ', $this->queryGrammar->getBuilder()->from)[0]; + if (!isset($limit)) { $limit = 999999999999999999999999999; } + $queryString = $this->queryStringForIdentity($from); + $identity = $this->getPdo()->query($queryString)->fetchAll( $me->getFetchMode() )[0]; if (count((array)$identity) === 0) { $queryString = $this->queryStringForPrimaries($from); + $primaries = $this->getPdo()->query($queryString)->fetchAll( $me->getFetchMode() ); + foreach ($primaries as $primary) { $newArr[] = $primary->primary_key . '+0 AS ' . $primary->primary_key; + $whereArr[] = "#tmpPaginate." . $primary->primary_key . ' = #tmpTable.' . $primary->primary_key; } + $resPrimaries = implode(', ', $newArr); + $wherePrimaries = implode(' AND ', $whereArr); } else { $resPrimaries = $identity->column . '+0 AS ' . $identity->column; + $wherePrimaries = "#tmpPaginate." . $identity->column . ' = #tmpTable.' . $identity->column; + // Offset operation $this->getPdo()->query(str_replace( - " from ", + ' from ', " into #tmpPaginate from ", $this->compileNewQuery($query, $bindings) )); + $this->getPdo()->query(" SELECT " . $resPrimaries . ", @@ -548,6 +632,7 @@ public function compileOffset($offset, $query, $bindings = array(), $me) #tmpTable FROM #tmpPaginate"); + return $this->getPdo()->query(" SELECT #tmpPaginate.*, @@ -566,9 +651,16 @@ public function compileOffset($offset, $query, $bindings = array(), $me) } } + /** + * Query string for identity. + * + * @param string $from + * @return string + */ private function queryStringForIdentity($from) { $explicitDB = explode('..', $from); + if (isset($explicitDB[1])) { return " SELECT @@ -594,9 +686,16 @@ private function queryStringForIdentity($from) } } + /** + * Query string for primaries. + * + * @param string $from + * @return string + */ private function queryStringForPrimaries($from) { $explicitDB = explode('..', $from); + if (isset($explicitDB[1])) { return " SELECT @@ -638,7 +737,7 @@ private function queryStringForPrimaries($from) * @param bool $useReadPdo * @return array */ - public function select($query, $bindings = array(), $useReadPdo = true) + public function select($query, $bindings = [], $useReadPdo = true) { return $this->run($query, $bindings, function ( $query, @@ -658,29 +757,35 @@ public function select($query, $bindings = array(), $useReadPdo = true) return $this->compileOffset($offset, $query, $bindings, $this); } else { $result = []; + $statement = $this->getPdo()->query($this->compileNewQuery( $query, $bindings )); + do { $result += $statement->fetchAll($this->getFetchMode()); } while ($statement->nextRowset()); + return $result; } }); } /** + * Get the statement. + * * @param string $query - * @param mixed array $bindings + * @param mixed|array $bindings * @return bool */ - public function statement($query, $bindings = array()) + public function statement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return true; } + return $this->getPdo()->query($this->compileNewQuery( $query, $bindings @@ -688,12 +793,20 @@ public function statement($query, $bindings = array()) }); } + /** + * Affecting statement. + * + * @param string $query + * @param array $bindings + * @return int + */ public function affectingStatement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return 0; } + return $this->getPdo()->query($this->compileNewQuery( $query, $bindings @@ -712,17 +825,22 @@ public function getFetchMode() } /** - * @return \Uepg\LaravelSybase\Database\Query\Builder + * Get SchemaBuilder. + * + * @return \Illuminate\Database\Query\Builder */ public function getSchemaBuilder() { if (is_null($this->schemaGrammar)) { $this->useDefaultSchemaGrammar(); } + $builder = new Builder($this); + $builder->blueprintResolver(function ($table, $callback) { return new Blueprint($table, $callback); }); + return $builder; } } diff --git a/src/Database/Query/Grammar.php b/src/Database/Query/Grammar.php index 37f40f2..a0ac0e4 100644 --- a/src/Database/Query/Grammar.php +++ b/src/Database/Query/Grammar.php @@ -2,8 +2,8 @@ namespace Uepg\LaravelSybase\Database\Query; -use Illuminate\Database\Query\Grammars\Grammar as IlluminateGrammar; use Illuminate\Database\Query\Builder; +use Illuminate\Database\Query\Grammars\Grammar as IlluminateGrammar; class Grammar extends IlluminateGrammar { @@ -18,8 +18,18 @@ class Grammar extends IlluminateGrammar '&', '&=', '|', '|=', '^', '^=', ]; + /** + * Builder for query. + * + * @var \Illuminate\Database\Query\Builder + */ protected $builder; + /** + * Get the builder. + * + * @return \Illuminate\Database\Query\Builder + */ public function getBuilder(){ return $this->builder; } @@ -27,12 +37,13 @@ public function getBuilder(){ /** * Compile a select query into SQL. * - * @param \Uepg\LaravelSybase\Database\Query\Builder + * @param \Illuminate\Database\Query\Builder $query * @return string */ public function compileSelect(Builder $query) { $this->builder = $query; + $components = $this->compileComponents($query); return $this->concatenate($components); @@ -41,7 +52,7 @@ public function compileSelect(Builder $query) /** * Compile the "select *" portion of the query. * - * @param \Uepg\LaravelSybase\Database\Query\Builder $query + * @param \Illuminate\Database\Query\Builder $query * @param array $columns * @return string */ @@ -67,7 +78,7 @@ protected function compileColumns(Builder $query, $columns) /** * Compile the "from" portion of the query. * - * @param \Uepg\LaravelSybase\Database\Query\Builder $query + * @param \Illuminate\Database\Query\Builder $query * @param string $table * @return string */ @@ -90,7 +101,7 @@ protected function compileFrom(Builder $query, $table) /** * Compile the "limit" portions of the query. * - * @param \Uepg\LaravelSybase\Database\Query\Builder $query + * @param \Illuminate\Database\Query\Builder $query * @param int $limit * @return string */ @@ -102,7 +113,7 @@ protected function compileLimit(Builder $query, $limit) /** * Compile the "offset" portions of the query. * - * @param \Uepg\LaravelSybase\Database\Query\Builder $query + * @param \Illuminate\Database\Query\Builder $query * @param int $offset * @return string */ @@ -114,13 +125,13 @@ protected function compileOffset(Builder $query, $offset) /** * Compile a truncate table statement into SQL. * - * @param \Uepg\LaravelSybase\Database\Query\Builder $query + * @param \Illuminate\Database\Query\Builder $query * @return array */ public function compileTruncate(Builder $query) { return [ - 'truncate table ' . $this->wrapTable($query->from) => array() + 'truncate table ' . $this->wrapTable($query->from) => [] ]; } diff --git a/src/Database/Schema/Blueprint.php b/src/Database/Schema/Blueprint.php index 6d7ff8c..6492575 100644 --- a/src/Database/Schema/Blueprint.php +++ b/src/Database/Schema/Blueprint.php @@ -6,6 +6,14 @@ class Blueprint extends IlluminateBlueprint { + /** + * Function for numeric type. + * + * @param string $type + * @param string $name + * @param array $parameters + * @return \Illuminate\Database\Schema\ColumnDefinition + */ public function numeric($column, $total = 8, $autoIncrement = false) { return $this->addColumn( diff --git a/src/Database/Schema/Grammar.php b/src/Database/Schema/Grammar.php index 9b0b176..6883231 100644 --- a/src/Database/Schema/Grammar.php +++ b/src/Database/Schema/Grammar.php @@ -2,9 +2,9 @@ namespace Uepg\LaravelSybase\Database\Schema; -use Illuminate\Database\Schema\Grammars\Grammar as IlluminateGrammar; -use Uepg\LaravelSybase\Database\Schema\Blueprint; use Uepg\LaravelSybase\Support\Fluent; +use Uepg\LaravelSybase\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Grammars\Grammar as IlluminateGrammar; class Grammar extends IlluminateGrammar { @@ -33,6 +33,7 @@ class Grammar extends IlluminateGrammar /** * Verify if $str length is lower to 30 characters. * + * @param string $str * @return string */ public function limit30Characters($str) @@ -596,7 +597,7 @@ protected function modifyNullable(Blueprint $blueprint, Fluent $column) protected function modifyDefault(Blueprint $blueprint, Fluent $column) { if (!is_null($column->default)) { - return " default " . $this->getDefaultValue($column->default); + return ' default ' . $this->getDefaultValue($column->default); } } diff --git a/src/SybaseServiceProvider.php b/src/SybaseServiceProvider.php index 78ba1c1..8740eea 100644 --- a/src/SybaseServiceProvider.php +++ b/src/SybaseServiceProvider.php @@ -2,10 +2,10 @@ namespace Uepg\LaravelSybase; -use Illuminate\Database\Connection as IlluminateConnection; use Illuminate\Support\ServiceProvider; -use Uepg\LaravelSybase\Database\Connection as SybaseConnection; use Uepg\LaravelSybase\Database\Connector; +use Illuminate\Database\Connection as IlluminateConnection; +use Uepg\LaravelSybase\Database\Connection as SybaseConnection; class SybaseServiceProvider extends ServiceProvider {