Skip to content

Commit

Permalink
Merge pull request #53 from efcor/master
Browse files Browse the repository at this point in the history
update for compatibility with Laravel 8
  • Loading branch information
jfelder authored Feb 10, 2021
2 parents 00d69c6 + 6f3575b commit 38f8278
Show file tree
Hide file tree
Showing 19 changed files with 371 additions and 120 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ composer.lock
atlassian-ide-plugin.xml
/vagrant
Vagrantfile


.phpunit.result.cache
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: php

php:
- 7.2
- 7.3
- 7.4

Expand Down
21 changes: 14 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "jfelder/oracledb",
"description": "Oracle DB driver for Laravel",
"keywords": ["oracle", "laravel", "laravel 7", "pdo_oci", "oci8"],
"keywords": ["oracle", "laravel", "laravel 8", "pdo_oci", "oci8"],
"license": "MIT",
"authors": [
{
Expand All @@ -10,19 +10,26 @@
}
],
"require": {
"php": "^7.2.5",
"illuminate/support": "^7.0",
"illuminate/database": "^7.0",
"illuminate/pagination": "^7.0"
"php": "^7.3.0",
"illuminate/support": "^8.0",
"illuminate/database": "^8.24.0",
"illuminate/pagination": "^8.0"
},
"require-dev": {
"mockery/mockery": "^1.3.1",
"phpunit/phpunit": "^8.4|^9.0"
"mockery/mockery": "^1.4.2",
"phpunit/phpunit": "^9.3.3"
},
"autoload": {
"psr-4": {
"Jfelder\\": "src/Jfelder"
}
},
"extra": {
"laravel": {
"providers": [
"Jfelder\\OracleDB\\OracleDBServiceProvider"
]
}
},
"minimum-stability": "stable"
}
63 changes: 36 additions & 27 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
## Laravel Oracle Database Package

### OracleDB (updated for Laravel 7.x)
### OracleDB (updated for Laravel 8.x)

[![Latest Stable Version](https://poser.pugx.org/jfelder/oracledb/v/stable.png)](https://packagist.org/packages/jfelder/oracledb) [![Total Downloads](https://poser.pugx.org/jfelder/oracledb/downloads.png)](https://packagist.org/packages/jfelder/oracledb) [![Build Status](https://travis-ci.org/jfelder/Laravel-OracleDB.png)](https://travis-ci.org/jfelder/Laravel-OracleDB)


OracleDB is an Oracle Database Driver package for [Laravel Framework](https://laravel.com) - thanks [@taylorotwell](https://github.com/taylorotwell). OracleDB is an extension of [Illuminate/Database](https://github.com/illuminate/database) that uses either the [PDO_OCI] (https://www.php.net/manual/en/ref.pdo-oci.php) extension or the [OCI8 Functions](https://www.php.net/manual/en/ref.oci8.php) wrapped into the PDO namespace.
OracleDB is an Oracle Database Driver package for [Laravel Framework](https://laravel.com) - thanks [@taylorotwell](https://github.com/taylorotwell). OracleDB is an extension of [Illuminate/Database](https://github.com/illuminate/database) that uses either the [PDO_OCI](https://www.php.net/manual/en/ref.pdo-oci.php) extension or the [OCI8 Functions](https://www.php.net/manual/en/ref.oci8.php) wrapped into the PDO namespace.

_NOTE: This package has not been tested in PHP 8._

**Please report any bugs you may find.**

Expand All @@ -16,48 +18,51 @@ OracleDB is an Oracle Database Driver package for [Laravel Framework](https://la

### Installation

Add `jfelder/oracledb` as a requirement to composer.json:
With [Composer](https://getcomposer.org):

```json
{
"require": {
"jfelder/oracledb": "7.*"
}
}
```sh
composer require jfelder/oracledb
```
And then run `composer update`

Once Composer has installed or updated your packages you need to register OracleDB. Open up `config/app.php` and find
the `providers` key and add:
During this command, Laravel's "Auto-Discovery" feature should automatically register OracleDB's service
provider.

```php
Jfelder\OracleDB\OracleDBServiceProvider::class,
Next, publish OracleDB's configuration file using the vendor:publish Artisan command. This will copy OracleDB's
configuration file to `config/oracledb.php` in your project.

```sh
php artisan vendor:publish --tag=oracledb-config
```

Finally you need to publish a configuration file by running the following Artisan command.
To finish the installation, set your environment variables (typically in your .env file) to the corresponding
env variables used in `config/oracledb.php`: such as `DB_HOST`, `DB_USERNAME`, etc.

```terminal
$ php artisan vendor:publish
```
This will copy the configuration file to config/oracledb.php
Additionally, it may be necessary for your app to configure the NLS_DATE_FORMAT of the database connection session,
before any queries are executed. One way to accomplish this is to run a statement in your `AppServiceProvider`'s `boot`
method, for example:

```php
if (config('database.default') === 'oracle') {
DB::statement("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
}
```

### Basic Usage
The configuration file for this package is located at 'config/oracledb.php'.
In this file you define all of your oracle database connections. If you need to make more than one connection, just
The configuration file for this package is located at `config/oracledb.php`.
In this file, you define all of your oracle database connections. If you need to make more than one connection, just
copy the example one. If you want to make one of these connections the default connection, enter the name you gave the
connection into the "Default Database Connection Name" section in 'config/database.php'.
connection into the "Default Database Connection Name" section in `config/database.php`.

Once you have configured the OracleDB database connection(s), you may run queries using the 'DB' class as normal.
Once you have configured the OracleDB database connection(s), you may run queries using the `DB` facade as normal.

#### NEW: The oci8 library in now the default library. If you want to use the pdo library, enter "pdo" as the driver and the code will automatically use the pdo library instead of the oci8 library. Any other value will result in the oci8 library being used.
_NOTE: OCI8 is the default driver. If you want to use the PDO_OCI driver, change the `driver` value to `'pdo'` in the `config/oracledb.php` file for whichever connections you wish to have utilize PDO_OCI. Setting the driver to `'pdo'` will make OracleDB use the [PDO_OCI](https://www.php.net/manual/en/ref.pdo-oci.php) extension. Given any other `driver` value, OracleDB will use the [OCI8 Functions](https://www.php.net/manual/en/ref.oci8.php)._

```php
$results = DB::select('select * from users where id = ?', [1]);
```

The above statement assumes you have set the default connection to be the oracle connection you setup in
config/database.php file and will always return an 'array' of results.
config/database.php file and will always return an `array` of results.

```php
$results = DB::connection('oracle')->select('select * from users where id = ?', [1]);
Expand All @@ -77,16 +82,19 @@ in config/oracledb.php file.
> **Note:** When using the insertGetId method, you can specify the auto-incrementing column name as the second
parameter in insertGetId function. It will default to "id" if not specified.

See [Laravel Database Basic Docs](https://laravel.com/docs/7.x/database) for more information.
See [Laravel Database Basic Docs](https://laravel.com/docs/8.x/database) for more information.

### Unimplemented Features

Some of the features available in the first-party Laravel database drivers are not implemented in this package. Pull requests are welcome for implementing any of these features, or for expanding this list if you find any unimplemented features not already listed.
Some of the features available in the first-party Laravel database drivers are not implemented in this package. Pull
requests are welcome for implementing any of these features, or for expanding this list if you find any unimplemented
features not already listed.

#### Query Builder

- insertOrIgnore `DB::from('users')->insertOrIgnore(['email' => 'foo']);`
- insertGetId with empty values `DB::from('users')->insertGetId([]);` (but calling with non-empty values is supported)
- upserts `DB::from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');`
- deleting with a join `DB::from('users')->join('contacts', 'users.id', '=', 'contacts.id')->where('users.email', '=', 'foo')->delete();`
- deleting with a limit `DB::from('users')->where('email', '=', 'foo')->orderBy('id')->take(1)->delete();`
- json operations `DB::from('users')->where('items->sku', '=', 'foo-bar')->get();`
Expand All @@ -99,6 +107,7 @@ Some of the features available in the first-party Laravel database drivers are n
- set collation on a column `$blueprint->string('some_column')->collation('BINARY_CI')`
- set comments on a table `$blueprint->comment("This table is great.")`
- set comments on a column `$blueprint->string('foo')->comment("Some helpful info about the foo column")`
- set the starting value of an auto-incrementing column `$blueprint->increments('id')->startingValue(1000)`
- create a private temporary table `$blueprint->temporary()`
- rename an index `$blueprint->renameIndex('foo', 'bar')`
- specify an algorithm when creating an index via the third argument `$blueprint->index(['foo', 'bar'], 'baz', 'hash')`
Expand Down
10 changes: 0 additions & 10 deletions src/Jfelder/OracleDB/OCI_PDO/OCI.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,16 +212,6 @@ public function getAttribute($attribute)
return;
}

/**
* Return an array of available PDO drivers.
*
* @return array Array of PDO driver names.
*/
public static function getAvailableDrivers()
{
return parent::getAvailableDrivers();
}

/**
* Checks if inside a transaction.
*
Expand Down
5 changes: 4 additions & 1 deletion src/Jfelder/OracleDB/OCI_PDO/OCIStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class OCIStatement extends \PDOStatement
*/
protected $datatypes = [
\PDO::PARAM_BOOL => \SQLT_INT,
\PDO::PARAM_NULL => \SQLT_INT,
// there is no SQLT_NULL, but oracle will insert a null value if it receives an empty string
\PDO::PARAM_NULL => \SQLT_CHR,
\PDO::PARAM_INT => \SQLT_INT,
\PDO::PARAM_STR => \SQLT_CHR,
\PDO::PARAM_INPUT_OUTPUT => \SQLT_CHR,
Expand Down Expand Up @@ -195,6 +196,8 @@ public function bindValue($parameter, $value, $data_type = \PDO::PARAM_STR)

/**
* Closes the cursor, enabling the statement to be executed again.
*
* Todo implement this method instead of always returning true
*
* @return bool Returns TRUE on success or FALSE on failure.
*/
Expand Down
19 changes: 16 additions & 3 deletions src/Jfelder/OracleDB/OracleConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
namespace Jfelder\OracleDB;

use Illuminate\Database\Connection;
use Jfelder\OracleDB\Schema\OracleBuilder;
use Jfelder\OracleDB\Schema\OracleBuilder as OracleSchemaBuilder;
use Jfelder\OracleDB\Query\Processors\OracleProcessor;
use Doctrine\DBAL\Driver\OCI8\Driver as DoctrineDriver;
use Jfelder\OracleDB\Query\Grammars\OracleGrammar as QueryGrammer;
use Jfelder\OracleDB\Query\OracleBuilder as OracleQueryBuilder;
use Jfelder\OracleDB\Schema\Grammars\OracleGrammar as SchemaGrammer;
use PDO;

Expand All @@ -15,15 +16,27 @@ class OracleConnection extends Connection
/**
* Get a schema builder instance for the connection.
*
* @return \Illuminate\Database\Schema\OracleBuilder
* @return \Jfelder\OracleDB\Schema\OracleBuilder
*/
public function getSchemaBuilder()
{
if (is_null($this->schemaGrammar)) {
$this->useDefaultSchemaGrammar();
}

return new OracleBuilder($this);
return new OracleSchemaBuilder($this);
}

/**
* Get a new query builder instance.
*
* @return \Jfelder\OracleDB\Query\OracleBuilder
*/
public function query()
{
return new OracleQueryBuilder(
$this, $this->getQueryGrammar(), $this->getPostProcessor()
);
}

/**
Expand Down
8 changes: 3 additions & 5 deletions src/Jfelder/OracleDB/OracleDBServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ class OracleDBServiceProvider extends ServiceProvider
*/
public function boot()
{
$this->publishes(
[
__DIR__.'/../../config/oracledb.php' => config_path('oracledb.php'),
]
);
$this->publishes([
__DIR__.'/../../config/oracledb.php' => config_path('oracledb.php'),
], 'oracledb-config');
}

/**
Expand Down
28 changes: 28 additions & 0 deletions src/Jfelder/OracleDB/Query/OracleBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Jfelder\OracleDB\Query;

use Illuminate\Database\Query\Expression;

class OracleBuilder extends \Illuminate\Database\Query\Builder
{
/**
* Add a subquery cross join to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @return $this
*/
public function crossJoinSub($query, $as)
{
[$query, $bindings] = $this->createSub($query);

$expression = '('.$query.') '.$this->grammar->wrapTable($as);

$this->addBinding($bindings, 'join');

$this->joins[] = $this->newJoinClause($this, 'cross', new Expression($expression));

return $this;
}
}
3 changes: 2 additions & 1 deletion src/Jfelder/OracleDB/Query/Processors/OracleProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Processors\Processor as Processor;
use Jfelder\OracleDB\OCI_PDO\OCI;

class OracleProcessor extends Processor
{
Expand All @@ -29,7 +30,7 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu

// PDO driver params are 1-based so ++ has to be before bindValue
// OCI driver params are 0-based so no ++ before bindValue
if (get_class($pdo) != 'Jfelder\OracleDB\OCI_PDO\OCI') {
if (get_class($pdo) != OCI::class) {
$counter++;
}

Expand Down
8 changes: 8 additions & 0 deletions src/Jfelder/OracleDB/Schema/Grammars/OracleGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ protected function addForeignKeys(Blueprint $blueprint)
if (! is_null($foreign->onDelete)) {
$sql .= " on delete {$foreign->onDelete}";
}

if (! is_null($foreign->onUpdate)) {
$sql .= " on update {$foreign->onUpdate}";
}
}

return $sql;
Expand Down Expand Up @@ -201,6 +205,10 @@ public function compileForeign(Blueprint $blueprint, Fluent $command)
$sql .= " on delete {$command->onDelete}";
}

if (! is_null($command->onUpdate)) {
$sql .= " on update {$command->onUpdate}";
}

return $sql;
}
}
Expand Down
13 changes: 7 additions & 6 deletions tests/OracleDBConnectorTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use Illuminate\Database\Connectors\Connector;
use Jfelder\OracleDB\Connectors\OracleConnector;
use Mockery as m;
use PHPUnit\Framework\TestCase;

Expand All @@ -12,7 +14,7 @@ public function tearDown(): void

public function testOptionResolution()
{
$connector = new Illuminate\Database\Connectors\Connector;
$connector = new Connector;
$connector->setDefaultOptions([0 => 'foo', 1 => 'bar']);
$this->assertEquals([0 => 'baz', 1 => 'bar', 2 => 'boom'], $connector->getOptions(['options' => [0 => 'baz', 2 => 'boom']]));
}
Expand All @@ -22,11 +24,10 @@ public function testOptionResolution()
*/
public function testOracleConnectCallsCreateConnectionWithProperArguments($dsn, $config)
{
$connection = m::mock('stdClass');
$connector = $this->getMockBuilder('Jfelder\OracleDB\Connectors\OracleConnector')->setMethods(['createConnection', 'getOptions'])->getMock();
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->will($this->returnValue(['options']));
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->will($this->returnValue($connection));

$connector = $this->getMockBuilder(OracleConnector::class)->onlyMethods(['createConnection', 'getOptions'])->getMock();
$connection = m::mock(\stdClass::class);
$connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->willReturn(['options']);
$connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->willReturn($connection);
$result = $connector->connect($config);

$this->assertSame($result, $connection);
Expand Down
6 changes: 4 additions & 2 deletions tests/OracleDBOCIProcessorTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use Jfelder\OracleDB\OracleConnection;
use Jfelder\OracleDB\Query\OracleBuilder;
use Mockery as m;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -29,10 +31,10 @@ public function testInsertGetIdProcessing()
$pdo = m::mock(new ProcessorTestOCIStub());
$pdo->shouldReceive('prepare')->once()->with('sql')->andReturn($stmt);

$connection = m::mock('Illuminate\Database\Connection');
$connection = m::mock(OracleConnection::class);
$connection->shouldReceive('getPdo')->once()->andReturn($pdo);

$builder = m::mock('Illuminate\Database\Query\Builder');
$builder = m::mock(OracleBuilder::class);
$builder->shouldReceive('getConnection')->once()->andReturn($connection);

$processor = new Jfelder\OracleDB\Query\Processors\OracleProcessor;
Expand Down
Loading

0 comments on commit 38f8278

Please sign in to comment.