Commit fb611b61 authored by Alexander Butenko's avatar Alexander Butenko

Optimize with() handling by using joins. Fixed a bug with with() on multiple rows

parent 19b4a35e
...@@ -146,13 +146,23 @@ After that you can get related object via variable names defined as keys. ...@@ -146,13 +146,23 @@ After that you can get related object via variable names defined as keys.
... ...
$user = user::byId (1); $user = user::byId (1);
// sql: select * from $persontable where id = $personValue // sql: select * from users where id = $personValue
echo $user->person->firstName . " " . $user->person->lastName . " have the following products:\n"; echo $user->person->firstName . " " . $user->person->lastName . " have the following products:\n";
// one more sql: select * from person where id=x
``` ```
Please note, that following way of querying will execute 2 sql queries:
1. select * from users where id=1;
2. select * from person where id=x
In HasMany Array should be defined target object name (product in example) and a relation key (userid). To optimize this into single select join query use with() method.
```php
$user = user::with ('person')->byId (1);
// sql: select * from users left join person on person.id = users.id wher id = 1;
echo $user->person->firstName . " " . $user->person->lastName . " have the following products:\n";
```
##HasMany example: ##HasMany example:
In HasMany Array should be defined target object name (product in example) and a relation key (userid).
```php ```php
protected $relations = Array ( protected $relations = Array (
'products' => Array ("hasMany", "product", 'userid') 'products' => Array ("hasMany", "product", 'userid')
......
...@@ -131,6 +131,9 @@ class dbObject { ...@@ -131,6 +131,9 @@ class dbObject {
* @return mixed * @return mixed
*/ */
public function __get ($name) { public function __get ($name) {
if (isset ($this->data[$name]) && $this->data[$name] instanceof dbObject)
return $this->data[$name];
if (property_exists ($this, 'relations') && isset ($this->relations[$name])) { if (property_exists ($this, 'relations') && isset ($this->relations[$name])) {
$relationType = strtolower ($this->relations[$name][0]); $relationType = strtolower ($this->relations[$name][0]);
$modelName = $this->relations[$name][1]; $modelName = $this->relations[$name][1];
...@@ -306,10 +309,11 @@ class dbObject { ...@@ -306,10 +309,11 @@ class dbObject {
* @return dbObject * @return dbObject
*/ */
private function getOne ($fields = null) { private function getOne ($fields = null) {
$results = $this->db->getOne ($this->dbTable, $fields); $this->processHasOneWith ();
$results = $this->db->ArrayBuilder()->getOne ($this->dbTable, $fields);
$this->processArrays ($results); $this->processArrays ($results);
$this->data = $results; $this->data = $results;
$this->processWith ($results); $this->processAllWith ($results);
if ($this->returnType == 'Json') if ($this->returnType == 'Json')
return json_encode ($results); return json_encode ($results);
if ($this->returnType == 'Array') if ($this->returnType == 'Array')
...@@ -333,17 +337,19 @@ class dbObject { ...@@ -333,17 +337,19 @@ class dbObject {
*/ */
private function get ($limit = null, $fields = null) { private function get ($limit = null, $fields = null) {
$objects = Array (); $objects = Array ();
$results = $this->db->get ($this->dbTable, $limit, $fields); $this->processHasOneWith ();
$results = $this->db->ArrayBuilder()->get ($this->dbTable, $limit, $fields);
foreach ($results as &$r) { foreach ($results as &$r) {
$this->processArrays ($r); $this->processArrays ($r);
$this->data = $r; $this->data = $r;
$this->processWith ($r); $this->processAllWith ($r, false);
if ($this->returnType == 'Object') { if ($this->returnType == 'Object') {
$item = new static ($r); $item = new static ($r);
$item->isNew = false; $item->isNew = false;
$objects[] = $item; $objects[] = $item;
} }
} }
$this->_with = Array();
if ($this->returnType == 'Object') if ($this->returnType == 'Object')
return $objects; return $objects;
...@@ -362,7 +368,10 @@ class dbObject { ...@@ -362,7 +368,10 @@ class dbObject {
* @return dbObject * @return dbObject
*/ */
private function with ($objectName) { private function with ($objectName) {
$this->_with[] = $objectName; if (!property_exists ($this, 'relations') && !isset ($this->relations[$name]))
die ("No relation with name $objectName found");
$this->_with[$objectName] = $this->relations[$objectName];
return $this; return $this;
} }
...@@ -393,7 +402,7 @@ class dbObject { ...@@ -393,7 +402,7 @@ class dbObject {
* @return int * @return int
*/ */
private function count () { private function count () {
$res = $this->db->getValue ($this->dbTable, "count(*)"); $res = $this->db->ArrayBuilder()->getValue ($this->dbTable, "count(*)");
return $res['cnt']; return $res['cnt'];
} }
...@@ -457,7 +466,7 @@ class dbObject { ...@@ -457,7 +466,7 @@ class dbObject {
*/ */
public function toArray () { public function toArray () {
$data = $this->data; $data = $this->data;
$this->processWith ($data); $this->processAllWith ($data);
foreach ($data as &$d) { foreach ($data as &$d) {
if ($d instanceof dbObject) if ($d instanceof dbObject)
$d = $d->data; $d = $d->data;
...@@ -484,17 +493,61 @@ class dbObject { ...@@ -484,17 +493,61 @@ class dbObject {
} }
/** /**
* Function queries hasMany relations if needed and also converts hasOne object names
*
* @param array $data * @param array $data
*/ */
private function processWith (&$data) { private function processAllWith (&$data, $shouldReset = true) {
if (count ($this->_with) == 0) if (count ($this->_with) == 0)
return; return;
foreach ($this->_with as $w)
$data[$w] = $this->$w;
foreach ($this->_with as $name => $opts) {
$relationType = strtolower ($opts[0]);
$modelName = $opts[1];
if ($relationType == 'hasone') {
$obj = new $modelName;
$table = $obj->dbTable;
if (!isset ($data[$table])) {
$data[$name] = $this->$name;
continue;
}
if ($this->returnType == 'Object') {
$item = new $modelName ($data[$table]);
$item->returnType = $this->returnType;
$item->isNew = false;
$data[$name] = $item;
} else {
$data[$name] = $data[$table];
}
unset ($data[$table]);
}
else
$data[$name] = $this->$name;
}
if ($shouldReset)
$this->_with = Array(); $this->_with = Array();
} }
/*
* Function building hasOne joins for get/getOne method
*/
private function processHasOneWith () {
if (count ($this->_with) == 0)
return;
foreach ($this->_with as $name => $opts) {
$relationType = strtolower ($opts[0]);
$modelName = $opts[1];
$key = null;
if (isset ($opts[2]))
$key = $opts[2];
if ($relationType == 'hasone') {
$this->db->setQueryOption ("MYSQLI_NESTJOIN");
$this->join ($modelName, $key);
}
}
}
/** /**
* @param array $data * @param array $data
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment