Skip to content

Instantly share code, notes, and snippets.

@brihter
Last active August 29, 2015 14:04
Show Gist options
  • Save brihter/a2fd1cfd84a9df8a8b00 to your computer and use it in GitHub Desktop.
Save brihter/a2fd1cfd84a9df8a8b00 to your computer and use it in GitHub Desktop.
doctrine custom oracle driver implementation that will return native types when executing a raw sql statement
<?php
namespace COMPANY\Core\Vendor\Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Driver\OCI8\Driver as OCIDriver;
class Driver extends OCIDriver
{
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
{
return new OCI8Connection(
$username,
$password,
$this->_constructDsn($params),
isset($params['charset']) ? $params['charset'] : null,
isset($params['sessionMode']) ? $params['sessionMode'] : OCI_DEFAULT,
isset($params['persistent']) ? $params['persistent'] : false
);
}
}
<?php
// ...
$connectionOptions = array(
'driverClass' => 'COMPANY\Core\Vendor\Doctrine\DBAL\Driver\OCI8\Driver',
'user' => 'user',
'password' => 'pass',
'host' => 'host',
'port' => 'port',
'dbname' => 'sid',
'charset' => 'charset'
);
$em = EntityManager::create($connectionOptions, $config);
// ...
$stmt = $em->getConnection()->prepare("select * from customer");
$stmt->execute();
$result = $stmt->fetchAll();
var_dump($result);
// result
// [0] =>
// array(4) {
// 'ID' =>
// int(1)
// 'FIRSTNAME' =>
// string(6) "Samuel"
// 'LASTNAME' =>
// string(4) "Ross"
// 'BIRTHDATE' =>
// class COMPANY\Core\Util\DateTime\ISO8601DateTime#27 (3) {
// public $date =>
// string(26) "1980-09-28 00:00:00.000000"
// public $timezone_type =>
// int(3)
// public $timezone =>
// string(16) "Europe/Ljubljana"
// }
// }
<?php
namespace COMPANY\Core\Vendor\Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Driver\OCI8\OCI8Connection as Connection;
class OCI8Connection extends Connection
{
public function prepare($prepareString)
{
return new OCI8Statement($this->dbh, $prepareString, $this);
}
}
<?php
namespace COMPANY\Core\Vendor\Doctrine\DBAL\Driver\OCI8;
use COMPANY\Core\Util\DateTime\ISO8601DateTime;
use Doctrine\DBAL\Driver\OCI8\OCI8Statement as Statement;
class OCI8Statement extends Statement
{
public function fetch($fetchMode = null)
{
return $this->_fetchByType(null, $fetchMode);
}
public function fetchAll($fetchMode = null)
{
return $this->_fetchAllByType(null, $fetchMode = null);
}
private function _fetchByType($types = null, $fetchMode = null)
{
if ($types == null)
$types = $this->_getTypeMapping();
// get row
$row = parent::fetch($fetchMode);
// end of iteration
if (!is_array($row)) {
return $row;
}
foreach ($row as $type => &$v)
{
switch ($types[$type])
{
case 'NUMBER':
//NOTE: we explicitly check if a returned number has a dot "." and parse this as float
//TODO: make regex non-greedy
//NOTE: find a better way to do this, since its an expensive operation
$r = preg_match('/\./', $v);
if ($r == false || $r == 0) {
$v = intval($v);
} else {
$v = floatval($v);
}
break;
//string
case 'CHAR':
case 'NCHAR':
case 'VARCHAR':
case 'NVARCHAR':
case 'NVARCHAR2':
case 'CLOB':
case 'NCLOB':
if ($v != null) {
$v = strval($v);
}
break;
case 'VARCHAR2':
if ($v != null)
{
//NOTE: we support the UTC ISO8601 format -> 2014-07-02T05:03:54Z
//NOTE: find a better way to do this, since its an expensive operation
$r = preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/', $v);
if($r == 0 || $r == false) {
// string
$v = strval($v);
} else {
$v = ISO8601DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $v);
}
}
break;
case 'DATE':
if ($v != null) {
//NOTE: we support the ISO8601 date format (YYYY-MM-DD -> 2014-07-02)
//TODO: require to_date from oracle, consolidate the "d-M-y" format!
$v = ISO8601DateTime::createFromFormat('d-M-y', $v);
$v->setTime(0, 0, 0);
}
break;
default:
throw new \Exception("Oracle type \"".$types[$type]."\" not supported.");
break;
}
}
return $row;
}
private function _fetchAllByType($types = null, $fetchMode = null)
{
if ($types == null)
$types = $this->_getTypeMapping();
$result = array();
while($row = $this->_fetchByType($types, $fetchMode))
$result[] = $row;
return $result;
}
private function _getTypeMapping()
{
oci_execute($this->_sth, OCI_DESCRIBE_ONLY);
$cols = oci_num_fields($this->_sth);
$types = array();
for ($i = 1; $i <= $cols; ++$i) {
$column = oci_field_name($this->_sth, $i);
$type = oci_field_type($this->_sth, $i);
$types[$column] = $type;
}
if (count($types) === 0)
return null;
return $types;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment