From 4c10c912436b8b43d10df6190840e87b08cf8c48 Mon Sep 17 00:00:00 2001 From: Ifeora Okechukwu Date: Thu, 16 Feb 2017 06:54:14 -0800 Subject: [PATCH] integrating the pixie query builder project step 2 --- README.md | 14 ++- models/Model.php | 66 ++++++++++- system/base/class_maps.php | 1 + system/base/functions.php | 20 +++- system/base/providers/Core/App.php | 9 +- .../DBConnection/MySqlConnectionAdapter.php | 2 +- .../DBConnection/PgSqlConnectionAdapter.php | 14 +++ .../DBConnection/SqlLiteConnectionAdapter.php | 14 +++ system/base/providers/Core/QueryBuilder.php | 4 +- system/base/providers/Core/QueryExtender.php | 106 +++++++++++++++--- system/base/providers/Services/DBService.php | 12 +- system/base/providers/Services/EnvService.php | 4 + views/forcedlogout/index.view | 9 ++ 13 files changed, 233 insertions(+), 42 deletions(-) create mode 100644 system/base/providers/Core/DBConnection/PgSqlConnectionAdapter.php create mode 100644 system/base/providers/Core/DBConnection/SqlLiteConnectionAdapter.php create mode 100644 views/forcedlogout/index.view diff --git a/README.md b/README.md index e8fb25f..3794d4d 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,19 @@ _Thanks to **Micheal Akpobome**, **Shuaib Afegbua**, **Abraham Yusuf**, **Stephe ## Minimum Requirements (Running Jollof) -- Have PHP 5.3.8 and above Installed +* Have PHP 5.3.8 and above Installed -- Have Composer 1.0.0 and above Installed + 1. Have the PHP *mb_string* extension enabled + 2. Have the PHP *openssl* extension enabled + 3. Have the PHP *pdo_mysql* extension enabled + 4. Have the PHP *pdo_sqlite* extension enabled + 5. Have the PHP *sockets* extension enabled + 6. Have the PHP *zip* extension enabled + 7. Have the PHP *curl* extension enabled -- Have NPM 4.2.0 and above Installed +* Have Composer 1.0.0 and above Installed + +* Have Npm 4.2.0 and above Installed ## Trademarks diff --git a/models/Model.php b/models/Model.php index 2247baa..21f7e74 100644 --- a/models/Model.php +++ b/models/Model.php @@ -63,12 +63,14 @@ protected static function setInstance(Model $m, array $scma){ if(!isset(static::$instance)){ + $name = get_class($m); + $m->$schema = $scma; - $m->builder = $app->getBuilder($m->getAttributes()); + $m->builder = $app->getBuilder($m->getAttributes(), $name); static::$instance = unserialize( - sprintf('O:%d:"%s":0:{}', strlen(get_called_class()), get_class($m)) + sprintf('O:%d:"%s":0:{}', strlen(get_called_class()), $name) ); static::$class = get_class(static::$instance); @@ -227,6 +229,39 @@ public static function whereBy(array $clause, array $cols = array('*')){ return static::$instance->get($cols, $clause)->exec(); } + + /** + * Retrieves the very first tuple/row from a Model table + * based on conditions. + * + * + * @param void + * @return void + */ + + public static function first(array $clause, array $cols = array('*')){ + + $attrs = static::$instance->getAttributes(); + + return static::$instance->get($cols, $clause)->exec(1); + } + + /** + * Retrieves distinct columns from a Model table + * + * + * + * @param void + * @return void + */ + + public static function fetchDistinct(array $cols = array('*')){ + + $attrs = static::$instance->getAttributes(); + + return static::$instance->get($cols, array())->distinct()->exec(); + } + /** * * @@ -236,7 +271,7 @@ public static function whereBy(array $clause, array $cols = array('*')){ * @return */ - public static function fetchAllWith($modelName, array $clause){ + public static function fetchAllWith($modelName, array $clause){ return static::$instance->get(array('*'), $clause)->with($modelName)->exec(); } @@ -255,7 +290,7 @@ public static function updateById($id = ''){ $attr = static::$instance->getAttributes(); $clause = array(); - $clause[$attr['key']] = array('=' =>$id); + $clause[$attr['key']] = array('=' => $id); return static::$instance->let(array('*'), $clause)->exec(0); } @@ -303,15 +338,34 @@ public static function findById($id = ''){ * * * + * @param array $clause * @param integer $limit * @param integer $offset * @return array * @api */ - public static function fetchAll($limit = -1, $offset = -1){ + public static function fetchAll(array $clause, $limit = -1, $offset = -1){ + + return static::$instance->get(array('*'), $clause)->exec($limit, $offset); + } + + /** + * Retrieves all tuples/rows in an ordered manner + * from the Model table. + * + * + * @param array $clause - + * @param array $orderCols - + * @param integer $limit - + * @param integer $offset - + * @return array + * @api + */ + + public static function fetchAllOrdered(array $clause, array $orderCols = array(), $limit = -1, $offset = -1){ - return static::$instance->get(array('*'))->exec($limit, $offset); + return static::$instance->get(array('*'), $clause)->ordering($orderCols, true)->exec($limit, $offset); } /** diff --git a/system/base/class_maps.php b/system/base/class_maps.php index 368378e..31ac82d 100644 --- a/system/base/class_maps.php +++ b/system/base/class_maps.php @@ -40,6 +40,7 @@ "\\Providers\\Tools\\ArgvOutput" => $compDir . "/providers/Tools/ArgvOutput", "\\Providers\\Tools\\Console" => $compDir . "/providers/Tools/Console", "\\Providers\\Tools\\JollofSecureHeaders" => $compDir . "/providers/Tools/JollofSecureHeaders", + "\\Providers\\Tools\\SchemaObject" => $compDir . "/providers/Tools/SchemaObject", "\\Providers\\Tools\\SecureHeaders" => $compDir . "/providers/Tools/SecureHeaders", "\\Providers\\Tools\\AuthContext" => $compDir . "/providers/Tools/AuthContext", "\\Providers\\Tools\\InputFilter" => $compDir . "/providers/Tools/InputFilter", diff --git a/system/base/functions.php b/system/base/functions.php index 9357891..f4e0ddf 100644 --- a/system/base/functions.php +++ b/system/base/functions.php @@ -458,10 +458,10 @@ function starts_with($str, $begin, $ignorecase = FALSE){ $slen = strlen($str); $sub = substr($str, 0, $len); if((gettype($str) == 'string' && gettype($begin) == 'string') && ($slen > $len)){ - if($ignorecase){ - $begin = strtolower($begin); - $sub = strtolower($sub); - } + if($ignorecase){ + $begin = strtolower($begin); + $sub = strtolower($sub); + } if(strcmp($sub, $begin) == 0){ return TRUE; }else{ @@ -564,6 +564,18 @@ function custom_session_id($native = FALSE){ } } +if(!function_exists('is_multi_array')){ + function is_multi_array($array){ + $result = false; + $filtered; + if(count($array) != count($array, COUNT_RECURSIVE)){ + $filtered = array_filter($array, 'is_array'); + $result = is_array(current($array)) || (count($filtered) > 0); + } + return $result; + } +} + if(! function_exists('is_binary_file') ){ function is_binary_file($file, $asString=FALSE){ $out = array(); diff --git a/system/base/providers/Core/App.php b/system/base/providers/Core/App.php index d7882a6..f669e29 100644 --- a/system/base/providers/Core/App.php +++ b/system/base/providers/Core/App.php @@ -297,13 +297,14 @@ public function exposeEnvironment($root){ * * * - * @param - * @return + * @param array $atrribs + * @param string $modelName + * @return \Providers\Core\QueryBuilder */ - public function getBuilder(array $attribs){ + public function getBuilder(array $attribs, $modelName){ - return $this->dbservice->getBuilder($attribs); + return $this->dbservice->getBuilder($attribs, $modelName); } /** diff --git a/system/base/providers/Core/DBConnection/MySqlConnectionAdapter.php b/system/base/providers/Core/DBConnection/MySqlConnectionAdapter.php index 89391a5..981b46a 100644 --- a/system/base/providers/Core/DBConnection/MySqlConnectionAdapter.php +++ b/system/base/providers/Core/DBConnection/MySqlConnectionAdapter.php @@ -2,7 +2,7 @@ namespace Providers\Core\DBConnection; -class MySqlConnectionAdapter{ +class MySqlConnectionAdapter extends BaseConnectionAdapter{ public function __construct($dbName = NULL, $unixSocket = NULL){ diff --git a/system/base/providers/Core/DBConnection/PgSqlConnectionAdapter.php b/system/base/providers/Core/DBConnection/PgSqlConnectionAdapter.php new file mode 100644 index 0000000..10cf5bb --- /dev/null +++ b/system/base/providers/Core/DBConnection/PgSqlConnectionAdapter.php @@ -0,0 +1,14 @@ + + diff --git a/system/base/providers/Core/DBConnection/SqlLiteConnectionAdapter.php b/system/base/providers/Core/DBConnection/SqlLiteConnectionAdapter.php new file mode 100644 index 0000000..5267053 --- /dev/null +++ b/system/base/providers/Core/DBConnection/SqlLiteConnectionAdapter.php @@ -0,0 +1,14 @@ + + diff --git a/system/base/providers/Core/QueryBuilder.php b/system/base/providers/Core/QueryBuilder.php index 9fa6a46..cfe22d9 100644 --- a/system/base/providers/Core/QueryBuilder.php +++ b/system/base/providers/Core/QueryBuilder.php @@ -36,9 +36,9 @@ class QueryBuilder { * @api */ - public function __construct(PDO $connection, array $paramTypes){ + public function __construct(PDO $connection, array $paramTypes, $modelName){ - $this->extender = new QueryExtender($connection, $paramTypes); + $this->extender = new QueryExtender($connection, $paramTypes, $modelName); } diff --git a/system/base/providers/Core/QueryExtender.php b/system/base/providers/Core/QueryExtender.php index a093246..c697d0f 100644 --- a/system/base/providers/Core/QueryExtender.php +++ b/system/base/providers/Core/QueryExtender.php @@ -11,6 +11,7 @@ use \PDO; use \UnexpectedValueException; +use \Exception; use \ReflectionClass; class QueryExtender { @@ -45,6 +46,26 @@ class QueryExtender { protected $connection; + /** + * @var string - + */ + + protected $ownerModel; + + /** + * @var array - all join types which are allowed in a query + */ + + protected $allowedJoinTypes = array( + 'INNER', + 'RIGHT OUTER', + 'RIGHT', + 'LEFT OUTER', + 'LEFT', + 'FULL OUTER', + 'CROSS' + ); + /** * @var array - all conjunctions which are allowed in a query */ @@ -57,11 +78,12 @@ class QueryExtender { ); /** - * @var array - all operators which are allowed in a query + * @var array - all operators which are allowed in the {WHERE} clause of a query */ protected $allowedOperators = array( 'LIKE', + 'NOT LIKE', 'BETWEEN', 'IN', '>', @@ -85,7 +107,7 @@ class QueryExtender { * @api public */ - public function __construct(PDO $connection, array $paramTypes){ + public function __construct(PDO $connection, array $paramTypes, $modelName = NULL){ $this->queryString = ''; @@ -97,6 +119,8 @@ public function __construct(PDO $connection, array $paramTypes){ $this->reflClass = NULL; + $this->ownerModel = $modelName; + } /** @@ -117,14 +141,14 @@ public function get($columns, $clauseProps, $conjunction){ throw new UnexpectedValueException(); } - $conjunction = " ". strtoupper($conjunction) ." "; + $conjunction = " " . strtoupper($conjunction) . " "; # wrap the table name with quotes like so: `table` $table = $this->wrap($this->attribs['table']); - $_columns = implode(', ', array_map(array(&$this, 'wrap'), $columns)); + $_columns = implode(', ', array_map(array(&$this, 'addTablePrefix'), $columns)); - foreach ($clauseProps as $key => $value) { + foreach($clauseProps as $key => $value){ if(is_array($value)){ if(count($value) > 0){ # check that WHERE clause operator supplied is allowed !! @@ -136,7 +160,7 @@ public function get($columns, $clauseProps, $conjunction){ } # start building query string -> SELECT - $this->queryString .= "SELECT " . $_columns . " FROM " . $table . (count($clauseProps) > 0? " <;join> WHERE " . implode($conjunction, $this->prepareSelectPlaceholder($clauseProps)) : " <;join>"); + $this->queryString .= "SELECT <;distinct> " . $_columns . " FROM " . $table . (count($clauseProps) > 0? " <;join> WHERE " . implode($conjunction, $this->prepareSelectPlaceholder($clauseProps)) : " <;join>"); return $this; } @@ -151,9 +175,29 @@ public function get($columns, $clauseProps, $conjunction){ * @return \Providers\Core\QueryExtender - */ + public function distinct(){ + + if(starts_with($this->queryString, 'SELECT')){ + + $this->queryString = str_replace(' <;distinct>', ' DISTINCT', $this->queryString); + + } + return $this; + } + + /** + * Builds out a create table query + * + * + * + * + * @param ---- + * @return \Providers\Core\QueryExtender - + */ + public function table(){ - return; + return $this; } /** @@ -171,7 +215,7 @@ public function set($columns, $values, $clauseProps = array()){ # wrap the table name with quotes like so: `table` $table = $this->wrap($this->attribs['table']); - $_columns = implode(', ', array_map(array(&$this, 'wrap'), $columns)); + $_columns = implode(', ', array_map(array(&$this, 'addTablePrefix'), $columns)); # start building query string -> INSERT $this->queryString .= "INSERT INTO " . $table . "(" . $_columns . ") VALUES (" . implode(', ', $this->prepareInsertPlaceholder($values)) . ")"; @@ -202,7 +246,7 @@ public function let($columnValues, $clauseProps, $conjunction){ throw new UnexpectedValueException(); } - $conjunction = " ".strtoupper($conjunction) ." "; + $conjunction = " " . strtoupper($conjunction) . " "; # wrap the table name with quotes like so: `table` $table = $this->wrap($this->attribs['table']); @@ -224,17 +268,23 @@ public function let($columnValues, $clauseProps, $conjunction){ * * * @param $columns - columns - * @param $clauseProps - column/value pairs for WHERE clause in UPDATE query + * @param $clauseProps - column/value pairs for WHERE clause in DELETE query * @return \Providers\Core\QueryExtender - */ - public function del($columns){ + public function del(array $columns, array $clauseProps){ # wrap the table name with quotes like so: `table` $table = $this->wrap($this->attribs['table']); + $columns = implode(', ', array_map(array(&$this, 'addTablePrefix'), $columns)); + # start building query string -> DELETE - $this->queryString .= "DELETE " . implode(', ', $columns) . " FROM " . $table; + $this->queryString .= "DELETE " . $columns . " FROM " . $table; + + if(count($clauseProps) > 0){ + ; + } return $this; } @@ -247,6 +297,7 @@ public function del($columns){ * @param string $modelName - * @param string $joinType - * @return \Providers\Core\QueryExtender - + * @throws Exception, UnxepectedValueException */ public function with($modelName, $joinType = 'inner'){ @@ -260,7 +311,7 @@ public function with($modelName, $joinType = 'inner'){ $this->reflClass = new ReflectionClass($modelName); - $object = $reflClass->newInstanceWithoutContructor(); + $object = $this->reflClass->newInstanceWithoutContructor(); $__atrribs = $object->getAttributes(); @@ -271,14 +322,29 @@ public function with($modelName, $joinType = 'inner'){ $parentReference = $this->wrap($this->attribs['key']); - $childReference = $this->wrap($__attribs['relations'][$modelName]); + $relations = $__attribs['relations']; + + $parentModelName = $this->ownerModel; - # start building query string -> {INNER|LEFT|OUTER RIGHT|OUTER LEFT|CROSS} JOIN - $joinExp = " {$joinType} JOIN `{$joinTable}` ON `{$table}`.`{$parentReference}` = `{$joinTable}`.`{$childReference}`"; + if(!array_key_exists($parentModelName, $relations)){ + + throw new Exception("No relations exists between Model -> {$parentModelName} and Model -> {$modelName}"); + } + + $childReference = $this->wrap($relations[$parentModelName]); + + /* if the join type isn't valid, throw an error */ + + if(!in_array($joinType, $this->allowedJoinTypes)){ + + throw new UnexpectedValueException("Invalid join type found"); + } + # start building query string -> JOIN + $joinExp = " {$joinType} JOIN {$joinTable} ON {$table}.{$parentReference} = {$joinTable}.{$childReference}"; $this->queryString = str_replace(' <;join>', $joinExp, $this->queryString); - return $this; + return $this; } /** @@ -386,6 +452,7 @@ public function exec($limit = 0, $offset = 0){ case 'select': $this->queryString .= implode(',', $stoppers); $this->queryString = str_replace(' <;join>', '', $this->queryString); + $this->queryString = str_replace(' <;distinct>', '', $this->queryString); $result = db_get($this->connection, $this->paramTypes, $this->queryString, $this->parmeterizeValues($this->paramValues)); break; case 'insert': @@ -425,6 +492,11 @@ private function wrap($attributeName, $char = "`"){ return $char.$attributeName.$char; } + private function addTablePrefix($column){ + + return $this->wrap($this->attribs['table']) . '.' . $this->wrap($column); + } + private function prepareInsertPlaceholder($props){ $this->paramValues = $props; diff --git a/system/base/providers/Services/DBService.php b/system/base/providers/Services/DBService.php index 0949275..49c4ed9 100644 --- a/system/base/providers/Services/DBService.php +++ b/system/base/providers/Services/DBService.php @@ -10,6 +10,8 @@ namespace Providers\Services; use \PDO; +use \Exception; +use \PDOException; use \Providers\Core\QueryBuilder as Builder; class DBService { @@ -211,9 +213,9 @@ protected function connect($env_file = ''){ $this->config['engines']['mysql'] = $engine; - }catch (\Exception $e) { ## PDOException ## + }catch (PDOException $e) { - ; //($e->getMessage()); + throw $e; } } @@ -241,7 +243,7 @@ protected function hasConnection(){ * @return \Providers\Core\QueryBuilder $builder; */ - public function getBuilder(array $modelAttributes){ + public function getBuilder(array $modelAttributes, $modelName){ $db_connection = $this->getConnection(); @@ -256,11 +258,11 @@ public function getBuilder(array $modelAttributes){ if(is_null($db_collection)){ - throw new \Exception("No Database Connection Found, .env File Probably Missing"); + throw new Exception("No Database Connection Found, .env File Probably Missing"); } - $builder = $this->builders[$table] = new Builder($db_collection, $p_types); + $builder = $this->builders[$table] = new Builder($db_collection, $p_types, $modelName); $builder->setAttributes($modelAttributes); diff --git a/system/base/providers/Services/EnvService.php b/system/base/providers/Services/EnvService.php index cdbce29..d5cb91d 100644 --- a/system/base/providers/Services/EnvService.php +++ b/system/base/providers/Services/EnvService.php @@ -81,6 +81,10 @@ private function setupAppEnvironment (){ ini_set("file_uploads", "Off"); } + + $extensions = get_loaded_extensions(); + + // More code here... } private function setupAppPaths(){ diff --git a/views/forcedlogout/index.view b/views/forcedlogout/index.view new file mode 100644 index 0000000..233de2b --- /dev/null +++ b/views/forcedlogout/index.view @@ -0,0 +1,9 @@ + + + + Force Logout + + +
+ + \ No newline at end of file