Commit baf4d2a1 authored by Alexander Butenko's avatar Alexander Butenko

Merge pull request #235 from avbdr/master

new dbObject class
parents fef36b1d a96ea382
...@@ -264,7 +264,7 @@ class MysqliDb ...@@ -264,7 +264,7 @@ class MysqliDb
/** /**
* *
* @param string $query Contains a user-provided select query. * @param string $query Contains a user-provided select query.
* @param int $numRows The number of rows total to return. * @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset)
* *
* @return array Contains the returned rows from the query. * @return array Contains the returned rows from the query.
*/ */
...@@ -321,7 +321,8 @@ class MysqliDb ...@@ -321,7 +321,8 @@ class MysqliDb
* A convenient SELECT * function. * A convenient SELECT * function.
* *
* @param string $tableName The name of the database table to work with. * @param string $tableName The name of the database table to work with.
* @param integer $numRows The number of rows total to return. * @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset)
* or only $count
* *
* @return array Contains the returned rows from the select query. * @return array Contains the returned rows from the select query.
*/ */
...@@ -453,7 +454,8 @@ class MysqliDb ...@@ -453,7 +454,8 @@ class MysqliDb
* Delete query. Call the "where" method first. * Delete query. Call the "where" method first.
* *
* @param string $tableName The name of the database table to work with. * @param string $tableName The name of the database table to work with.
* @param integer $numRows The number of rows to delete. * @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset)
* or only $count
* *
* @return boolean Indicates success. 0 or 1. * @return boolean Indicates success. 0 or 1.
*/ */
...@@ -694,7 +696,8 @@ class MysqliDb ...@@ -694,7 +696,8 @@ class MysqliDb
* any passed update data, and the desired rows. * any passed update data, and the desired rows.
* It then builds the SQL query. * It then builds the SQL query.
* *
* @param int $numRows The number of rows total to return. * @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset)
* or only $count
* @param array $tableData Should contain an array of data for updating the database. * @param array $tableData Should contain an array of data for updating the database.
* *
* @return mysqli_stmt Returns the $stmt object. * @return mysqli_stmt Returns the $stmt object.
...@@ -937,7 +940,6 @@ class MysqliDb ...@@ -937,7 +940,6 @@ class MysqliDb
/** /**
* Abstraction method that will build the LIMIT part of the WHERE statement * Abstraction method that will build the LIMIT part of the WHERE statement
* *
* @param int $numRows The number of rows total to return.
*/ */
protected function _buildOrderBy () { protected function _buildOrderBy () {
if (empty ($this->_orderBy)) if (empty ($this->_orderBy))
...@@ -957,7 +959,8 @@ class MysqliDb ...@@ -957,7 +959,8 @@ class MysqliDb
/** /**
* Abstraction method that will build the LIMIT part of the WHERE statement * Abstraction method that will build the LIMIT part of the WHERE statement
* *
* @param int $numRows The number of rows total to return. * @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset)
* or only $count
*/ */
protected function _buildLimit ($numRows) { protected function _buildLimit ($numRows) {
if (!isset ($numRows)) if (!isset ($numRows))
......
dbObject - model implementation on top of the MysqliDb
Please note, that this library is not pretending to be a full stack ORM but a simple OOP wrapper for mysqlidb
<hr>
###Initialization
1. Include mysqlidb and dbObject classes.
2. If you want to use model autoloading instead of manually including them in the scripts use autoload () method.
```php
require_once ("libs/MysqliDb.php");
require_once ("libs/dbObject.php");
// db instance
$db = new Mysqlidb ('localhost', 'user', '', 'testdb');
// enable class autoloading
dbObject::autoload ("models");
```
3. Create simple user class (models/user.php):
```php
class user extends dbObject {
protected $dbTable = "users";
protected $primaryKey = "id";
protected $dbFields = Array (
'login' => Array ('text', 'required'),
'password' => Array ('text'),
'createdAt' => Array ('datetime'),
'updatedAt' => Array ('datetime'),
);
}
```
###Insert Row
1. OOP Way. Just create new object of a needed class, fill it in and call save () method. Save will return
record id in case of success and false in case if insert will fail.
```php
$user = new user;
$user->login = 'demo';
$user->password = 'demo';
$id = $user->save ();
if ($id)
echo "user created with id = " . $id;
```
2. Using arrays
```php
$data = Array ('login' => 'demo',
'password' => 'demo');
$user = new user ($data);
$id = $user->save ();
if ($id == null) {
print_r ($user->errors);
echo $db->getLastError;
} else
echo "user created with id = " . $id;
```
3. Multisave
```php
$user = new user;
$user->login = 'demo';
$user->pass = 'demo';
$p = new product;
$p->title = "Apples";
$p->price = 0.5;
$p->seller = $user;
$p->save ();
```
After save() is call both new objects (user and product) will be saved.
###Selects
Retrieving objects from the database is pretty much the same process of a get ()/getOne () execution without a need to specify table name.
All mysqlidb functions like where(), orWhere(), orderBy(), join etc are supported.
Please note that objects returned with join() will not save changes to a joined properties. For this you can use relationships.
Select row by primary key
```php
$user = user::byId (1);
echo $user->login;
```
Get all users
```php
$users = user::orderBy ('id')->get ();
foreach (users as $u) {
echo $u->login;
}
```
Using where with limit
```php
$users = user::where ("login", "demo")->get (Array (10, 20));
foreach (users as $u) ...
```
###Update
To update model properties just set them and call save () method. As well values that needed to by changed could be passed as an array to the save () method.
```php
$user = user::byId (1);
$user->password = 'demo2';
$user->save ();
```
```php
$data = Array ('password', 'demo2');
$user = user::byId (1);
$user->save ($data);
```
###Delete
Use delete() method on any loaded object.
```php
$user = user::byId (1);
$user->delete ();
```
###Relations
Currently dbObject supports only hasMany and hasOne relations. To use them declare $relations array in the model class.
After that you can get related object via variable names defined as keys.
HasOne example:
```php
protected $relations = Array (
'person' => Array ("hasOne", "person", 'id');
);
...
$user = user::byId (1);
// sql: select * from $persontable where id = $personValue
echo $user->person->firstName . " " . $user->person->lastName . " have the following products:\n";
```
In HasMany Array should be defined target object name (product in example) and a relation key (userid).
HasMany example:
```php
protected $relations = Array (
'products' => Array ("hasMany", "product", 'userid')
);
...
$user = user::byId (1);
// sql: select * from $product_table where userid = $userPrimaryKey
foreach ($user->products as $p) {
echo $p->title;
}
```
###Timestamps
Library provides a transparent way to set timestamps of an object creation and its modification:
To enable that define $timestamps array as follows:
```php
protected $timestamps = Array ('createdAt', 'updatedAt');
```
Field names cant be changed.
###Validation and Error checking
Before saving and updating the row dbObject do input validation. In case validation rules are set but their criteria is not met
then save() will return an error with its description. For example:
```php
$id = $user->save();
if (!$id) {
// show all validation errors
print_r ($user->errors);
echo $db->getLastQuery();
echo $db->getLastError();
}
echo "user were created with id" . $id;
```
Validation rules must be defined in $dbFields array.
```php
protected $dbFields = Array (
'login' => Array ('text', 'required'),
'password' => Array ('text'),
'createdAt' => Array ('datetime'),
'updatedAt' => Array ('datetime'),
'custom' => Array ('/^test/'),
);
```
First parameter is a field type. Types could be the one of following: text, bool, int, datetime or a custom regexp.
Second parameter is 'required' and its defines that following entry field be always defined.
###Array as return values
dbObject can return its data as array instead of object. To do that ArrayBuilder() function should be used in the beginning of the call.
```php
$user = user::ArrayBuilder()->byId (1);
echo $user['login'];
$users = user::ArrayBuilder()->orderBy ("id", "desc")->get ();
foreach ($users as $u)
echo $u['login'];
```
Following call will return data only of the called instance without any relations data. Use with() function to include relation data as well.
```php
$user = user::ArrayBuilder()->with ("product")->byId (1);
print_r ($user['products']);
```
###Object serialization
Object could be easily converted to a json string or an array.
```php
$user = user::byId (1);
// echo will display json representation of an object
echo $user;
// userJson will contain json representation of an object
$userJson = $user->toJson ();
// userArray will contain array representation of an object
$userArray = $user->toArray ();
```
###Examples
Please look for a use examples in tests/dbObjectTests.php file and test models inside the tests/models/ directory
<?php
/**
* Mysqli Model wrapper
*
* @category Database Access
* @package MysqliDb
* @author Alexander V. Butenko <a.butenka@gmail.com>
* @copyright Copyright (c) 2015
* @license http://opensource.org/licenses/gpl-3.0.html GNU Public License
* @version 2.0
*
* @method int count ()
* @method mixed byId (string $id, mixed $fields)
* @method mixed get (mixed $limit, mixed $fields)
* @method mixed getOne (mixed $fields)
* @method mixed paginate (int $page, array $fields)
* @method dbObject query ($query, $numRows)
* @method dbObject rawQuery ($query, $bindParams, $sanitize)
* @method dbObject join (string $objectName, string $key, string $joinType)
* @method dbObject with (string $objectName)
* @method dbObject groupBy (string $groupByField)
* @method dbObject orderBy ($orderByField, $orderbyDirection, $customFields)
* @method dbObject where ($whereProp, $whereValue, $operator)
* @method dbObject orWhere ($whereProp, $whereValue, $operator)
* @method dbObject setQueryOption ($options)
* @method dbObject setTrace ($enabled, $stripPrefix)
* @method dbObject withTotalCount ()
* @method dbObject startTransaction ()
* @method dbObject commit ()
* @method dbObject rollback ()
* @method dbObject ping ()
* @method string getLastError ()
* @method string getLastQuery ()
**/
class dbObject {
/**
* Working instance of MysqliDb created earlier
*
* @var MysqliDb
*/
private $db;
/**
* Models path
*
* @var modelPath
*/
private static $modelPath;
/**
* An array that holds object data
*
* @var array
*/
public $data;
/**
* Flag to define is object is new or loaded from database
*
* @var boolean
*/
public $isNew = true;
/**
* Return type: 'Array' to return results as array, 'Object' as object
*
* @var string
*/
public $returnType = 'Object';
/**
* An array that holds has* objects which should be loaded togeather with main
* object togeather with main object
*
* @var string
*/
private $_with = Array();
/**
* Per page limit for pagination
*
* @var int
*/
public $pageLimit = 20;
/**
* Variable that holds total pages count of last paginate() query
*
* @var int
*/
public $totalPages = 0;
/**
* An array that holds insert/update/select errors
*
* @var array
*/
public $errors = null;
/**
* @param array $data Data to preload on object creation
*/
public function __construct ($data = null) {
$this->db = MysqliDb::getInstance();
if ($data)
$this->data = $data;
}
/**
* Magic setter function
*
* @return mixed
*/
public function __set ($name, $value) {
$this->data[$name] = $value;
}
/**
* Magic getter function
*
* @param $name Variable name
*
* @return mixed
*/
public function __get ($name) {
if (property_exists ($this, 'relations') && isset ($this->relations[$name])) {
$relationType = strtolower ($this->relations[$name][0]);
$modelName = $this->relations[$name][1];
switch ($relationType) {
case 'hasone':
$obj = new $modelName;
$obj->returnType = $this->returnType;
return $obj->byId($this->data[$name]);
break;
case 'hasmany':
$key = $this->relations[$name][2];
$obj = new $modelName;
$obj->returnType = $this->returnType;
return $obj->where($key, $this->data[$this->primaryKey])->get();
break;
default:
break;
}
}
if (isset ($this->data[$name])) {
return $this->data[$name];
}
if (property_exists ($this->db, $name))
return $this->db->$name;
}
public function __isset ($name) {
if (isset ($this->data[$name]))
return isset ($this->data[$name]);
if (property_exists ($this->db, $name))
return isset ($this->db->$name);
}
public function __unset ($name) {
unset ($this->data[$name]);
}
/**
* Helper function to create dbObject with Array return type
*
* @return dbObject
*/
public static function ArrayBuilder () {
$obj = new static;
$obj->returnType = 'Array';
return $obj;
}
/**
* Helper function to create dbObject with Object return type.
* Added for consistency. Works same way as new $objname ()
*
* @return dbObject
*/
public static function ObjectBuilder () {
$obj = new static;
return $obj;
}
/**
* @return mixed insert id or false in case of failure
*/
public function insert () {
if (!empty ($this->timestamps) && in_array ("createdAt", $this->timestamps))
$this->createdAt = date("Y-m-d H:i:s");
$sqlData = $this->prepareData ();
if (!$this->validate ($sqlData))
return false;
$id = $this->db->insert ($this->dbTable, $sqlData);
if (!empty ($this->primaryKey))
$this->data[$this->primaryKey] = $id;
$this->isNew = false;
return $id;
}
/**
* @param array $data Optional update data to apply to the object
*/
public function update ($data = null) {
if (empty ($this->dbFields))
return false;
if (empty ($this->data[$this->primaryKey]))
return false;
if ($data) {
foreach ($data as $k => $v)
$this->$k = $v;
}
if (!empty ($this->timestamps) && in_array ("updatedAt", $this->timestamps))
$this->updatedAt = date("Y-m-d H:i:s");
$sqlData = $this->prepareData ();
if (!$this->validate ($sqlData))
return false;
$this->db->where ($this->primaryKey, $this->data[$this->primaryKey]);
return $this->db->update ($this->dbTable, $sqlData);
}
/**
* Save or Update object
*
* @return mixed insert id or false in case of failure
*/
public function save ($data = null) {
if ($this->isNew)
return $this->insert();
return $this->update($data);
}
/**
* Delete method. Works only if object primaryKey is defined
*
* @return boolean Indicates success. 0 or 1.
*/
public function delete () {
if (empty ($this->data[$this->primaryKey]))
return false;
$this->db->where ($this->primaryKey, $this->data[$this->primaryKey]);
return $this->db->delete ($this->dbTable);
}
/**
* Get object by primary key.
*
* @access public
* @param $id Primary Key
* @param array|string $fields Array or coma separated list of fields to fetch
*
* @return dbObject|array
*/
private function byId ($id, $fields = null) {
$this->db->where ($this->dbTable . '.' . $this->primaryKey, $id);
return $this->getOne ($fields);
}
/**
* Convinient function to fetch one object. Mostly will be togeather with where()
*
* @access public
* @param array|string $fields Array or coma separated list of fields to fetch
*
* @return dbObject
*/
private function getOne ($fields = null) {
$results = $this->db->getOne ($this->dbTable, $fields);
$this->processArrays ($results);
$this->processWith ($results);
if ($this->returnType == 'Array')
return $results;
$item = new static ($results);
$item->isNew = false;
return $item;
}
/**
* Fetch all objects
*
* @access public
* @param integer|array $limit Array to define SQL limit in format Array ($count, $offset)
or only $count
* @param array|string $fields Array or coma separated list of fields to fetch
*
* @return array Array of dbObjects
*/
private function get ($limit = null, $fields = null) {
$objects = Array ();
$results = $this->db->get ($this->dbTable, $limit, $fields);
foreach ($results as &$r) {
$this->processArrays ($r);
$this->processWith ($r);
if ($this->returnType == 'Object') {
$item = new static ($r);
$item->isNew = false;
$objects[] = $item;
}
}
if ($this->returnType == 'Object')
return $objects;
return $results;
}
/**
* Function to set witch hasOne or hasMany objects should be loaded togeather with a main object
*
* @access public
* @param string $objectName Object Name
*
* @return dbObject
*/
private function with ($objectName) {
$this->_with[] = $objectName;
return $this;
}
/**
* Function to join object with another object.
*
* @access public
* @param string $objectName Object Name
* @param string $key Key for a join from primary object
* @param string $joinType SQL join type: LEFT, RIGHT, INNER, OUTER
*
* @return dbObject
*/
private function join ($objectName, $key = null, $joinType = 'LEFT') {
$joinObj = new $objectName;
if (!$key)
$key = $objectName . "id";
$joinStr = "{$this->dbTable}.{$key} = {$joinObj->dbTable}.{$joinObj->primaryKey}";
$this->db->join ($joinObj->dbTable, $joinStr, $joinType);
return $this;
}
/**
* Function to get a total records count
*
* @return int
*/
private function count () {
$res = $this->db->getValue ($this->dbTable, "count(*)");
return $res['cnt'];
}
/**
* Pagination wraper to get()
*
* @access public
* @param int $page Page number
* @param array|string $fields Array or coma separated list of fields to fetch
* @return array
*/
private function paginate ($page, $fields = null) {
$offset = $this->pageLimit * ($page - 1);
$this->db->withTotalCount();
$results = $this->get (Array ($this->pageLimit, $offset), $fields);
$this->totalPages = round ($this->db->totalCount / $this->pageLimit);
return $results;
}
/**
* Catches calls to undefined methods.
*
* Provides magic access to private functions of the class and native public mysqlidb functions
*
* @param string $method
* @param mixed $arg
*
* @return mixed
*/
public function __call ($method, $arg) {
if (method_exists ($this, $method))
return call_user_func_array (array ($this, $method), $arg);
call_user_func_array (array ($this->db, $method), $arg);
return $this;
}
/**
* Catches calls to undefined static methods.
*
* Transparently creating dbObject class to provide smooth API like name::get() name::orderBy()->get()
*
* @param string $method
* @param mixed $arg
*
* @return mixed
*/
public static function __callStatic ($method, $arg) {
$obj = new static;
$result = call_user_func_array (array ($obj, $method), $arg);
if (method_exists ($obj, $method))
return $result;
return $obj;
}
/**
* Converts object data to an associative array.
*
* @return array Converted data
*/
public function toArray () {
$data = $this->data;
$this->processWith ($data);
foreach ($data as &$d) {
if ($d instanceof dbObject)
$d = $d->data;
}
return $data;
}
/**
* Converts object data to a JSON string.
*
* @return string Converted data
*/
public function toJson () {
return json_encode ($this->toArray());
}
/**
* Converts object data to a JSON string.
*
* @return string Converted data
*/
public function __toString () {
return $this->toJson ();
}
/**
* @param array $data
*/
private function processWith (&$data) {
if (count ($this->_with) == 0)
return;
foreach ($this->_with as $w)
$data[$w] = $this->$w;
$this->_with = Array();
}
/**
* @param array $data
*/
private function processArrays (&$data) {
if (isset ($this->jsonFields) && is_array ($this->jsonFields)) {
foreach ($this->jsonFields as $key)
$data[$key] = json_decode ($data[$key]);
}
if (isset ($this->arrayFields) && is_array($this->arrayFields)) {
foreach ($this->arrayFields as $key)
$data[$key] = explode ("|", $data[$key]);
}
}
/**
* @param array $data
*/
private function validate ($data) {
foreach ($this->dbFields as $key => $desc) {
$type = null;
$required = false;
if (isset ($data[$key]))
$value = $data[$key];
else
$value = null;
if (is_array ($value))
continue;
if (isset ($desc[0]))
$type = $desc[0];
if (isset ($desc[1]) && ($desc[1] == 'required'))
$required = true;
if ($required && strlen ($value) == 0) {
$this->errors[] = Array ($this->dbTable . "." . $key => "is required");
continue;
}
if ($value == null)
continue;
switch ($type) {
case "text";
$regexp = null;
break;
case "int":
$regexp = "/^[0-9]*$/";
break;
case "bool":
$regexp = '/^[yes|no|0|1|true|false]$/i';
break;
case "datetime":
$regexp = "/^[0-9a-zA-Z -:]*$/";
break;
default:
$regexp = $type;
break;
}
if (!$regexp)
continue;
if (!preg_match ($regexp, $value)) {
$this->errors[] = Array ($this->dbTable . "." . $key => "$type validation failed");
continue;
}
}
return !count ($this->errors) > 0;
}
private function prepareData () {
$this->errors = Array ();
$sqlData = Array();
if (count ($this->data) == 0)
return Array();
if (method_exists ($this, "preLoad"))
$this->preLoad ($data);
foreach ($this->data as $key => &$value) {
if ($value instanceof dbObject && $value->isNew == true) {
$id = $value->save();
if ($id)
$value = $id;
else
$this->errors = array_merge ($this->errors, $value->errors);
}
if (!in_array ($key, array_keys ($this->dbFields)))
continue;
if (!is_array($value)) {
$sqlData[$key] = $value;
continue;
}
if (isset ($this->jsonFields) && in_array ($key, $this->jsonFields))
$sqlData[$key] = json_encode($value);
else if (isset ($this->arrayFields) && in_array ($key, $this->arrayFields))
$sqlData[$key] = implode ("|", $value);
else
$sqlData[$key] = $value;
}
return $sqlData;
}
private static function dbObjectAutoload ($classname) {
$filename = "models/". $classname .".php";
include ($filename);
}
/*
* Enable models autoload from a specified path
*
* Calling autoload() without path will set path to dbObjectPath/models/ directory
*
* @param string $path
*/
public static function autoload ($path = null) {
if ($path)
static::$modelPath = $path . "/";
else
static::$modelPath = __DIR__ . "/models/";
spl_autoload_register ("dbObject::dbObjectAutoload");
}
}
?>
<?
error_reporting (E_ALL|E_STRICT);
require_once ("../MysqliDb.php");
require_once ("../dbObject.php");
$db = new Mysqlidb('localhost', 'root', '', 'testdb');
dbObject::autoload ("models");
$tables = Array (
'users' => Array (
'login' => 'char(10) not null',
'active' => 'bool default 0',
'customerId' => 'int(10) not null',
'firstName' => 'char(10) not null',
'lastName' => 'char(10)',
'password' => 'text not null',
'createdAt' => 'datetime',
'updatedAt' => 'datetime',
'expires' => 'datetime',
'loginCount' => 'int(10) default 0'
),
'products' => Array (
'customerId' => 'int(10) not null',
'userId' => 'int(10) not null',
'productName' => 'char(50)'
)
);
$data = Array (
'user' => Array (
Array ('login' => 'user1',
'customerId' => 10,
'firstName' => 'John',
'lastName' => 'Doe',
'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")),
'expires' => $db->now('+1Y'),
'loginCount' => $db->inc()
),
Array ('login' => 'user2',
'customerId' => 10,
'firstName' => 'Mike',
'lastName' => NULL,
'password' => $db->func('SHA1(?)',Array ("secretpassword2+salt")),
'expires' => $db->now('+1Y'),
'loginCount' => $db->inc(2)
),
Array ('login' => 'user3',
'active' => true,
'customerId' => 11,
'firstName' => 'Pete',
'lastName' => 'D',
'password' => $db->func('SHA1(?)',Array ("secretpassword2+salt")),
'expires' => $db->now('+1Y'),
'loginCount' => $db->inc(3)
)
),
'product' => Array (
Array ('customerId' => 1,
'userId' => 1,
'productName' => 'product1',
),
Array ('customerId' => 1,
'userId' => 1,
'productName' => 'product2',
),
Array ('customerId' => 1,
'userId' => 1,
'productName' => 'product3',
),
Array ('customerId' => 1,
'userId' => 2,
'productName' => 'product4',
),
Array ('customerId' => 1,
'userId' => 2,
'productName' => 'product5',
),
)
);
function createTable ($name, $data) {
global $db;
//$q = "CREATE TABLE $name (id INT(9) UNSIGNED PRIMARY KEY NOT NULL";
$q = "CREATE TABLE $name (id INT(9) UNSIGNED PRIMARY KEY AUTO_INCREMENT";
foreach ($data as $k => $v) {
$q .= ", $k $v";
}
$q .= ")";
$db->rawQuery($q);
}
// rawQuery test
foreach ($tables as $name => $fields) {
$db->rawQuery("DROP TABLE " . $name);
createTable ($name, $fields);
}
foreach ($data as $name => $datas) {
foreach ($data[$name] as $userData) {
$obj = new $name ($userData);
$id = $obj->save();
if ($obj->errors) {
echo "errors:";
print_r ($obj->errors);
exit;
}
}
}
$products = product::ArrayBuilder()->get(2);
foreach ($products as $p) {
if (!is_array ($p)) {
echo "ArrayBuilder do not return an array\n";
exit;
}
}
$product = product::ArrayBuilder()->with('userId')->byId(5);
if (!is_array ($product['userId'])) {
echo "Error in with processing in getOne";
exit;
}
$products = product::ArrayBuilder()->with('userId')->get(2);
if (!is_array ($products[0]['userId'])) {
echo "Error in with processing in get";
exit;
}
$depts = product::join('user')->orderBy('products.id', 'desc')->get(5);
foreach ($depts as $d) {
if (!is_object($d)) {
echo "Return should be an object\n";
exit;
}
}
$dept = product::join('user')->byId(5);
if (count ($dept->data) != 13) {
echo "wrong props count " .count ($dept->data). "\n";
exit;
}
if ($db->count != 1) {
echo "wrong count after byId\n";
exit;
}
// hasOne
$products = product::get ();
$cnt = 0;
foreach ($products as $p) {
if (get_class ($d) != 'product') {
echo "wrong class returned\n";
exit;
}
if (!($p->userId instanceof user)) {
echo "wrong return class of hasOne result\n";
exit;
}
$cnt++;
}
if (($cnt != $db->count) && ($cnt != 5)) {
echo "wrong count after get\n";
exit;
}
// hasMany
$user = user::where('id',1)->getOne();
if (!is_array ($user->products) || (count ($user->products) != 3)) {
echo "wrong count in hasMany\n";
exit;
}
foreach ($user->products as $p) {
if (!($p instanceof product)) {
echo "wrong return class of hasMany result\n";
exit;
}
}
// multi save
$client = new user;
$client->login = 'testuser';
$client->firstName = 'john';
$client->lastName = 'Doe Jr';
$obj = new product;
$obj->customerId = 2;
$obj->userId = 2;
$obj->productName = "product6";
$obj->save();
$obj->userId = 5;
$obj->save();
$obj->userId = $client;
$obj->save();
if ($client->errors) {
echo "errors:";
print_r ($client->errors);
exit;
}
$expected = '{"customerId":2,"userId":{"id":4,"login":"testuser","active":0,"customerId":0,"firstName":"john","lastName":"Doe Jr","password":"","createdAt":"' .$client->createdAt. '","updatedAt":null,"expires":null,"loginCount":0},"productName":"product6","id":6}';
if ($obj->with('userId')->toJson() != $expected) {
echo "Multisave problem\n";
echo $obj->with('userId')->toJson();
exit;
}
$u= new user;
$u->active='test';
$u->customerId = 'test';
$u->expires = 'test;';
$u->firstName = 'test';
$obj = new product;
$obj->userId = $u;
$obj->save();
if ($obj->save()) {
echo "validation 1 failed\n";
exit;
}
if (count ($obj->errors) != 7) {
print_r ($obj->errors);
echo "validation 2 failed\n";
exit;
}
if (!user::byId(1) instanceof user)
echo "wrong return type1";
if (!is_array (user::ArrayBuilder()->byId(1)))
echo "wrong return type2";
if (!is_array (product::join('user')->orderBy('products.id', 'desc')->get(2)))
echo "wrong return type2";
if (!is_array (product::orderBy('products.id', 'desc')->join('user')->get(2)))
echo "wrong return type2";
$u = new user;
if (!$u->byId(1) instanceof user)
echo "wrong return type2";
$p = new product;
if (!is_array ($p->join('user')->orderBy('products.id', 'desc')->get(2)))
echo "wrong return type2";
if (!is_array ($p->orderBy('products.id', 'desc')->join('user')->get(2)))
echo "wrong return type2";
echo "All done";
?>
<?php
/**
* To make IDEs autocomplete happy
*
* @property int id
* @property int userid
* @property int customerId
* @property string productName
*/
class product extends dbObject {
protected $dbTable = "products";
protected $primaryKey = "id";
protected $dbFields = Array (
'userId' => Array('int', 'required'),
'customerId' => Array ('int', 'required'),
'productName' => Array ('text','required')
);
protected $relations = Array (
'userId' => Array ("hasOne", "user")
);
public function last () {
$this->where ("id" , 130, '>');
return $this;
}
}
?>
<?php
/**
* To make IDEs autocomplete happy
*
* @property int id
* @property string login
* @property bool active
* @property string customerId
* @property string firstName
* @property string lastName
* @property string password
* @property string createdAt
* @property string updatedAt
* @property string expires
* @property int loginCount
*/
class user extends dbObject {
protected $dbTable = "users";
protected $primaryKey = "id";
protected $dbFields = Array (
'login' => Array ('text', 'required'),
'active' => Array ('bool'),
'customerId' => Array ('int'),
'firstName' => Array ('/[a-zA-Z0-9 ]+/'),
'lastName' => Array ('text'),
'password' => Array ('text'),
'createdAt' => Array ('datetime'),
'updatedAt' => Array ('datetime'),
'expires' => Array ('datetime'),
'loginCount' => Array ('int')
);
protected $timestamps = Array ('createdAt', 'updatedAt');
protected $relations = Array (
'products' => Array ("hasMany", "product", 'userid')
);
}
?>
<?php <?php
require_once ("MysqliDb.php"); require_once ("../MysqliDb.php");
error_reporting(E_ALL); error_reporting(E_ALL);
$db = new Mysqlidb('localhost', 'root', '', 'testdb'); $db = new Mysqlidb('localhost', 'root', '', 'testdb');
...@@ -358,9 +358,9 @@ if ($db->count != 0) { ...@@ -358,9 +358,9 @@ if ($db->count != 0) {
} }
$db->delete("products"); $db->delete("products");
echo "All done";
//print_r($db->rawQuery("CALL simpleproc(?)",Array("test"))); //print_r($db->rawQuery("CALL simpleproc(?)",Array("test")));
print_r ($db->trace); print_r ($db->trace);
echo "All done";
?> ?>
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