Last active
August 29, 2015 14:04
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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" | |
// } | |
// } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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