Skip to content

Commit 574943c

Browse files
committed
Merge pull request #257 from avbdr/master
new functions
2 parents 6d61f87 + fb611b6 commit 574943c

File tree

4 files changed

+108
-21
lines changed

4 files changed

+108
-21
lines changed

MysqliDb.php

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ class MysqliDb
120120
*/
121121
public $returnType = 'Array';
122122

123+
/**
124+
* Should join() results be nested by table
125+
* @var boolean
126+
*/
127+
protected $_nestJoin = false;
128+
private $_tableName = '';
123129
/**
124130
* Variables for query execution tracing
125131
*
@@ -220,6 +226,8 @@ protected function reset()
220226
$this->_query = null;
221227
$this->_queryOptions = array();
222228
$this->returnType = 'Array';
229+
$this->_nestJoin = false;
230+
$this->_tableName = '';
223231
}
224232

225233
/**
@@ -332,7 +340,7 @@ public function query($query, $numRows = null)
332340
public function setQueryOption ($options) {
333341
$allowedOptions = Array ('ALL','DISTINCT','DISTINCTROW','HIGH_PRIORITY','STRAIGHT_JOIN','SQL_SMALL_RESULT',
334342
'SQL_BIG_RESULT','SQL_BUFFER_RESULT','SQL_CACHE','SQL_NO_CACHE', 'SQL_CALC_FOUND_ROWS',
335-
'LOW_PRIORITY','IGNORE','QUICK');
343+
'LOW_PRIORITY','IGNORE','QUICK', 'MYSQLI_NESTJOIN');
336344
if (!is_array ($options))
337345
$options = Array ($options);
338346

@@ -341,7 +349,10 @@ public function setQueryOption ($options) {
341349
if (!in_array ($option, $allowedOptions))
342350
die ('Wrong query option: '.$option);
343351

344-
$this->_queryOptions[] = $option;
352+
if ($option == 'MYSQLI_NESTJOIN')
353+
$this->_nestJoin = true;
354+
else
355+
$this->_queryOptions[] = $option;
345356
}
346357

347358
return $this;
@@ -372,8 +383,9 @@ public function get($tableName, $numRows = null, $columns = '*')
372383
$columns = '*';
373384

374385
$column = is_array($columns) ? implode(', ', $columns) : $columns;
386+
$this->_tableName = self::$prefix . $tableName;
375387
$this->_query = 'SELECT ' . implode(' ', $this->_queryOptions) . ' ' .
376-
$column . " FROM " .self::$prefix . $tableName;
388+
$column . " FROM " . $this->_tableName;
377389
$stmt = $this->_buildQuery($numRows);
378390

379391
if ($this->isSubQuery)
@@ -827,8 +839,14 @@ protected function _dynamicBindResults(mysqli_stmt $stmt)
827839
if ($field->type == $mysqlLongType)
828840
$shouldStoreResult = true;
829841

830-
$row[$field->name] = null;
831-
$parameters[] = & $row[$field->name];
842+
if ($this->_nestJoin && $field->table != $this->_tableName) {
843+
$field->table = substr ($field->table, strlen (self::$prefix));
844+
$row[$field->table][$field->name] = null;
845+
$parameters[] = & $row[$field->table][$field->name];
846+
} else {
847+
$row[$field->name] = null;
848+
$parameters[] = & $row[$field->name];
849+
}
832850
}
833851

834852
// avoid out of memory bug in php 5.2 and 5.3. Mysqli allocates lot of memory for long*
@@ -844,8 +862,14 @@ protected function _dynamicBindResults(mysqli_stmt $stmt)
844862
while ($stmt->fetch()) {
845863
if ($this->returnType == 'Object') {
846864
$x = new stdClass ();
847-
foreach ($row as $key => $val)
848-
$x->$key = $val;
865+
foreach ($row as $key => $val) {
866+
if (is_array ($val)) {
867+
$x->$key = new stdClass ();
868+
foreach ($val as $k => $v)
869+
$x->$key->$k = $v;
870+
} else
871+
$x->$key = $val;
872+
}
849873
} else {
850874
$x = array();
851875
foreach ($row as $key => $val)

dbObject.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,23 @@ After that you can get related object via variable names defined as keys.
146146
...
147147

148148
$user = user::byId (1);
149-
// sql: select * from $persontable where id = $personValue
149+
// sql: select * from users where id = $personValue
150150
echo $user->person->firstName . " " . $user->person->lastName . " have the following products:\n";
151+
// one more sql: select * from person where id=x
151152
```
153+
Please note, that following way of querying will execute 2 sql queries:
154+
1. select * from users where id=1;
155+
2. select * from person where id=x
152156

153-
In HasMany Array should be defined target object name (product in example) and a relation key (userid).
157+
To optimize this into single select join query use with() method.
158+
```php
159+
$user = user::with ('person')->byId (1);
160+
// sql: select * from users left join person on person.id = users.id wher id = 1;
161+
echo $user->person->firstName . " " . $user->person->lastName . " have the following products:\n";
162+
```
154163

155164
##HasMany example:
165+
In HasMany Array should be defined target object name (product in example) and a relation key (userid).
156166
```php
157167
protected $relations = Array (
158168
'products' => Array ("hasMany", "product", 'userid')

dbObject.php

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ public function __set ($name, $value) {
131131
* @return mixed
132132
*/
133133
public function __get ($name) {
134+
if (isset ($this->data[$name]) && $this->data[$name] instanceof dbObject)
135+
return $this->data[$name];
136+
134137
if (property_exists ($this, 'relations') && isset ($this->relations[$name])) {
135138
$relationType = strtolower ($this->relations[$name][0]);
136139
$modelName = $this->relations[$name][1];
@@ -306,10 +309,11 @@ private function byId ($id, $fields = null) {
306309
* @return dbObject
307310
*/
308311
private function getOne ($fields = null) {
309-
$results = $this->db->getOne ($this->dbTable, $fields);
312+
$this->processHasOneWith ();
313+
$results = $this->db->ArrayBuilder()->getOne ($this->dbTable, $fields);
310314
$this->processArrays ($results);
311315
$this->data = $results;
312-
$this->processWith ($results);
316+
$this->processAllWith ($results);
313317
if ($this->returnType == 'Json')
314318
return json_encode ($results);
315319
if ($this->returnType == 'Array')
@@ -333,17 +337,19 @@ private function getOne ($fields = null) {
333337
*/
334338
private function get ($limit = null, $fields = null) {
335339
$objects = Array ();
336-
$results = $this->db->get ($this->dbTable, $limit, $fields);
340+
$this->processHasOneWith ();
341+
$results = $this->db->ArrayBuilder()->get ($this->dbTable, $limit, $fields);
337342
foreach ($results as &$r) {
338343
$this->processArrays ($r);
339344
$this->data = $r;
340-
$this->processWith ($r);
345+
$this->processAllWith ($r, false);
341346
if ($this->returnType == 'Object') {
342347
$item = new static ($r);
343348
$item->isNew = false;
344349
$objects[] = $item;
345350
}
346351
}
352+
$this->_with = Array();
347353
if ($this->returnType == 'Object')
348354
return $objects;
349355

@@ -362,7 +368,10 @@ private function get ($limit = null, $fields = null) {
362368
* @return dbObject
363369
*/
364370
private function with ($objectName) {
365-
$this->_with[] = $objectName;
371+
if (!property_exists ($this, 'relations') && !isset ($this->relations[$name]))
372+
die ("No relation with name $objectName found");
373+
374+
$this->_with[$objectName] = $this->relations[$objectName];
366375

367376
return $this;
368377
}
@@ -393,7 +402,7 @@ private function join ($objectName, $key = null, $joinType = 'LEFT') {
393402
* @return int
394403
*/
395404
private function count () {
396-
$res = $this->db->getValue ($this->dbTable, "count(*)");
405+
$res = $this->db->ArrayBuilder()->getValue ($this->dbTable, "count(*)");
397406
return $res['cnt'];
398407
}
399408

@@ -457,7 +466,7 @@ public static function __callStatic ($method, $arg) {
457466
*/
458467
public function toArray () {
459468
$data = $this->data;
460-
$this->processWith ($data);
469+
$this->processAllWith ($data);
461470
foreach ($data as &$d) {
462471
if ($d instanceof dbObject)
463472
$d = $d->data;
@@ -484,15 +493,59 @@ public function __toString () {
484493
}
485494

486495
/**
496+
* Function queries hasMany relations if needed and also converts hasOne object names
497+
*
487498
* @param array $data
488499
*/
489-
private function processWith (&$data) {
500+
private function processAllWith (&$data, $shouldReset = true) {
490501
if (count ($this->_with) == 0)
491502
return;
492-
foreach ($this->_with as $w)
493-
$data[$w] = $this->$w;
494503

495-
$this->_with = Array();
504+
foreach ($this->_with as $name => $opts) {
505+
$relationType = strtolower ($opts[0]);
506+
$modelName = $opts[1];
507+
if ($relationType == 'hasone') {
508+
$obj = new $modelName;
509+
$table = $obj->dbTable;
510+
511+
if (!isset ($data[$table])) {
512+
$data[$name] = $this->$name;
513+
continue;
514+
}
515+
if ($this->returnType == 'Object') {
516+
$item = new $modelName ($data[$table]);
517+
$item->returnType = $this->returnType;
518+
$item->isNew = false;
519+
$data[$name] = $item;
520+
} else {
521+
$data[$name] = $data[$table];
522+
}
523+
unset ($data[$table]);
524+
}
525+
else
526+
$data[$name] = $this->$name;
527+
}
528+
if ($shouldReset)
529+
$this->_with = Array();
530+
}
531+
532+
/*
533+
* Function building hasOne joins for get/getOne method
534+
*/
535+
private function processHasOneWith () {
536+
if (count ($this->_with) == 0)
537+
return;
538+
foreach ($this->_with as $name => $opts) {
539+
$relationType = strtolower ($opts[0]);
540+
$modelName = $opts[1];
541+
$key = null;
542+
if (isset ($opts[2]))
543+
$key = $opts[2];
544+
if ($relationType == 'hasone') {
545+
$this->db->setQueryOption ("MYSQLI_NESTJOIN");
546+
$this->join ($modelName, $key);
547+
}
548+
}
496549
}
497550

498551
/**

tests/dbObjectTests.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ function createTable ($name, $data) {
131131

132132

133133
$products = product::ArrayBuilder()->with('userId')->get(2);
134-
if (!is_array ($products[0]['userId'])) {
134+
if (!is_array ($products[0]['userId']) || !is_array ($products[1]['userId'])) {
135135
echo "Error in with processing in get";
136136
exit;
137137
}

0 commit comments

Comments
 (0)