Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
55.56% |
5 / 9 |
CRAP | |
86.08% |
68 / 79 |
| FunctionAPI | |
0.00% |
0 / 1 |
|
55.56% |
5 / 9 |
40.70 | |
86.08% |
68 / 79 |
| setFetchMode($fetchMode) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| setFetchAssoc() | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| resetFetchMode() | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| __construct(\PDO $pdo, $options = NULL) | |
100.00% |
1 / 1 |
7 | |
100.00% |
5 / 5 |
|||
| __call($functionName, $arguments) | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
| addEvalSubstitution($className, $callbackName) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| _performArgumentSubstitution($argument) | |
0.00% |
0 / 1 |
8.70 | |
77.78% |
14 / 18 |
|||
| _makeCall($functionName, $arguments, $callType) | |
0.00% |
0 / 1 |
6.01 | |
94.12% |
16 / 17 |
|||
| _fetch($pdoStatement) | |
0.00% |
0 / 1 |
10.29 | |
85.71% |
24 / 28 |
|||
| <?php | |
| /** | |
| * All rights reserved Axel Ancona Esselmann | |
| */ | |
| namespace aae\db { | |
| /** | |
| * Maps function calls from application layer to stored function | |
| * and stored procedure calls in storage layer. | |
| * | |
| * @author Axel Ancona Esselmann | |
| * @package aae\db | |
| */ | |
| class FunctionAPI /*implements StorageAPI*/ { | |
| private $_dbName, $_pdo, $_fetchMode = 0, $_debug = false, $_evalSubstitutions = array('aae\app\User' => "getId", 'DateTime' => ["format", 'Y-m-d H:i:s']); | |
| public $echoQuery = false; | |
| const RESET = 0, //notmulrow | is array | is array or [] | |
| FETCH_NUM_ARRAY = 3, // 0 | 1 | 1 | |
| FETCH_ASS_ARRAY = 1, // 0 | 0 | 1 | |
| FETCH_ONE_ROW = 4, // 1 | 0 | 0 | |
| //---------------------------------------------------------\\ | |
| IS_ARRAY = 1, // 0 | 0 | 1 | |
| IS_NUM_ARRAY = 2; // 0 | 1 | 0 | |
| /** | |
| * Accepts a bit flag. Combine class constants: | |
| * RESET | |
| * FETCH_NUM_ARRAY | |
| * FETCH_ASS_ARRAY | |
| * FETCH_ONE_ROW | |
| * | |
| * Make sure to reset the fetch mode when done. | |
| * | |
| * @param bitFlag $fetchMode | |
| */ | |
| public function setFetchMode($fetchMode) { | |
| $this->_fetchMode = $fetchMode; | |
| } | |
| public function setFetchAssoc() { | |
| $this->_fetchMode = self::FETCH_ASS_ARRAY; | |
| } | |
| public function resetFetchMode() { | |
| $this->_fetchMode = self::RESET; | |
| } | |
| public function __construct(\PDO $pdo, $options = NULL) { | |
| $this->_pdo = $pdo; | |
| $this->_dbName = (is_array($options) && array_key_exists("dbName", $options)) ? $options["dbName"] : NULL; | |
| $this->_debug = (is_array($options) && array_key_exists("debug", $options)) ? (bool)$options["debug"] : false; | |
| $this->echoQuery = (is_array($options) && array_key_exists("echoQuery", $options)) ? (bool)$options["echoQuery"] : false; | |
| } | |
| public function __call($functionName, $arguments) { | |
| $callString = ($this->_fetchMode & 1) ? "CALL" : "SELECT"; | |
| $result = $this->_makeCall($functionName, $arguments, $callString); | |
| return $result; | |
| } | |
| /** | |
| * An eval substitution allows for passing of objects to the function api. When it is time to pass the instance | |
| * to the database, an evaluation callback is called on the object to get database representation for the instance. | |
| * @param string $className the class name for the object that supports eval substitution | |
| * @param string $callbackName the name of the function that is called on the instance | |
| */ | |
| public function addEvalSubstitution($className, $callbackName) { | |
| $this->_evalSubstitutions[$className] = $callbackName; | |
| } | |
| private function _performArgumentSubstitution($argument) { | |
| if (is_string($argument)) $argument = $this->_pdo->quote($argument); | |
| else if (is_null( $argument)) $argument = "NULL"; | |
| else if ($argument === true) $argument = 'TRUE'; | |
| else if ($argument === false) $argument = 'FALSE'; | |
| else if (is_object($argument)) { | |
| if (array_key_exists(get_class($argument), $this->_evalSubstitutions)) { | |
| $evalFunctionName = $this->_evalSubstitutions[get_class($argument)]; | |
| $className = $argument; | |
| if (is_array($evalFunctionName)) { | |
| $evalArguments = $evalFunctionName; | |
| $evalFunctionName = array_shift($evalArguments); | |
| $argument = call_user_func_array([$className, $evalFunctionName], $evalArguments); | |
| } else { | |
| $argument = $className->$evalFunctionName(); | |
| } | |
| $argument = $this->_performArgumentSubstitution($argument); | |
| } else throw new StorageAPIException("FunctionAPI has no eval substitution for an object of type '".get_class($argument)."'.", 226151433); | |
| } | |
| return $argument; | |
| } | |
| private function _makeCall($functionName, $arguments, $callType) { | |
| $this->_pdo->beginTransaction(); | |
| $dbName = (!is_null($this->_dbName)) ? $this->_dbName."." : ""; | |
| $query = $callType." ".$dbName.$functionName."("; | |
| for ($i=0; $i < count($arguments); $i++) { | |
| $arguments[$i] = $this->_performArgumentSubstitution($arguments[$i]); | |
| } | |
| $query .= implode(", ", $arguments).")"; | |
| // @codeCoverageIgnoreStart | |
| if ($this->echoQuery) echo "Last query:<br /><span style='color:red;font-weight: bold;'>$query</span><br /><br />"; | |
| // @codeCoverageIgnoreEnd | |
| try { | |
| $pdoStatement = $this->_pdo->query($query); | |
| $result = $this->_fetch($pdoStatement); | |
| } catch (\Exception $e) { | |
| if ($this->_debug) { | |
| $querySummary = "<br /><br />Last query:<br /><span style='color:red;font-weight: bold;'>$query</span><br />"; | |
| } else $querySummary = ""; | |
| throw new StorageAPIException("Database Error with message:\n".$e->getMessage().$querySummary, 1015141104); | |
| } | |
| $pdoStatement->closeCursor(); | |
| $this->_pdo->commit(); | |
| return $result; | |
| } | |
| private function _fetch($pdoStatement) { | |
| if (!$pdoStatement) { | |
| if ($this->_debug) { | |
| $errorinfo = ": <br />\n".implode($this->_pdo->errorInfo(), "<br />\n"); | |
| } else $errorinfo = ""; | |
| throw new StorageAPIException("Database Error".$errorinfo, 1015141105); | |
| } | |
| if ($this->_fetchMode & self::IS_ARRAY) { | |
| $fetchMode = ($this->_fetchMode & self::IS_NUM_ARRAY) | |
| ? \PDO::FETCH_NUM | |
| : \PDO::FETCH_ASSOC; | |
| $pdoStatement->setFetchMode($fetchMode); | |
| $result = array(); | |
| $row = $pdoStatement->fetch(); | |
| if ($this->_fetchMode & self::FETCH_ONE_ROW) { | |
| $result = $row; | |
| } else { | |
| if (count($row) == 1 && ($this->_fetchMode & self::IS_NUM_ARRAY)) { | |
| while ($row) { | |
| $result[] = $row[0]; | |
| $row = $pdoStatement->fetch(); | |
| } | |
| } else { | |
| while ($row) { | |
| $result[] = $row; | |
| $row = $pdoStatement->fetch(); | |
| } | |
| } | |
| } | |
| } else { | |
| $result = $pdoStatement->fetchColumn(); | |
| } | |
| return $result; | |
| } | |
| } | |
| } |