1
0
mirror of synced 2024-12-05 03:06:05 +03:00
This commit is contained in:
doctrine 2006-04-13 20:37:28 +00:00
parent dac05178ca
commit 571cb46726
92 changed files with 11638 additions and 0 deletions

76
classes/Access.class.php Normal file
View File

@ -0,0 +1,76 @@
<?php
/**
* class Doctrine_Access
* Doctrine_Record and Doctrine_Collection classes extend this base class
* the purpose of DAOStrategy is to provice array access and property overload interface for these classes
*/
abstract class Doctrine_Access implements ArrayAccess {
/**
* setArray
* @param array $array an array of key => value pairs
*/
public function setArray(array $array) {
foreach($array as $k=>$v):
$this->set($k,$v);
endforeach;
}
/**
* __set -- an alias of set()
* @see set, offsetSet
* @param $name
* @param $value
*/
public function __set($name,$value) {
$this->set($name,$value);
}
/**
* __get -- an alias of get()
* @see get, offsetGet
* @param mixed $name
* @return mixed
*/
public function __get($name) {
return $this->get($name);
}
/**
* @return boolean -- whether or not the data has a field $offset
*/
public function offsetExists($offset) {
return (bool) isset($this->data[$offset]);
}
/**
* offsetGet -- an alias of get()
* @see get, __get
* @param mixed $offset
* @return mixed
*/
public function offsetGet($offset) {
return $this->get($offset);
}
/**
* sets $offset to $value
* @see set, __set
* @param mixed $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value) {
if( ! isset($offset)) {
$this->add($value);
} else
$this->set($offset,$value);
}
/**
* unset a given offset
* @see set, offsetSet, __set
* @param mixed $offset
*/
public function offsetUnset($offset) {
if($this instanceof Doctrine_Collection) {
return $this->remove($offset);
} else {
$this->set($offset,null);
}
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
require_once("Relation.class.php");
/**
* Doctrine_Association this class takes care of association mapping
* (= many-to-many relationships, where the relationship is handled through an additional relational table
* which holds 2 foreign keys)
*/
class Doctrine_Association extends Doctrine_Relation {
/**
* @var Doctrine_Table $associationTable
*/
private $associationTable;
/**
* the constructor
* @param Doctrine_Table $table foreign factory object
* @param Doctrine_Table $associationTable factory which handles the association
* @param string $local local field name
* @param string $foreign foreign field name
* @param integer $type type of relation
* @see Doctrine_Table constants
*/
public function __construct(Doctrine_Table $table, Doctrine_Table $associationTable, $local, $foreign, $type) {
parent::__construct($table, $local, $foreign, $type);
$this->associationTable = $associationTable;
}
/**
* @return Doctrine_Table
*/
public function getAssociationFactory() {
return $this->associationTable;
}
}
?>

View File

@ -0,0 +1,74 @@
<?php
/**
* Doctrine_BatchIterator
* iterates through Doctrine_Collection_Batch
*/
class Doctrine_BatchIterator implements Iterator {
/**
* @var Doctrine_Collection_Batch $collection
*/
private $collection;
/**
* @var array $keys
*/
private $keys;
/**
* @var mixed $key
*/
private $key;
/**
* @var integer $index
*/
private $index;
/**
* @var integer $count
*/
private $count;
/**
* constructor
* @var Doctrine_Collection_Batch $collection
*/
public function __construct(Doctrine_Collection_Batch $collection) {
$this->collection = $collection;
$this->keys = $this->collection->getKeys();
$this->count = $this->collection->count();
}
/**
* @return void
*/
public function rewind() {
$this->index = 0;
$i = $this->index;
if(isset($this->keys[$i]))
$this->key = $this->keys[$i];
}
/**
* @return boolean whether or not the iteration will continue
*/
public function valid() {
return $this->index < $this->count;
}
/**
* @return integer the current key
*/
public function key() {
return $this->key;
}
/**
* @return Doctrine_Record the current DAO
*/
public function current() {
return $this->collection->get($this->key);
}
/**
* @return void
*/
public function next() {
$this->index++;
$i = $this->index;
if(isset($this->keys[$i]))
$this->key = $this->keys[$i];
}
}
?>

57
classes/Cache.class.php Normal file
View File

@ -0,0 +1,57 @@
<?php
interface iDoctrine_Cache {
public function store(Doctrine_Record $record);
public function clean();
public function delete($id);
public function fetch($id);
public function exists($id);
}
class Doctrine_Cache implements iDoctrine_Cache {
/**
* implemented by child classes
* @param Doctrine_Record $record
* @return boolean
*/
public function store(Doctrine_Record $record) {
return false;
}
/**
* implemented by child classes
* @return boolean
*/
public function clean() {
return false;
}
/**
* implemented by child classes
* @return boolean
*/
public function delete($id) {
return false;
}
/**
* implemented by child classes
* @throws InvalidKeyException
* @return Doctrine_Record found Data Access Object
*/
public function fetch($id) {
throw new InvalidKeyException();
}
/**
* implemented by child classes
* @param integer $id
* @return boolean
*/
public function exists($id) {
return false;
}
/**
* implemented by child classes
* @return integer
*/
public function deleteAll() {
return 0;
}
}
?>

View File

@ -0,0 +1,261 @@
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Cache.class.php");
/**
* Doctrine_CacheFile
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Cache_File extends Doctrine_Cache implements Countable {
const STATS_FILE = "stats.cache";
/**
* @var string $path path for the cache files
*/
private $path;
/**
* @var array $fetched an array of fetched primary keys
*/
private $fetched = array();
/**
* @var Doctrine_Table $objTable
*/
private $objTable;
/**
* constructor
* @param Doctrine_Table $objTable
*/
public function __construct(Doctrine_Table $objTable) {
$this->objTable = $objTable;
$name = $this->getTable()->getTableName();
$manager = Doctrine_Manager::getInstance();
$dir = $manager->getAttribute(Doctrine::ATTR_CACHE_DIR);
if( ! is_dir($dir))
mkdir($dir, 0777);
if( ! is_dir($dir.DIRECTORY_SEPARATOR.$name))
mkdir($dir.DIRECTORY_SEPARATOR.$name, 0777);
$this->path = $dir.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR;
/**
* create stats file
*/
if( ! file_exists($this->path.self::STATS_FILE))
touch($this->path.self::STATS_FILE);
}
/**
* @return Doctrine_Table
*/
public function getTable() {
return $this->objTable;
}
/**
* @return integer number of cache files
*/
public function count() {
$c = -1;
foreach(glob($this->path."*.cache") as $file) {
$c++;
}
return $c;
}
/**
* getStats
* @return array an array of fetch statistics, keys as primary keys
* and values as fetch times
*/
public function getStats() {
$f = file_get_contents($this->path.self::STATS_FILE);
// every cache file starts with a ":"
$f = substr(trim($f),1);
$e = explode(":",$f);
return array_count_values($e);
}
/**
* store store a Doctrine_Record into file cache
* @param Doctrine_Record $record data access object to be stored
* @return boolean whether or not storing was successful
*/
public function store(Doctrine_Record $record) {
if($record->getState() != Doctrine_Record::STATE_CLEAN)
return false;
$file = $this->path.$record->getID().".cache";
if(file_exists($file))
return false;
$clone = clone $record;
$id = $clone->getID();
$fp = fopen($file,"w+");
fwrite($fp,serialize($clone));
fclose($fp);
$this->fetched[] = $id;
return true;
}
/**
* clean
* @return void
*/
public function clean() {
$stats = $this->getStats();
arsort($stats);
$size = $this->objTable->getAttribute(Doctrine::ATTR_CACHE_SIZE);
$count = count($stats);
$i = 1;
$preserve = array();
foreach($stats as $id => $count) {
if($i > $size)
break;
$preserve[$id] = true;
$i++;
}
foreach(glob($this->path."*.cache") as $file) {
$e = explode(".",basename($file));
$c = count($e);
$id = $e[($c - 2)];
if( ! isset($preserve[$id]))
@unlink($this->path.$id.".cache");
}
$fp = fopen($this->path.self::STATS_FILE,"w+");
fwrite($fp,"");
fclose($fp);
}
/**
* @param integer $id primary key of the DAO
* @return string filename and path
*/
public function getFileName($id) {
return $this->path.$id.".cache";
}
/**
* @return array an array of fetched primary keys
*/
public function getFetched() {
return $this->fetched;
}
/**
* fetch fetch a Doctrine_Record from the file cache
* @param integer $id
*/
public function fetch($id) {
$name = $this->getTable()->getComponentName();
$file = $this->path.$id.".cache";
if( ! file_exists($file))
throw new InvalidKeyException();
$data = file_get_contents($file);
$record = unserialize($data);
if( ! ($record instanceof Doctrine_Record)) {
// broken file, delete silently
$this->delete($id);
throw new InvalidKeyException();
}
$this->fetched[] = $id;
return $record;
}
/**
* exists check the existence of a cache file
* @param integer $id primary key of the cached DAO
* @return boolean whether or not a cache file exists
*/
public function exists($id) {
$name = $this->getTable()->getComponentName();
$file = $this->path.$id.".cache";
return file_exists($file);
}
/**
* deleteAll
* @return void
*/
public function deleteAll() {
foreach(glob($this->path."*.cache") as $file) {
@unlink($file);
}
$fp = fopen($this->path.self::STATS_FILE,"w+");
fwrite($fp,"");
fclose($fp);
}
/**
* delete delete a cache file
* @param integer $id primary key of the cached DAO
*/
public function delete($id) {
$file = $this->path.$id.".cache";
if( ! file_exists($file))
return false;
@unlink($file);
return true;
}
/**
* deleteMultiple delete multiple cache files
* @param array $ids an array containing cache file ids
* @return integer the number of files deleted
*/
public function deleteMultiple(array $ids) {
$deleted = 0;
foreach($ids as $id) {
if($this->delete($id)) $deleted++;
}
return $deleted;
}
/**
* destructor
* the purpose of this destructor is to save all the fetched
* primary keys into the cache stats
*/
public function __destruct() {
if( ! empty($this->fetched)) {
$fp = fopen($this->path.self::STATS_FILE,"a");
fwrite($fp,":".implode(":",$this->fetched));
fclose($fp);
}
/**
*
* cache auto-cleaning algorithm
* $ttl is the number of page loads between each cache cleaning
* the default is 100 page loads
*
* this means that the average number of page loads between
* each cache clean is 100 page loads (= 100 constructed Doctrine_Managers)
*
*/
$ttl = $this->objTable->getAttribute(Doctrine::ATTR_CACHE_TTL);
$l1 = (mt_rand(1,$ttl) / $ttl);
$l2 = (1 - 1/$ttl);
if($l1 > $l2)
$this->clean();
}
}
?>

View File

@ -0,0 +1,289 @@
<?php
/**
* class Doctrine_Collection a collection of data access objects
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Collection extends Doctrine_Access implements Countable, IteratorAggregate {
/**
* @var array $data an array containing the data access objects of this collection
*/
protected $data = array();
/**
* @var Doctrine_Table $table each collection has only records of specified table
*/
protected $table;
/**
* @var Doctrine_Record $reference collection can belong to a record
*/
protected $reference;
/**
* @var string $reference_field the reference field of the collection
*/
protected $reference_field;
/**
* @var Doctrine_Relation
*/
protected $relation;
/**
* @var boolean $expanded whether or not this collection has been expanded
*/
protected $expanded = false;
/**
* constructor
*/
public function __construct(Doctrine_Table $table) {
$this->table = $table;
}
/**
* @return object Doctrine_Table
*/
public function getTable() {
return $this->table;
}
/**
* @param array $data
*/
public function addData(array $data) {
$this->data[] = $data;
}
/**
* @return mixed
*/
public function getLast() {
return end($this->data);
}
/**
* @return void
*/
public function setReference(Doctrine_Record $record,Doctrine_Relation $relation) {
$this->reference = $record;
$this->relation = $relation;
if($relation instanceof Doctrine_ForeignKey ||
$relation instanceof Doctrine_LocalKey) {
$this->reference_field = $relation->getForeign();
$value = $record->get($relation->getLocal());
foreach($this as $record) {
if($value !== null) {
$record->set($this->reference_field, $value);
} else {
$record->set($this->reference_field, $this->reference);
}
}
}
}
/**
* @return mixed
*/
public function getReference() {
return $this->reference;
}
/**
* @return boolean
*/
public function expand($i = null) {
if( ! isset($this->reference))
return false;
$id = $this->reference->getID();
if(empty($id))
return false;
foreach($this->data as $v) {
switch(gettype($v)):
case "array":
$ids[] = $v['id'];
break;
case "object":
$id = $v->getID();
if( ! empty($id))
$ids[] = $id;
break;
endswitch;
}
if($this instanceof Doctrine_Collection_Immediate) {
$fields = implode(", ",$this->table->getColumnNames());
} else {
$fields = implode(", ",$this->table->getPrimaryKeys());
}
if($this->relation instanceof Doctrine_ForeignKey) {
$str = "";
$params = array($this->reference->getID());
if( ! empty($ids)) {
$str = " && id NOT IN (".substr(str_repeat("?, ",count($ids)),0,-2).")";
$params = array_merge($params,$ids);
}
$str = " WHERE ".$this->reference_field." = ?".$str;
$query = "SELECT ".$fields." FROM ".$this->table->getTableName().$str;
$coll = $this->table->execute($query,$params);
} elseif($this->relation instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
$query = "SELECT ".$foreign." FROM ".$asf->getTableName()." WHERE ".$local."=".$this->getID();
$table = $fk->getTable();
$graph = new Doctrine_DQL_Parser($table->getSession());
$q = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".id IN ($query)";
}
foreach($coll as $record) {
if(isset($this->reference_field))
$record->rawSet($this->reference_field, $this->reference);
$this->reference->addReference($record);
}
return true;
}
/**
* @return boolean
*/
public function remove($key) {
if( ! isset($this->data[$key]))
throw new InvalidKeyException();
$removed = $this->data[$key];
unset($this->data[$key]);
return $removed;
}
/**
* @param mixed $key
* @return boolean
*/
public function contains($key) {
return isset($this->data[$key]);
}
/**
* @param mixed $key
* @return object Doctrine_Record return a specified dao
*/
public function get($key) {
if( ! isset($this->data[$key])) {
$this->expand();
if( ! isset($this->data[$key]))
$this->data[$key] = $this->table->create();
if(isset($this->reference_field)) {
$value = $this->reference->get($this->relation->getLocal());
if($value !== null) {
$this->data[$key]->set($this->reference_field, $value);
} else {
$this->data[$key]->set($this->reference_field, $this->reference);
}
}
}
return $this->data[$key];
}
/**
* @return array an array containing all primary keys
*/
public function getPrimaryKeys() {
$list = array();
foreach($this->data[$key] as $record):
$list[] = $record->getID();
endforeach;
return $list;
}
/**
* returns all keys
* @return array
*/
public function getKeys() {
return array_keys($this->data);
}
/**
* count
* this class implements interface countable
* @return integer number of data access objects in this collection
*/
public function count() {
return count($this->data);
}
/**
* set
* @param integer $key
* @param Doctrine_Record $record
* @return void
*/
public function set($key,Doctrine_Record $record) {
if(isset($this->reference_field))
$record->set($this->reference_field,$this->reference);
$this->data[$key] = $record;
}
/**
* add
* adds a dao instance to this collection
* @param Doctrine_Record $record data access object to be added
* @param string $key optional key for the DAO
* @return boolean
*/
public function add(Doctrine_Record $record,$key = null) {
if(isset($this->reference_field))
$record->rawSet($this->reference_field,$this->reference);
if(isset($key)) {
if(isset($this->data[$key]))
return false;
$this->data[$key] = $record;
}
$this->data[] = $record;
return true;
}
/**
* save
* saves all data access objects
*/
public function save() {
$this->table->getSession()->saveCollection($this);
}
/**
* single shot delete
* deletes all dao instances from this collection
* uses only one database query to perform this operation
* @return boolean
*/
public function delete() {
$ids = $this->table->getSession()->deleteCollection($this);
$this->data = array();
}
/**
* getIterator
* @return object ArrayIterator
*/
public function getIterator() {
$data = $this->data;
return new ArrayIterator($data);
}
/**
* returns a string representation of this object
*/
public function __toString() {
return Doctrine_Lib::getCollectionAsString($this);
}
}
?>

View File

@ -0,0 +1,182 @@
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Collection.class.php");
/**
* Doctrine_Collection_Batch a collection of data access objects,
* with batch load strategy
*
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Collection_Batch extends Doctrine_Collection {
/**
* @var integer $batchSize batch size
*/
private $batchSize;
/**
* @var array $loaded an array containing the loaded batches, keys representing the batch indexes
*/
private $loaded = array();
public function __construct(Doctrine_DQL_Parser $graph,$key) {
parent::__construct($graph->getTable($key));
$this->data = $graph->getData($key);
if( ! is_array($this->data))
$this->data = array();
$this->batchSize = $this->getTable()->getAttribute(Doctrine::ATTR_BATCH_SIZE);
}
/**
* @param integer $batchSize batch size
*/
public function setBatchSize($batchSize) {
$batchSize = (int) $batchSize;
if($batchSize <= 0)
return false;
$this->batchSize = $batchSize;
return true;
}
/**
* @return integer
*/
public function getBatchSize() {
return $this->batchSize;
}
/**
* load load a specified element, by loading the batch the element is part of
* @param Doctrine_Record $record data access object
* @return boolean whether or not the load operation was successful
*/
public function load(Doctrine_Record $record) {
if(empty($this->data))
return false;
$id = $record->getID();
foreach($this->data as $key => $v) {
if(is_object($v)) {
if($v->getID() == $id)
break;
} elseif(is_array($v["id"])) {
if($v["id"] == $id)
break;
}
}
$x = floor($key / $this->batchSize);
if( ! isset($this->loaded[$x])) {
$e = $x * $this->batchSize;
$e2 = ($x + 1)* $this->batchSize;
$a = array();
$proxies = array();
for($i = $e; $i < $e2 && $i < $this->count(); $i++):
if(is_object($this->data[$i]))
$id = $this->data[$i]->getID();
elseif(is_array($this->data[$i]))
$id = $this->data[$i]["id"];
$load = false;
// check the cache
// no need of fetching the same data twice
try {
$record = $this->table->getCache()->fetch($id);
} catch(InvalidKeyException $ex) {
$load = true;
}
if($load)
$a[] = $id;
endfor;
$c = count($a);
$query = $this->table->getQuery()." WHERE ";
$query .= ($c > 1)?"id IN (":"id = ";
$query .= substr(str_repeat("?, ",count($a)),0,-2);
$query .= ($c > 1)?")":"";
$stmt = $this->table->getSession()->execute($query,$a);
while($row = $stmt->fetch(PDO::FETCH_ASSOC)):
$this->table->setData($row);
if(is_object($this->data[$e])) {
$this->data[$e]->factoryRefresh($this->table);
} else {
$this->data[$e] = $this->table->getRecord();
}
$e++;
endwhile;
$this->loaded[$x] = true;
return true;
} else {
return false;
}
}
/**
* get
* @param mixed $key the key of the data access object
* @return object Doctrine_Record data access object
*/
public function get($key) {
if(isset($this->data[$key])) {
switch(gettype($this->data[$key])):
case "array":
try {
// try to fetch the Doctrine_Record from cache
if( ! isset($this->data[$key]["id"]))
throw new InvalidKeyException();
$record = $this->table->getCache()->fetch($this->data[$key]["id"]);
} catch(InvalidKeyException $e) {
// Doctrine_Record didn't exist in cache
$this->table->setData($this->data[$key]);
$proxy = $this->table->getProxy();
$record = $proxy;
}
$record->addCollection($this);
break;
case "object":
$record = $this->data[$key];
break;
endswitch;
} else {
$this->expand();
if(isset($this->data[$key])) {
$record = $this->data[$key];
} else {
$record = $this->table->create();
}
}
if(isset($this->reference_field))
$record->set($this->reference_field,$this->reference);
$this->data[$key] = $record;
return $this->data[$key];
}
/**
* @return Doctrine_BatchIterator
*/
public function getIterator() {
return new Doctrine_BatchIterator($this);
}
}
?>

View File

@ -0,0 +1,28 @@
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Collection.class.php");
/**
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Collection_Immediate extends Doctrine_Collection {
/**
* @param Doctrine_DQL_Parser $graph
* @param integer $key
*/
public function __construct(Doctrine_DQL_Parser $graph,$key) {
parent::__construct($graph->getTable($key));
$name = $this->table->getComponentName();
$data = $graph->getData($name);
if(is_array($data)) {
foreach($data as $k=>$v):
$this->table->setData($v);
$this->add($this->table->getRecord());
endforeach;
}
}
}
?>

View File

@ -0,0 +1,18 @@
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Collection.class.php");
/**
* a collection of Doctrine_Record objects with lazy load strategy
* (batch load strategy with batch size 1)
*/
class Doctrine_Collection_Lazy extends Doctrine_Collection_Batch {
/**
* constructor
* @param Doctrine_DQL_Parser $graph
* @param string $key
*/
public function __construct(Doctrine_DQL_Parser $graph,$key) {
parent::setBatchSize(1);
parent::__construct($graph,$key);
}
}
?>

View File

@ -0,0 +1,150 @@
<?php
/**
* Doctrine_Configurable
* the base for Doctrine_Table, Doctrine_Manager and Doctrine_Session
*
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 beta2
*
*/
abstract class Doctrine_Configurable {
/**
* @var array $attributes an array of containing all attributes
*/
private $attributes = array();
/**
* @var $parent the parents of this component
*/
private $parent;
/**
* @throws Exception if the value is invalid
* @param integer $attribute
* @param mixed $value
* @return void
*/
final public function setAttribute($attribute,$value) {
switch($attribute):
case Doctrine::ATTR_BATCH_SIZE:
if($value < 0)
throw new Doctrine_Exception("Batch size should be greater than or equal to zero");
break;
case Doctrine::ATTR_CACHE_DIR:
if(substr(trim($value),0,6) == "%ROOT%") {
$dir = dirname(__FILE__);
$value = $dir.substr($value,6);
}
if(! is_dir($value) && ! file_exists($value))
mkdir($value,0777);
break;
case Doctrine::ATTR_CACHE_TTL:
if($value < 1)
throw new Doctrine_Exception("Cache TimeToLive should be greater than or equal to 1");
break;
case Doctrine::ATTR_CACHE_SIZE:
if($value < 1)
throw new Doctrine_Exception("Cache size should be greater than or equal to 1");
break;
case Doctrine::ATTR_CACHE_SLAM:
if($value < 0 || $value > 1)
throw new Doctrine_Exception("Cache slam defense should be a floating point number between 0 and 1");
break;
case Doctrine::ATTR_FETCHMODE:
if($value < 0)
throw new Doctrine_Exception("Unknown fetchmode. Fetchmode should be an integer between 0 and 2. See Doctrine::FETCH_* constants.");
break;
case Doctrine::ATTR_LISTENER:
$this->setEventListener($value);
break;
case Doctrine::ATTR_PK_COLUMNS:
if( ! is_array($value))
throw new Doctrine_Exception("The value of Doctrine::ATTR_PK_COLUMNS attribute must be an array");
break;
case Doctrine::ATTR_PK_TYPE:
if($value != Doctrine::INCREMENT_KEY && $value != Doctrine::UNIQUE_KEY)
throw new Doctrine_Exception("The value of Doctrine::ATTR_PK_TYPE attribute must be either Doctrine::INCREMENT_KEY or Doctrine::UNIQUE_KEY");
break;
case Doctrine::ATTR_LOCKMODE:
if($this instanceof Doctrine_Session) {
if($this->getState() != Doctrine_Session::STATE_OPEN)
throw new Doctrine_Exception("Couldn't set lockmode. There are transactions open.");
} elseif($this instanceof Doctrine_Manager) {
foreach($this as $session) {
if($session->getState() != Doctrine_Session::STATE_OPEN)
throw new Doctrine_Exception("Couldn't set lockmode. There are transactions open.");
}
} else {
throw new Doctrine_Exception("Lockmode attribute can only be set at the global or session level.");
}
break;
case Doctrine::ATTR_CREATE_TABLES:
$value = (bool) $value;
break;
case Doctrine::ATTR_VLD:
break;
case Doctrine::ATTR_CACHE:
if($value != Doctrine::CACHE_FILE && $value != Doctrine::CACHE_NONE)
throw new Doctrine_Exception("Unknown cache container. See Doctrine::CACHE_* constants for availible containers.");
break;
default:
throw new Exception("Unknown attribute.");
endswitch;
$this->attributes[$attribute] = $value;
}
/**
* @param Doctrine_EventListener $listener
* @return void
*/
final public function setEventListener(Doctrine_EventListener $listener) {
$i = Doctrine::ATTR_LISTENER;
$this->attributes[$i] = $listener;
}
/**
* @return mixed the value of the attribute
*/
final public function getAttribute($attribute) {
$attribute = (int) $attribute;
if($attribute < 1 || $attribute > 14)
throw new InvalidKeyException();
if( ! isset($this->attributes[$attribute])) {
if(isset($this->parent))
return $this->parent->getAttribute($attribute);
return null;
}
return $this->attributes[$attribute];
}
/**
* getAttributes
* @return array
*/
final public function getAttributes() {
return $this->attributes;
}
/**
* @param Doctrine_Configurable $component
* @return void
*/
final public function setParent(Doctrine_Configurable $component) {
$this->parent = $component;
}
/**
* getParent
*/
final public function getParent() {
return $this->parent;
}
}
?>

View File

@ -0,0 +1,64 @@
<?php
abstract class Doctrine_Component {
/**
* setTableName
* @param string $name table name
* @return void
*/
final public function setTableName($name) {
$this->getComponent()->setTableName($name);
}
/**
* setInheritanceMap
* @param array $inheritanceMap
* @return void
*/
final public function setInheritanceMap(array $inheritanceMap) {
$this->getComponent()->setInheritanceMap($inheritanceMap);
}
/**
* setAttribute
* @param integer $attribute
* @param mixed $value
* @see Doctrine::ATTR_* constants
* @return void
*/
final public function setAttribute($attribute,$value) {
$this->getComponent()->setAttribute($attribute,$value);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function ownsOne($componentName,$foreignKey) {
$this->getComponent()->bind($componentName,$foreignKey,Doctrine_Table::ONE_COMPOSITE);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function ownsMany($componentName,$foreignKey) {
$this->getComponent()->bind($componentName,$foreignKey,Doctrine_Table::MANY_COMPOSITE);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function hasOne($componentName,$foreignKey) {
$this->getComponent()->bind($componentName,$foreignKey,Doctrine_Table::ONE_AGGREGATE);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function hasMany($componentName,$foreignKey) {
$this->getComponent()->bind($componentName,$foreignKey,Doctrine_Table::MANY_AGGREGATE);
}
abstract public function getComponent();
}
?>

121
classes/DB.class.php Normal file
View File

@ -0,0 +1,121 @@
<?php
class Doctrine_DB extends PDO implements Countable, IteratorAggregate {
/**
* default DSN
*/
const DSN = "mysql://zYne:dc34@localhost/test";
/**
* executed queries
*/
private $queries = array();
/**
* execution times of the executed queries
*/
private $exectimes = array();
/**
* constructor
* @param string $dsn
* @param string $username
* @param string $password
*/
public function __construct($dsn,$username,$password) {
parent::__construct($dsn,$username,$password);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array("Doctrine_DBStatement",array($this)));
}
/**
* @param string $dsn PEAR::DB like DSN
* format: schema://user:password@address/dbname
*/
public static function getConnection($dsn = null) {
static $instance;
if( ! isset($instance)) {
if( ! isset($dsn)) {
$a = parse_url(self::DSN);
} else {
$a = parse_url($dsn);
}
$e = array();
$e[0] = $a["scheme"].":host=".$a["host"].";dbname=".substr($a["path"],1);
$e[1] = $a["user"];
$e[2] = $a["pass"];
$instance = new Doctrine_DB($e[0],$e[1],$e[2]);
}
return $instance;
}
/**
* @param string $query query to be executed
*/
public function query($query) {
$this->queries[] = $query;
$time = microtime();
$stmt = parent::query($query);
$this->exectimes[] = (microtime() - $time);
return $stmt;
}
/**
* @param string $query query to be prepared
*/
public function prepare($query) {
$this->queries[] = $query;
return parent::prepare($query);
}
/**
* @param string $time exectime of the last executed query
* @return void
*/
public function addExecTime($time) {
$this->exectimes[] = $time;
}
public function getExecTimes() {
return $this->exectimes;
}
/**
* @return array an array of executed queries
*/
public function getQueries() {
return $this->queries;
}
/**
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->queries);
}
/**
* returns the number of executed queries
* @return integer
*/
public function count() {
return count($this->queries);
}
}
class Doctrine_DBStatement extends PDOStatement {
/**
* @param Doctrine_DB $dbh Doctrine Database Handler
*/
private $dbh;
/**
* @param Doctrine_DB $dbh
*/
private function __construct(Doctrine_DB $dbh) {
$this->dbh = $dbh;
}
/**
* @param array $params
*/
public function execute($params) {
$time = microtime();
$result = parent::execute($params);
$exectime = (microtime() - $time);
$this->dbh->addExecTime($exectime);
return $result;
}
}
?>

View File

@ -0,0 +1,779 @@
<?php
/**
* Doctrine_DQL_Parser
* this is the base class for generating complex data graphs
* (multiple collections, multiple factories, multiple data access objects)
* with only one query
*
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_DQL_Parser {
/**
* @var array $fetchmodes an array containing all fetchmodes
*/
private $fetchModes = array();
/**
* @var array $fields an array containing all the selected fields
*/
private $fields = array();
/**
* @var array $tablenames an array containing all the tables used in the query
*/
private $tablenames = array();
/**
* @var array $from query FROM parts
*/
private $from = array();
/**
* @var array $join query JOIN parts
*/
private $join = array();
/**
* @var string $where
*/
private $where = array();
/**
* @var array $orderby query ORDER BY parts
*/
private $orderby = array();
/**
* @var integer $limit query limit
*/
private $limit;
/**
* @var integer $offset query offset
*/
private $offset;
private $joined = array();
/**
* @var array $data fetched data
*/
private $data = array();
/**
* @var Doctrine_Session $session Doctrine_Session object
*/
private $session;
private $inheritanceApplied = false;
private $aggregate = false;
private $paths = array();
private $connectors = array();
/**
* @param Doctrine_Session $session
*/
public function __construct(Doctrine_Session $session) {
$this->session = $session;
}
/**
* clear
* resets all the variables
*/
private function clear() {
$this->fetchModes = array();
$this->fields = array();
$this->tnames = array();
$this->from = array();
$this->join = array();
$this->where = array();
$this->orderby = array();
$this->inheritanceApplied = false;
$this->aggregate = false;
$this->data = array();
$this->connectors = array();
}
/**
* loadFields -- this method loads fields for a given factory and
* constructs a little bit of sql for every field
*
* fields of the factories become: [tablename].[fieldname] as [tablename]__[fieldname]
*
* @access private
* @param object Doctrine_Table $table a Doctrine_Table object
* @param integer $fetchmode fetchmode the table is using eg. Doctrine::FETCH_LAZY
* @return void
*/
private function loadFields(Doctrine_Table $table,$fetchmode) {
switch($fetchmode):
case Doctrine::FETCH_IMMEDIATE:
$names = $table->getColumnNames();
break;
case Doctrine::FETCH_LAZY:
case Doctrine::FETCH_BATCH:
$names = $table->getPrimaryKeys();
break;
default:
throw new InvalidFetchModeException();
endswitch;
$cname = $table->getComponentName();
$this->fetchModes[$cname] = $fetchmode;
$tablename = $table->getTableName();
$count = count($this->tnames);
foreach($names as $name) {
if($count == 0) {
$this->fields[] = $tablename.".".$name;
} else {
$this->fields[] = $tablename.".".$name." AS ".$cname."__".$name;
}
}
}
/**
* @return string the built sql query
*/
final public function getQuery() {
if(empty($this->fields) || empty($this->from))
return false;
// build the basic query
$q = "SELECT ".implode(", ",$this->fields).
" FROM ";
foreach($this->from as $tname => $bool) {
$str = $tname;
if(isset($this->join[$tname]))
$str .= " ".$this->join[$tname];
$a[] = $str;
}
$q .= implode(", ",$a);
$this->applyInheritance();
if( ! empty($this->where))
$q .= " WHERE ".implode(" && ",$this->where);
if( ! empty($this->orderby))
$q .= " ORDER BY ".implode(", ",$this->orderby);
return $q;
}
/**
* sql delete for mysql
*/
final public function buildDelete() {
if(empty($this->fields) || empty($this->from))
return false;
$a = array_merge(array_keys($this->from),$this->joined);
$q = "DELETE ".implode(", ",$a)." FROM ";
$a = array();
foreach($this->from as $tname => $bool) {
$str = $tname;
if(isset($this->join[$tname]))
$str .= " ".$this->join[$tname];
$a[] = $str;
}
$q .= implode(", ",$a);
$this->applyInheritance();
if( ! empty($this->where))
$q .= " WHERE ".implode(" && ",$this->where);
if( ! empty($this->orderby))
$q .= " ORDER BY ".implode(", ",$this->orderby);
if( ! empty($this->limit) && ! empty($this->offset))
$q = $this->session->modifyLimitQuery($q,$this->limit,$this->offset);
return $q;
}
/**
* applyInheritance
* applies column aggregation inheritance to DQL query
* @return boolean
*/
final public function applyInheritance() {
if($this->inheritanceApplied)
return false;
// get the inheritance maps
$array = array();
foreach($this->tnames as $objTable):
$tname = $objTable->getTableName();
$array[$tname][] = $objTable->getInheritanceMap();
endforeach;
// apply inheritance maps
$str = "";
$c = array();
foreach($array as $tname => $maps) {
$a = array();
foreach($maps as $map) {
$b = array();
foreach($map as $field=>$value) {
$b[] = $tname.".$field = $value";
}
if( ! empty($b)) $a[] = implode(" && ",$b);
}
if( ! empty($a)) $c[] = implode(" || ",$a);
}
$str .= implode(" || ",$c);
$this->addWhere($str);
$this->inheritanceApplied = true;
return true;
}
/**
* @param string $where
* @return boolean
*/
final public function addWhere($where) {
if(empty($where))
return false;
$this->where[] = "(".$where.")";
return true;
}
/**
* @param string $from from part of the query
*/
final public function addFrom($from) {
$this->from[] = $from;
}
/**
* getData
* @param $key the factory name
* @return array the data row for the specified factory
*/
final public function getData($key) {
if(isset($this->data[$key]))
return $this->data[$key];
return array();
}
/**
* execute
* executes the datagraph and populates Doctrine_Collections
* @param string $params
* @return Doctrine_Collection the root collection
*/
private function execute($params = array()) {
switch(count($this->tnames)):
case 0:
throw new DQLException();
break;
case 1:
$query = $this->getQuery();
$keys = array_keys($this->tnames);
$name = $this->tnames[$keys[0]]->getComponentName();
$stmt = $this->session->execute($query,$params);
while($data = $stmt->fetch(PDO::FETCH_ASSOC)):
foreach($data as $key => $value):
$e = explode("__",$key);
if(count($e) > 1) {
$data[$e[1]] = $value;
} else {
$data[$e[0]] = $value;
}
unset($data[$key]);
endforeach;
$this->data[$name][] = $data;
endwhile;
return $this->getCollection($keys[0]);
break;
default:
$query = $this->getQuery();
$keys = array_keys($this->tnames);
$root = $keys[0];
$stmt = $this->session->execute($query,$params);
$previd = array();
$coll = $this->getCollection($root);
$array = $this->parseData($stmt);
foreach($array as $data):
/**
* remove duplicated data rows and map data into objects
*/
foreach($data as $key => $row):
if(empty($row) || empty($row['id']))
continue;
$key = ucwords($key);
$name = $this->tnames[$key]->getComponentName();
if( ! isset($previd[$name]))
$previd[$name] = array();
if($previd[$name] !== $row) {
$this->tnames[$name]->setData($row);
$record = $this->tnames[$name]->getRecord();
if($name == $root) {
$this->tnames[$name]->setData($row);
$record = $this->tnames[$name]->getRecord();
$coll->add($record);
} else {
$last = $coll->getLast();
if( ! $last->hasReference($name)) {
$last->initReference($this->getCollection($name),$this->connectors[$name]);
}
$last->addReference($record);
}
}
$previd[$name] = $row;
endforeach;
endforeach;
return $coll;
endswitch;
}
/**
* parseData
* @return array
*/
public function parseData(PDOStatement $stmt) {
$array = array();
while($data = $stmt->fetch(PDO::FETCH_ASSOC)):
/**
* parse the data into two-dimensional array
*/
foreach($data as $key => $value):
$e = explode("__",$key);
if(count($e) > 1) {
$data[$e[0]][$e[1]] = $value;
} else {
$data[0][$e[0]] = $value;
}
unset($data[$key]);
endforeach;
$array[] = $data;
endwhile;
$stmt->closeCursor();
return $array;
}
/**
* @return Doctrine_Table
*/
public function getTable($name) {
return $this->tnames[$name];
}
/**
* getCollection
* @param integer $index
*/
private function getCollection($name) {
switch($this->fetchModes[$name]):
case 0:
$coll = new Doctrine_Collection_Immediate($this,$name);
break;
case 1:
$coll = new Doctrine_Collection_Batch($this,$name);
break;
case 2:
$coll = new Doctrine_Collection_Lazy($this,$name);
break;
default:
throw new Exception("Unknown fetchmode");
endswitch;
return $coll;
}
/**
* query the database with DQL (Doctrine Query Language)
*
* @param string $query DQL query
* @param array $params parameters
*/
public function query($query,$params = array()) {
$this->parseQuery($query);
if($this->aggregate) {
$keys = array_keys($this->tnames);
$query = $this->getQuery();
$stmt = $this->tnames[$keys[0]]->getSession()->select($query);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if(count($data) == 1) {
return current($data);
} else {
return $data;
}
} else {
return $this->execute($params);
}
}
/**
* DQL PARSER
*/
final public function parseQuery($query) {
$this->clear();
$e = self::bracketExplode($query," ","(",")");
$parts = array();
foreach($e as $k=>$part):
switch(strtolower($part)):
case "select":
case "from":
case "where":
case "limit":
case "offset":
$p = $part;
$parts[$part] = array();
break;
case "order":
$p = $part;
$i = $k+1;
if(isset($e[$i]) && strtolower($e[$i]) == "by") {
$parts[$part] = array();
}
break;
case "by":
continue;
default:
$parts[$p][] = $part;
endswitch;
endforeach;
foreach($parts as $k => $part) {
$part = implode(" ",$part);
switch($k):
case "SELECT":
$this->parseSelect($part);
break;
case "FROM":
$this->parseFrom($part);
break;
case "WHERE":
$this->addWhere($this->parseWhere($part));
break;
case "ORDER":
$this->parseOrderBy($part);
break;
case "LIMIT":
$this->limit = trim($part);
break;
case "OFFSET":
$this->offset = trim($part);
break;
endswitch;
}
}
/**
* DQL SELECT PARSER
* parses the select part of the query string
* @param string $str
* @return void
*/
private function parseSelect($str) {
$this->aggregate = true;
foreach(explode(",",trim($str)) as $reference) {
$e = explode(" AS ",trim($reference));
$f = explode("(",$e[0]);
$a = explode(".",$f[1]);
$field = substr(array_pop($a),0,-1);
$reference = trim(implode(".",$a));
$objTable = $this->load($reference);
if(isset($e[1]))
$s = " AS $e[1]";
$this->fields[]= $f[0]."(".$objTable->getTableName().".$field)$s";
}
}
/**
* DQL FROM PARSER
* parses the from part of the query string
* @param string $str
* @return void
*/
private function parseFrom($str) {
foreach(explode(",",trim($str)) as $reference) {
$reference = trim($reference);
$e = explode("-",$reference);
$reference = $e[0];
$table = $this->load($reference);
if(isset($e[1])) {
switch(strtolower($e[1])):
case "i":
case "immediate":
$fetchmode = Doctrine::FETCH_IMMEDIATE;
break;
case "b":
case "batch":
$fetchmode = Doctrine::FETCH_BATCH;
break;
case "l":
case "lazy":
$fetchmode = Doctrine::FETCH_LAZY;
break;
default:
throw new DQLException("Unknown fetchmode '$e[1]'. The availible fetchmodes are 'i', 'b' and 'l'.");
endswitch;
} else
$fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE);
if( ! $this->aggregate) {
$this->loadFields($table,$fetchmode);
}
}
}
/**
* DQL ORDER BY PARSER
* parses the order by part of the query string
*
* @param string $str
* @return void
*/
private function parseOrderBy($str) {
foreach(explode(",",trim($str)) as $r) {
$r = trim($r);
$e = explode(" ",$r);
$a = explode(".",$e[0]);
if(count($a) > 1) {
$field = array_pop($a);
$reference = implode(".",$a);
$name = end($a);
$this->load($reference);
$tname = $this->tnames[$name]->getTableName();
$r = $tname.".".$field;
if(isset($e[1])) $r .= " ".$e[1];
$this->orderby[] = $r;
} else {
$this->orderby[] = $r;
}
}
}
/**
* DQL WHERE PARSER
* parses the where part of the query string
*
*
* @param string $str
* @return string
*/
private function parseWhere($str) {
$tmp = trim($str);
$str = self::bracketTrim($tmp,"(",")");
$brackets = false;
while($tmp != $str) {
$brackets = true;
$tmp = $str;
$str = self::bracketTrim($str,"(",")");
}
$parts = self::bracketExplode($str," && ","(",")");
if(count($parts) > 1) {
$ret = array();
foreach($parts as $part) {
$ret[] = $this->parseWhere($part);
}
$r = implode(" && ",$ret);
} else {
$parts = self::bracketExplode($str," || ","(",")");
if(count($parts) > 1) {
$ret = array();
foreach($parts as $part) {
$ret[] = $this->parseWhere($part);
}
$r = implode(" || ",$ret);
} else {
return $this->loadWhere($parts[0]);
}
}
if($brackets)
return "(".$r.")";
else
return $r;
}
/**
* trims brackets
*
* @param string $str
* @param string $e1 the first bracket, usually '('
* @param string $e2 the second bracket, usually ')'
*/
public static function bracketTrim($str,$e1,$e2) {
if(substr($str,0,1) == $e1 && substr($str,-1) == $e2)
return substr($str,1,-1);
else
return $str;
}
/**
* bracketExplode
* usage:
* $str = (age < 20 && age > 18) && email LIKE 'John@example.com'
* now exploding $str with parameters $d = ' && ', $e1 = '(' and $e2 = ')'
* would return an array:
* array("(age < 20 && age > 18)", "email LIKE 'John@example.com'")
*
* @param string $str
* @param string $d the delimeter which explodes the string
* @param string $e1 the first bracket, usually '('
* @param string $e2 the second bracket, usually ')'
*
*/
public static function bracketExplode($str,$d,$e1,$e2) {
$str = explode("$d",$str);
$i = 0;
$term = array();
foreach($str as $key=>$val) {
if (empty($term[$i])) {
$term[$i] = trim($val);
$s1 = substr_count($term[$i],"$e1");
$s2 = substr_count($term[$i],"$e2");
if($s1 == $s2) $i++;
} else {
$term[$i] .= "$d".trim($val);
$c1 = substr_count($term[$i],"$e1");
$c2 = substr_count($term[$i],"$e2");
if($c1 == $c2) $i++;
}
}
return $term;
}
/**
* loadWhere
*
*/
private function loadWhere($where) {
$e = explode(" ",$where);
$r = array_shift($e);
$a = explode(".",$r);
if(count($a) > 1) {
$field = array_pop($a);
$operator = array_shift($e);
$value = implode(" ",$e);
$reference = implode(".",$a);
$objTable = $this->session->getTable(end($a));
$where = $objTable->getTableName().".".$field." ".$operator." ".$value;
if(count($a) > 1 && isset($a[1])) {
$root = $a[0];
$fk = $this->tnames[$root]->getForeignKey($a[1]);
if($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
switch($fk->getType()):
case Doctrine_Table::ONE_AGGREGATE:
case Doctrine_Table::ONE_COMPOSITE:
break;
case Doctrine_Table::MANY_AGGREGATE:
case Doctrine_Table::MANY_COMPOSITE:
$b = array_shift($a);
$b = array_shift($a);
$graph = new Doctrine_DQL_Parser($this->session);
$graph->parseQuery("FROM $b WHERE $where");
$where = $this->tnames[$root]->getTableName().".id IN (SELECT ".$fk->getLocal()." FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." IN (".$graph->getQuery()."))";
break;
endswitch;
} else
$this->load($reference);
} else
$this->load($reference);
}
return $where;
}
/**
* @param string $path the path of the loadable component
* @param integer $fetchmode optional fetchmode, if not set the components default fetchmode will be used
* @throws DQLException
*/
final public function load($path, $fetchmode = Doctrine::FETCH_LAZY) {
$e = explode(".",$path);
foreach($e as $key => $name) {
$low = strtolower($name);
$name = ucwords($low);
try {
if($key == 0) {
$objTable = $this->session->getTable($name);
if(count($e) == 1) {
$tname = $objTable->getTableName();
$this->from[$tname] = true;
}
} else {
$fk = $objTable->getForeignKey($name);
$tname = $objTable->getTableName();
$next = $fk->getTable();
$tname2 = $next->getTableName();
$this->connectors[$name] = $fk;
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($fk->getType()):
case Doctrine_Table::ONE_AGGREGATE:
case Doctrine_Table::ONE_COMPOSITE:
$this->where[] = "(".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign().")";
$this->from[$tname] = true;
$this->from[$tname2] = true;
break;
case Doctrine_Table::MANY_AGGREGATE:
case Doctrine_Table::MANY_COMPOSITE:
$this->join[$tname] = "LEFT JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
$this->joined[] = $tname2;
$this->from[$tname] = true;
break;
endswitch;
} elseif($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
switch($fk->getType()):
case Doctrine_Table::ONE_AGGREGATE:
case Doctrine_Table::ONE_COMPOSITE:
break;
case Doctrine_Table::MANY_AGGREGATE:
case Doctrine_Table::MANY_COMPOSITE:
//$this->addWhere("SELECT ".$fk->getLocal()." FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." IN (SELECT ".$fk->getTable()->getComponentName().")");
$this->from[$tname] = true;
break;
endswitch;
}
$objTable = $next;
}
if( ! isset($this->tnames[$name])) {
$this->tnames[$name] = $objTable;
}
} catch(Doctrine_Exception $e) {
throw new DQLException();
} catch(InvalidKeyException $e) {
throw new DQLException();
}
}
return $objTable;
}
}
?>

View File

@ -0,0 +1,96 @@
<?php
class Doctrine_DataDict {
private $table;
public function __construct(Doctrine_Table $table) {
$this->table = $table;
$manager = $this->table->getSession()->getManager();
require_once($manager->getRoot()."/adodb-hack/adodb.inc.php");
$dbh = $this->table->getSession()->getDBH();
$this->dict = NewDataDictionary($dbh);
}
public function metaColumns() {
return $this->dict->metaColumns($this->table->getTableName());
}
public function createTable() {
foreach($this->table->getColumns() as $name => $args) {
$r[] = $name." ".$this->getADOType($args[0],$args[1])." ".$args[2];
}
$dbh = $this->table->getSession()->getDBH();
$r = implode(", ",$r);
$a = $this->dict->createTableSQL($this->table->getTableName(),$r);
$return = true;
foreach($a as $sql) {
try {
$dbh->query($sql);
} catch(PDOException $e) {
$return = false;
}
}
return $return;
}
/**
* converts doctrine type to adodb type
*
* @param string $type column type
* @param integer $length column length
*/
public function getADOType($type,$length) {
switch($type):
case "string":
case "s":
if($length < 255)
return "C($length)";
elseif($length < 4000)
return "X";
break;
case "mbstring":
if($length < 255)
return "C2($length)";
return "X2";
case "clob":
return "XL";
break;
case "float":
case "f":
case "double":
return "F";
break;
case "timestamp":
case "t":
return "T";
break;
case "boolean":
case "bool":
return "L";
break;
case "integer":
case "int":
case "i":
if(empty($length))
return "I8";
elseif($length < 4)
return "I1";
elseif($length < 6)
return "I2";
elseif($length < 10)
return "I4";
elseif($length <= 20)
return "I8";
else
throw new Doctrine_Exception("Too long integer (max length is 20).");
break;
endswitch;
}
}
?>

151
classes/Debugger.class.php Normal file
View File

@ -0,0 +1,151 @@
<?php
require_once("EventListener.class.php");
class Doctrine_DebugMessage {
private $code;
private $object;
public function __construct($object, $code) {
$this->object = $object;
$this->code = $code;
}
final public function getCode() {
return $this->code;
}
final public function getObject() {
return $this->object;
}
}
class Doctrine_Debugger extends Doctrine_EventListener {
const EVENT_LOAD = 1;
const EVENT_PRELOAD = 2;
const EVENT_SLEEP = 3;
const EVENT_WAKEUP = 4;
const EVENT_UPDATE = 5;
const EVENT_PREUPDATE = 6;
const EVENT_CREATE = 7;
const EVENT_PRECREATE = 8;
const EVENT_SAVE = 9;
const EVENT_PRESAVE = 10;
const EVENT_INSERT = 11;
const EVENT_PREINSERT = 12;
const EVENT_DELETE = 13;
const EVENT_PREDELETE = 14;
const EVENT_EVICT = 15;
const EVENT_PREEVICT = 16;
const EVENT_CLOSE = 17;
const EVENT_PRECLOSE = 18;
const EVENT_OPEN = 19;
const EVENT_COMMIT = 20;
const EVENT_PRECOMMIT = 21;
const EVENT_ROLLBACK = 22;
const EVENT_PREROLLBACK = 23;
const EVENT_BEGIN = 24;
const EVENT_PREBEGIN = 25;
const EVENT_COLLDELETE = 26;
const EVENT_PRECOLLDELETE = 27;
private $debug;
public function getMessages() {
return $this->debug;
}
public function onLoad(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_LOAD);
}
public function onPreLoad(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PRELOAD);
}
public function onSleep(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_SLEEP);
}
public function onWakeUp(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_WAKEUP);
}
public function onUpdate(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_UPDATE);
}
public function onPreUpdate(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PREUPDATE);
}
public function onCreate(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_CREATE);
}
public function onPreCreate(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PRECREATE);
}
public function onSave(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_SAVE);
}
public function onPreSave(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PRESAVE);
}
public function onInsert(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_INSERT);
}
public function onPreInsert(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PREINSERT);
}
public function onDelete(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_DELETE);
}
public function onPreDelete(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PREDELETE);
}
public function onEvict(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_EVICT);
}
public function onPreEvict(Doctrine_Record $record) {
$this->debug[] = new Doctrine_DebugMessage($record,self::EVENT_PREEVICT);
}
public function onClose(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_CLOSE);
}
public function onPreClose(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_PRECLOSE);
}
public function onOpen(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_OPEN);
}
public function onTransactionCommit(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_COMMIT);
}
public function onPreTransactionCommit(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_PRECOMMIT);
}
public function onTransactionRollback(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_ROLLBACK);
}
public function onPreTransactionRollback(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_PREROLLBACK);
}
public function onTransactionBegin(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_BEGIN);
}
public function onPreTransactionBegin(Doctrine_Session $session) {
$this->debug[] = new Doctrine_DebugMessage($session,self::EVENT_PREBEGIN);
}
public function onCollectionDelete(Doctrine_Collection $collection) {
$this->debug[] = new Doctrine_DebugMessage($collection,self::EVENT_COLLDELETE);
}
public function onPreCollectionDelete(Doctrine_Collection $collection) {
$this->debug[] = new Doctrine_DebugMessage($collection,self::EVENT_PRECOLLDELETE);
}
}
?>

268
classes/Doctrine.class.php Normal file
View File

@ -0,0 +1,268 @@
<?php
require_once("Exception.class.php");
/**
* Doctrine
* the base class of Doctrine framework
*/
final class Doctrine {
/**
* ERROR MODE CONSTANTS
*/
/**
* NO PRIMARY KEY COLUMN ERROR
* no primary key column found error code
*/
const ERR_NO_PK = 0;
/**
* PRIMARY KEY MISMATCH ERROR
* this error code is used when user uses factory refresh for a
* given Doctrine_Record and the old primary key doesn't match the new one
*/
const ERR_REFRESH = 1;
/**
* FIND ERROR
* this code used when for example Doctrine_Table::find() is called and
* a Data Access Object is not found
*/
const ERR_FIND = 2;
/**
* TABLE NOT FOUND ERROR
* this error code is used when user tries to initialize
* a table and there is no database table for this factory
*/
const ERR_NOSUCH_TABLE = 3;
/**
* NAMING ERROR
* this code is used when user defined Doctrine_Table is badly named
*/
const ERR_NAMING = 5;
/**
* TABLE INSTANCE ERROR
* this code is used when user tries to initialize
* a table that is already initialized
*/
const ERR_TABLE_INSTANCE = 6;
/**
* NO OPEN SESSIONS ERROR
* error code which is used when user tries to get
* current session are there are no sessions open
*/
const ERR_NO_SESSIONS = 7;
/**
* MAPPING ERROR
* if there is something wrong with mapping logic
* this error code is used
*/
const ERR_MAPPING = 8;
/**
* ATTRIBUTE CONSTANTS
*/
/**
* event listener attribute
*/
const ATTR_LISTENER = 1;
/**
* fetchmode attribute
*/
const ATTR_FETCHMODE = 2;
/**
* cache directory attribute
*/
const ATTR_CACHE_DIR = 3;
/**
* cache time to live attribute
*/
const ATTR_CACHE_TTL = 4;
/**
* cache size attribute
*/
const ATTR_CACHE_SIZE = 5;
/**
* cache slam defense probability
*/
const ATTR_CACHE_SLAM = 6;
/**
* cache container attribute
*/
const ATTR_CACHE = 7;
/**
* batch size attribute
*/
const ATTR_BATCH_SIZE = 8;
/**
* primary key columns attribute
*/
const ATTR_PK_COLUMNS = 9;
/**
* primary key type attribute
*/
const ATTR_PK_TYPE = 10;
/**
* locking attribute
*/
const ATTR_LOCKMODE = 11;
/**
* validatate attribute
*/
const ATTR_VLD = 12;
/**
* name prefix attribute
*/
const ATTR_NAME_PREFIX = 13;
/**
* create tables attribute
*/
const ATTR_CREATE_TABLES = 14;
/**
* CACHE CONSTANTS
*/
/**
* file cache constant
*/
const CACHE_FILE = 0;
/**
* constant for disabling the caching
*/
const CACHE_NONE = 1;
/**
* FETCHMODE CONSTANTS
*/
/**
* IMMEDIATE FETCHING
* mode for immediate fetching
*/
const FETCH_IMMEDIATE = 0;
/**
* BATCH FETCHING
* mode for batch fetching
*/
const FETCH_BATCH = 1;
/**
* LAZY FETCHING
* mode for lazy fetching
*/
const FETCH_LAZY = 2;
/**
* LOCKMODE CONSTANTS
*/
/**
* mode for optimistic locking
*/
const LOCK_OPTIMISTIC = 0;
/**
* mode for pessimistic locking
*/
const LOCK_PESSIMISTIC = 1;
/**
* PRIMARY KEY TYPE CONSTANTS
*/
/**
* auto-incremented/(sequence updated) primary key
*/
const INCREMENT_KEY = 0;
/**
* unique key
*/
const UNIQUE_KEY = 1;
/**
* @var string $path doctrine root directory
*/
private static $path;
public static function getPath() {
if(! self::$path)
self::$path = dirname(__FILE__);
return self::$path;
}
/**
* loads all runtime classes
*/
public static function loadAll() {
if(! self::$path)
self::$path = dirname(__FILE__);
$dir = dir(self::$path);
$a = array();
while (false !== ($entry = $dir->read())) {
switch($entry):
case ".":
case "..":
break;
case "Cache":
case "Record":
case "Collection":
case "Table":
case "Validator":
case "Exception":
case "Session":
case "DQL":
$a[] = self::$path.DIRECTORY_SEPARATOR.$entry;
break;
default:
if(is_file(self::$path.DIRECTORY_SEPARATOR.$entry)) {
require_once($entry);
}
endswitch;
}
foreach($a as $dirname) {
$dir = dir($dirname);
$path = $dirname.DIRECTORY_SEPARATOR;
while (false !== ($entry = $dir->read())) {
if(is_file($path.$entry)) {
require_once($path.$entry);
}
}
}
}
/**
* simple autoload function
*/
public static function autoload($classname) {
if(! self::$path)
self::$path = dirname(__FILE__);
$e = explode("_",$classname);
if($e[0] != "Doctrine")
return false;
if(end($e) != "Exception") {
if(count($e) > 2) {
array_shift($e);
$dir = array_shift($e);
$class = self::$path.DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR.implode('',$e).".class.php";
} elseif(count($e) > 1) {
$class = self::$path.DIRECTORY_SEPARATOR.$e[1].".class.php";
} else
return false;
} else {
$class = self::$path.DIRECTORY_SEPARATOR."Exception".DIRECTORY_SEPARATOR.$e[1].".class.php";
}
if( ! file_exists($class)) {
return false;
}
require_once($class);
return true;
}
}
?>

View File

@ -0,0 +1,124 @@
<?php
/**
* interface for event listening, forces all classes that extend
* Doctrine_EventListener to have the same method arguments as their parent
*/
interface iDoctrine_EventListener {
public function onLoad(Doctrine_Record $record);
public function onPreLoad(Doctrine_Record $record);
public function onUpdate(Doctrine_Record $record);
public function onPreUpdate(Doctrine_Record $record);
public function onCreate(Doctrine_Record $record);
public function onPreCreate(Doctrine_Record $record);
public function onSave(Doctrine_Record $record);
public function onPreSave(Doctrine_Record $record);
public function onInsert(Doctrine_Record $record);
public function onPreInsert(Doctrine_Record $record);
public function onDelete(Doctrine_Record $record);
public function onPreDelete(Doctrine_Record $record);
public function onEvict(Doctrine_Record $record);
public function onPreEvict(Doctrine_Record $record);
public function onSaveCascade(Doctrine_Record $record);
public function onPreSaveCascade(Doctrine_Record $record);
public function onDeleteCascade(Doctrine_Record $record);
public function onPreDeleteCascade(Doctrine_Record $record);
public function onSleep(Doctrine_Record $record);
public function onWakeUp(Doctrine_Record $record);
public function onClose(Doctrine_Session $session);
public function onPreClose(Doctrine_Session $session);
public function onOpen(Doctrine_Session $session);
public function onTransactionCommit(Doctrine_Session $session);
public function onPreTransactionCommit(Doctrine_Session $session);
public function onTransactionRollback(Doctrine_Session $session);
public function onPreTransactionRollback(Doctrine_Session $session);
public function onTransactionBegin(Doctrine_Session $session);
public function onPreTransactionBegin(Doctrine_Session $session);
public function onCollectionDelete(Doctrine_Collection $collection);
public function onPreCollectionDelete(Doctrine_Collection $collection);
}
/**
* Doctrine_EventListener all event listeners extend this base class
* the empty methods allow child classes to only implement the methods they need to implement
*
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*
*/
abstract class Doctrine_EventListener implements iDoctrine_EventListener {
public function onLoad(Doctrine_Record $record) { }
public function onPreLoad(Doctrine_Record $record) { }
public function onSleep(Doctrine_Record $record) { }
public function onWakeUp(Doctrine_Record $record) { }
public function onUpdate(Doctrine_Record $record) { }
public function onPreUpdate(Doctrine_Record $record) { }
public function onCreate(Doctrine_Record $record) { }
public function onPreCreate(Doctrine_Record $record) { }
public function onSave(Doctrine_Record $record) { }
public function onPreSave(Doctrine_Record $record) { }
public function onInsert(Doctrine_Record $record) { }
public function onPreInsert(Doctrine_Record $record) { }
public function onDelete(Doctrine_Record $record) { }
public function onPreDelete(Doctrine_Record $record) { }
public function onEvict(Doctrine_Record $record) { }
public function onPreEvict(Doctrine_Record $record) { }
public function onSaveCascade(Doctrine_Record $record) { }
public function onPreSaveCascade(Doctrine_Record $record) { }
public function onDeleteCascade(Doctrine_Record $record) { }
public function onPreDeleteCascade(Doctrine_Record $record) { }
public function onClose(Doctrine_Session $session) { }
public function onPreClose(Doctrine_Session $session) { }
public function onOpen(Doctrine_Session $session) { }
public function onTransactionCommit(Doctrine_Session $session) { }
public function onPreTransactionCommit(Doctrine_Session $session) { }
public function onTransactionRollback(Doctrine_Session $session) { }
public function onPreTransactionRollback(Doctrine_Session $session) { }
public function onTransactionBegin(Doctrine_Session $session) { }
public function onPreTransactionBegin(Doctrine_Session $session) { }
public function onCollectionDelete(Doctrine_Collection $collection) { }
public function onPreCollectionDelete(Doctrine_Collection $collection) { }
}
/**
* an emtpy listener all components use this by default
*/
class EmptyEventListener extends Doctrine_EventListener { }
?>

View File

@ -0,0 +1,6 @@
<?php
class InvalidKeyException extends Exception { }
class InvalidTypeException extends Exception { }
class Doctrine_Exception extends Exception { }
class DQLException extends Doctrine_Exception { }
?>

View File

@ -0,0 +1,10 @@
<?php
/**
* thrown when user tries to find a Doctrine_Record for given primary key and that object is not found
*/
class Doctrine_Find_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("Couldn't find Data Access Object.",Doctrine::ERR_FIND);
}
}
?>

View File

@ -0,0 +1,10 @@
<?php
/**
* thrown when user tries to get a foreign key object but the mapping is not done right
*/
class Doctrine_Mapping_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("An error occured in the mapping logic.",Doctrine::ERR_MAPPING);
}
}
?>

View File

@ -0,0 +1,11 @@
<?php
/**
* thrown when user defined Doctrine_Table is badly named
*/
class Doctrine_Naming_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("Badly named Doctrine_Table. Each Doctrine_Table
must be in format [Name]Table.", Doctrine::ERR_NAMING);
}
}
?>

View File

@ -0,0 +1,10 @@
<?php
/**
* thrown when Doctrine_Record is loaded and there is no primary key field
*/
class Doctrine_PrimaryKey_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("No primary key column found. Each data set must have primary key column.", Doctrine::ERR_NO_PK);
}
}
?>

View File

@ -0,0 +1,11 @@
<?php
/**
* thrown when Doctrine_Record is refreshed and the refreshed primary key doens't match the old one
*/
class Doctrine_Refresh_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("The refreshed primary key doesn't match the
one in the record memory.", Doctrine::ERR_REFRESH);
}
}
?>

View File

@ -0,0 +1,12 @@
<?php
/**
* thrown when user tries to get the current
* session and there are no open sessions
*/
class Doctrine_Session_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("There are no opened sessions. Use
Doctrine_Manager::getInstance()->openSession() to open a new session.",Doctrine::ERR_NO_SESSIONS);
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
/**
* thrown when user tries to initialize a new instance of Doctrine_Table,
* while there already exists an instance of that table
*/
class Doctrine_Table_Exception extends Doctrine_Exception {
public function __construct() {
parent::__construct("Couldn't initialize table. One instance of this
tabke already exists. Always use Doctrine_Session::getTable(\$name)
to get on instance of a Doctrine_Table.",Doctrine::ERR_TABLE_INSTANCE);
}
}
?>

View File

@ -0,0 +1,11 @@
<?php
class Doctrine_Validator_Exception extends Doctrine_Exception {
private $validator;
public function __construct(Doctrine_Validator $validator) {
$this->validator = $validator;
}
public function getErrorStack() {
return $this->validator->getErrorStack();
}
}
?>

View File

@ -0,0 +1,6 @@
<?php
/**
* Foreign Key
*/
class Doctrine_ForeignKey extends Doctrine_Relation { }
?>

View File

@ -0,0 +1,22 @@
<?php
/**
* Doctrine_Form_Builder
*/
class Doctrine_Form_Builder {
public static function buildForm(Doctrine_Record $record) {
}
}
class Doctrine_Element {
private $attributes = array();
private $data;
public function toHtml() {
return "<".$this->name.">"."</>";
}
}
class InputElement {
private $attributes = array();
}
?>

140
classes/Lib.php Normal file
View File

@ -0,0 +1,140 @@
<?php
class Doctrine_Lib {
/**
* @param integer $state the state of record
* @see Doctrine_Record::STATE_* constants
* @return string string representation of given state
*/
public static function getRecordStateAsString($state) {
switch($state):
case Doctrine_Record::STATE_PROXY:
return "proxy";
break;
case Doctrine_Record::STATE_CLEAN:
return "persistent clean";
break;
case Doctrine_Record::STATE_DIRTY:
return "persistent dirty";
break;
case Doctrine_Record::STATE_TDIRTY:
return "transient dirty";
break;
case Doctrine_Record::STATE_TCLEAN:
return "transient clean";
break;
endswitch;
}
/**
* returns a string representation of Doctrine_Record object
* @param Doctrine_Record $record
* @return string
*/
public function getRecordAsString(Doctrine_Record $record) {
$r[] = "<pre>";
$r[] = "Component : ".$record->getTable()->getComponentName();
$r[] = "ID : ".$record->getID();
$r[] = "References : ".count($record->getReferences());
$r[] = "State : ".Doctrine_Lib::getRecordStateAsString($record->getState());
$r[] = "OID : ".$record->getOID();
$r[] = "</pre>";
return implode("\n",$r)."<br />";
}
/**
* getStateAsString
* returns a given session state as string
* @param integer $state session state
*/
public static function getSessionStateAsString($state) {
switch($state):
case Doctrine_Session::STATE_OPEN:
return "open";
break;
case Doctrine_Session::STATE_CLOSED:
return "closed";
break;
case Doctrine_Session::STATE_BUSY:
return "busy";
break;
case Doctrine_Session::STATE_ACTIVE:
return "active";
break;
endswitch;
}
/**
* returns a string representation of Doctrine_Session object
* @param Doctrine_Session $session
* @return string
*/
public function getSessionAsString(Doctrine_Session $session) {
$r[] = "<pre>";
$r[] = "Doctrine_Session object";
$r[] = "State : ".Doctrine_Session::getStateAsString($session->getState());
$r[] = "Open Transactions : ".$session->getTransactionLevel();
$r[] = "Open Factories : ".$session->count();
$sum = 0;
$rsum = 0;
$csum = 0;
foreach($session->getTables() as $objTable) {
if($objTable->getCache() instanceof Doctrine_Cache_File) {
$sum += array_sum($objTable->getCache()->getStats());
$rsum += $objTable->getRepository()->count();
$csum += $objTable->getCache()->count();
}
}
$r[] = "Cache Hits : ".$sum." hits ";
$r[] = "Cache : ".$csum." objects ";
$r[] = "Repositories : ".$rsum." objects ";
$queries = false;
if($session->getDBH() instanceof Doctrine_DB) {
$handler = "Doctrine Database Handler";
$queries = count($this->dbh->getQueries());
$sum = array_sum($this->dbh->getExecTimes());
} elseif($this->dbh instanceof PDO) {
$handler = "PHP Native PDO Driver";
} else
$handler = "Unknown Database Handler";
$r[] = "DB Handler : ".$handler;
if($queries) {
$r[] = "Executed Queries : ".$queries;
$r[] = "Sum of Exec Times : ".$sum;
}
$r[] = "</pre>";
return implode("\n",$r)."<br>";
}
/**
* returns a string representation of Doctrine_Table object
* @param Doctrine_Table $table
* @return string
*/
public function getTableAsString(Doctrine_Table $table) {
$r[] = "<pre>";
$r[] = "Component : ".$this->getComponentName();
$r[] = "Table : ".$this->getTableName();
$r[] = "Repository : ".$this->getRepository()->count()." objects";
if($this->cache instanceof Doctrine_Cache_File) {
$r[] = "Cache : ".$this->getCache()->count()." objects";
$r[] = "Cache hits : ".array_sum($this->getCache()->getStats())." hits";
}
$r[] = "</pre>";
return implode("\n",$r)."<br>";
}
/**
* returns a string representation of Doctrine_Collection object
* @param Doctrine_Collection $collection
* @return string
*/
public function getCollectionAsString(Doctrine_Collection $collection) {
$r[] = "<pre>";
$r[] = get_class($collection);
foreach($collection as $key => $record) {
$r[] = "Key : ".$key." ID : ".$record->getID();
}
$r[] = "</pre>";
return implode("\n",$r);
}
}
?>

View File

@ -0,0 +1,6 @@
<?php
/**
* Local Key
*/
class Doctrine_LocalKey extends Doctrine_Relation { }
?>

207
classes/Manager.class.php Normal file
View File

@ -0,0 +1,207 @@
<?php
require_once("Configurable.class.php");
require_once("EventListener.class.php");
/**
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Manager extends Doctrine_Configurable implements Countable, IteratorAggregate {
/**
* @var array $session an array containing all the opened sessions
*/
private $sessions = array();
/**
* @var integer $index
*/
private $index = 0;
/**
* @var integer $currIndex
*/
private $currIndex = 0;
/**
* @var string $root
*/
private $root;
/**
* constructor
*/
private function __construct() {
$this->root = dirname(__FILE__);
}
/**
* setDefaultAttributes
*/
final public function setDefaultAttributes() {
static $init = false;
if( ! $init) {
$init = true;
$attributes = array(
Doctrine::ATTR_CACHE_DIR => "%ROOT%".DIRECTORY_SEPARATOR."cachedir",
Doctrine::ATTR_FETCHMODE => Doctrine::FETCH_LAZY,
Doctrine::ATTR_CACHE_TTL => 100,
Doctrine::ATTR_CACHE_SIZE => 100,
Doctrine::ATTR_CACHE => Doctrine::CACHE_FILE,
Doctrine::ATTR_BATCH_SIZE => 5,
Doctrine::ATTR_LISTENER => new EmptyEventListener(),
Doctrine::ATTR_PK_COLUMNS => array("id"),
Doctrine::ATTR_PK_TYPE => Doctrine::INCREMENT_KEY,
Doctrine::ATTR_LOCKMODE => 1,
Doctrine::ATTR_VLD => false,
Doctrine::ATTR_CREATE_TABLES => true
);
foreach($attributes as $attribute => $value) {
$old = $this->getAttribute($attribute);
if($old === null)
$this->setAttribute($attribute,$value);
}
}
}
/**
* @return string the root directory of Doctrine
*/
final public function getRoot() {
return $this->root;
}
/**
* getInstance this class uses the singleton pattern
*/
final public static function getInstance() {
static $instance;
if( ! isset($instance))
$instance = new Doctrine_Manager();
return $instance;
}
/**
* openSession open a new session and save it to Doctrine_Manager->sessions
* @param PDO $pdo PDO database driver
* @param string $name name of the session, if empty numeric key is used
* @return Doctrine_Session the opened session object
*/
final public function openSession(PDO $pdo, $name = null) {
// initialize the default attributes
$this->setDefaultAttributes();
if($name !== null) {
$name = (string) $name;
if(isset($this->sessions[$name]))
throw new InvalidKeyException();
} else {
$name = $this->index;
$this->index++;
}
switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)):
case "mysql":
$this->sessions[$name] = new Doctrine_Session_Mysql($this,$pdo);
break;
case "sqlite":
$this->sessions[$name] = new Doctrine_Session_Sqlite($this,$pdo);
break;
case "pgsql":
$this->sessions[$name] = new Doctrine_Session_Pgsql($this,$pdo);
break;
case "oci":
$this->sessions[$name] = new Doctrine_Session_Oracle($this,$pdo);
break;
case "mssql":
$this->sessions[$name] = new Doctrine_Session_Mssql($this,$pdo);
break;
case "firebird":
$this->sessions[$name] = new Doctrine_Session_Firebird($this,$pdo);
break;
case "informix":
$this->sessions[$name] = new Doctrine_Session_Informix($this,$pdo);
break;
endswitch;
$this->currIndex = $name;
return $this->sessions[$name];
}
/**
* getSession
* @param integer $index
* @return object Doctrine_Session
* @throws InvalidKeyException
*/
final public function getSession($index) {
if( ! isset($this->sessions[$index]))
throw new InvalidKeyException();
$this->currIndex = $index;
return $this->sessions[$index];
}
/**
* closes the session
*
* @param Doctrine_Session $session
* @return void
*/
final public function closeSession(Doctrine_Session $session) {
$session->close();
unset($session);
}
/**
* getSessions
* @return array
*/
final public function getSessions() {
return $this->sessions;
}
/**
* setCurrentSession
* @param mixed $key the session key
* @throws InvalidKeyException
* @return void
*/
final public function setCurrentSession($key) {
$key = (string) $key;
if( ! isset($this->sessions[$key]))
throw new InvalidKeyException();
$this->currIndex = $key;
}
/**
* count
* @return integer the number of open sessions
*/
public function count() {
return count($this->sessions);
}
/**
* getIterator
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->sessions);
}
/**
* getCurrentSession
* @return object Doctrine_Session
*/
final public function getCurrentSession() {
$i = $this->currIndex;
if( ! isset($this->sessions[$i]))
throw new Doctrine_Session_Exception();
return $this->sessions[$i];
}
/**
* __toString
*/
public function __toString() {
$r[] = "<pre>";
$r[] = "Doctrine_Manager";
$r[] = "Sessions : ".count($this->sessions);
$r[] = "</pre>";
return implode("\n",$r);
}
}
?>

999
classes/Record.class.php Normal file
View File

@ -0,0 +1,999 @@
<?php
require_once("Access.class.php");
/**
* Doctrine_Record
*/
abstract class Doctrine_Record extends Doctrine_Access implements Countable, IteratorAggregate {
/**
* STATE CONSTANTS
*/
/**
* DIRTY STATE
* a Doctrine_Record is in dirty state when its properties are changed
*/
const STATE_DIRTY = 1;
/**
* TDIRTY STATE
* a Doctrine_Record is in transient dirty state when it is created and some of its fields are modified
* but it is NOT yet persisted into database
*/
const STATE_TDIRTY = 2;
/**
* CLEAN STATE
* a Doctrine_Record is in clean state when all of its properties are loaded from the database
* and none of its properties are changed
*/
const STATE_CLEAN = 3;
/**
* PROXY STATE
* a Doctrine_Record is in proxy state when its properties are not fully loaded
*/
const STATE_PROXY = 4;
/**
* NEW TCLEAN
* a Doctrine_Record is in transient clean state when it is created and none of its fields are modified
*/
const STATE_TCLEAN = 5;
/**
* DELETED STATE
* a Doctrine_Record turns into deleted state when it is deleted
*/
const STATE_DELETED = 6;
/**
* FETCHMODE CONSTANTS
*/
/**
* @var object Doctrine_Table $table the factory that created this data access object
*/
protected $table;
/**
* @var integer $id the primary key of this object
*/
protected $id;
/**
* @var array $data the dao data
*/
protected $data = array();
/**
* @var array $modified an array containing properties that have been modified
*/
private $modified = array();
/**
* @var integer $state the state of this data access object
* @see STATE_* constants
*/
private $state;
/**
* @var array $collections the collections this dao is in
*/
private $collections = array();
/**
* @var mixed $references an array containing all the references
*/
private $references = array();
/**
* @var mixed $originals an array containing all the original references
*/
private $originals = array();
/**
* @var integer $index this index is used for creating object identifiers
*/
private static $index = 1;
/**
* @var integer $oid object identifier
*/
private $oid;
/**
* @var boolean $loaded whether or not this object has its data loaded from database
*/
private $loaded = false;
/**
* constructor
* @param Doctrine_Table $table a Doctrine_Table object
* @throws Doctrine_Session_Exception if object is created using the new operator and there are no
* open sessions
*/
public function __construct($table = null) {
if(isset($table) && $table instanceof Doctrine_Table) {
$this->table = $table;
$exists = ( ! $this->table->isNewEntry());
} else {
$this->table = Doctrine_Manager::getInstance()->getCurrentSession()->getTable(get_class($this));
$exists = false;
}
// Check if the current session has the records table in its registry
// If not this is record is only used for creating table definition and setting up
// relations.
if($this->table->getSession()->hasTable($this->table->getComponentName())) {
$this->oid = self::$index;
self::$index++;
if( ! $exists) {
// listen the onPreCreate event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreCreate($this);
} else {
// listen the onPreLoad event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreLoad($this);
}
// get the data array
$this->data = $this->table->getData();
// clean data array
$cols = $this->cleanData();
if( ! $exists) {
if($cols > 0)
$this->state = Doctrine_Record::STATE_TDIRTY;
else
$this->state = Doctrine_Record::STATE_TCLEAN;
// listen the onCreate event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onCreate($this);
} else {
$this->state = Doctrine_Record::STATE_CLEAN;
if($cols <= 1)
$this->state = Doctrine_Record::STATE_PROXY;
else
$this->loaded = true;
// id property is protected
$keys = $this->table->getPrimaryKeys();
if(count($keys) == 1) {
$this->id = $this->data[$keys[0]];
} else {
/**
$this->id = array();
foreach($keys as $key) {
$this->id[] = $this->data[$key];
}
*/
}
// listen the onLoad event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onLoad($this);
}
// add data access object to registry
$this->table->getRepository()->add($this);
unset($this->data['id']);
$this->table->setData(array());
$this->table->getCache()->store($this);
}
}
/**
* setUp
* implemented by child classes
*/
public function setUp() { }
/**
* return the object identifier
* @return integer
*/
public function getOID() {
return $this->oid;
}
/**
* isLoaded
*/
public function isLoaded() {
return $this->loaded;
}
/**
* cleanData
* modifies data array
* example:
*
* $data = array("name"=>"John","lastname"=> null,"id"=>1,"unknown"=>"unknown");
* $names = array("name","lastname","id");
* $data after operation:
* $data = array("name"=>"John","lastname" => array(),"id"=>1);
*/
private function cleanData() {
$cols = 0;
$tmp = $this->data;
$this->data = array();
foreach($this->table->getColumnNames() as $name) {
if( ! isset($tmp[$name])) {
$this->data[$name] = array();
} else {
$cols++;
$this->data[$name] = $tmp[$name];
}
}
return $cols;
}
/**
* this method is automatically called when this Doctrine_Record is serialized
*/
public function __sleep() {
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onSleep($this);
$this->table = $this->table->getComponentName();
// unset all vars that won't need to be serialized
unset($this->modified);
unset($this->associations);
unset($this->state);
unset($this->collections);
unset($this->references);
unset($this->originals);
unset($this->oid);
unset($this->loaded);
foreach($this->data as $k=>$v) {
if($v instanceof Doctrine_Record)
$this->data[$k] = array();
}
return array_keys(get_object_vars($this));
}
/**
* __wakeup
* this method is automatically called everytime a Doctrine_Record object is unserialized
*/
public function __wakeup() {
$this->modified = array();
$this->state = Doctrine_Record::STATE_CLEAN;
$name = $this->table;
$manager = Doctrine_Manager::getInstance();
$sess = $manager->getCurrentSession();
$this->oid = self::$index;
self::$index++;
$this->table = $sess->getTable($name);
$this->table->getRepository()->add($this);
$this->loaded = true;
$this->cleanData();
unset($this->data['id']);
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onWakeUp($this);
}
/**
* addCollection
* @param Doctrine_Collection $collection
* @param mixed $key
*/
final public function addCollection(Doctrine_Collection $collection,$key = null) {
if($key !== null) {
if(isset($this->collections[$key]))
throw InvalidKeyException();
$this->collections[$key] = $collection;
} else {
$this->collections[] = $collection;
}
}
/**
* getCollection
* @param integer $key
* @return Doctrine_Collection
*/
final public function getCollection($key) {
return $this->collections[$key];
}
/**
* hasCollections
* @return boolean whether or not this dao is part of a collection
*/
final public function hasCollections() {
return (! empty($this->collections));
}
/**
* getState
* @see Doctrine_Record::STATE_* constants
* @return integer the current state
*/
final public function getState() {
return $this->state;
}
/**
* refresh refresh internal data from the database
* @return boolean
*/
final public function refresh() {
if($this->getID() == null) return false;
$query = $this->table->getQuery()." WHERE ".implode(" = ? && ",$this->table->getPrimaryKeys())." = ?";
$this->data = $this->table->getSession()->execute($query,array($this->getID()))->fetch(PDO::FETCH_ASSOC);
unset($this->data["id"]);
$this->modified = array();
$this->cleanData();
$this->state = Doctrine_Record::STATE_CLEAN;
$this->getTable()->getCache()->store($this);
return true;
}
/**
* factoryRefresh
* @throws Doctrine_Exception
* @return void
*/
final public function factoryRefresh() {
$data = $this->table->getData();
if($this->id != $data["id"])
throw new Doctrine_Refresh_Exception();
$this->data = $data;
$this->cleanData();
unset($this->data["id"]);
$this->state = Doctrine_Record::STATE_CLEAN;
$this->modified = array();
$this->getTable()->getCache()->store($this);
}
/**
* return the factory that created this data access object
* @return object Doctrine_Table a Doctrine_Table object
*/
final public function getTable() {
return $this->table;
}
/**
* return all the internal data
* @return array an array containing all the properties
*/
final public function getData() {
return $this->data;
}
/**
* get
* returns a value of a property or related component
*
* @param $name name of the property or related component
* @throws InvalidKeyException
* @return mixed
*/
public function get($name) {
if(isset($this->data[$name])) {
// check if the property is not loaded (= it is an empty array)
if(is_array($this->data[$name]) && ! $this->loaded) {
// no use trying to load the data from database if the Doctrine_Record is new or clean
if($this->state != Doctrine_Record::STATE_TDIRTY &&
$this->state != Doctrine_Record::STATE_TCLEAN &&
$this->state != Doctrine_Record::STATE_CLEAN) {
$this->loaded = true;
if( ! empty($this->collections)) {
foreach($this->collections as $collection) {
$collection->load($this);
}
} else {
$this->refresh();
}
$this->state = Doctrine_Record::STATE_CLEAN;
}
if(is_array($this->data[$name]))
return null;
return $this->data[$name];
}
return $this->data[$name];
}
if($name == "id")
return $this->id;
if( ! isset($this->references[$name]))
$this->loadReference($name);
return $this->references[$name];
}
/**
* rawSet
* doctrine uses this function internally, not recommended for developers
*
* @param mixed $name name of the property or reference
* @param mixed $value value of the property or reference
*/
final public function rawSet($name,$value) {
if($value instanceof Doctrine_Record)
$id = $value->getID();
if( ! empty($id))
$value = $id;
$this->data[$name] = $value;
}
/**
* set
* method for altering properties and Doctrine_Record references
*
* @param mixed $name name of the property or reference
* @param mixed $value value of the property or reference
* @throws InvalidKeyException
* @throws InvalidTypeException
* @return void
*/
public function set($name,$value) {
if(isset($this->data[$name])) {
$old = $this->get($name);
if($value instanceof Doctrine_Record) {
$id = $value->getID();
if( ! empty($id))
$value = $value->getID();
}
if($old !== $value) {
$this->data[$name] = $value;
$this->modified[] = $name;
switch($this->state):
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_PROXY:
$this->state = Doctrine_Record::STATE_DIRTY;
break;
case Doctrine_Record::STATE_TCLEAN:
$this->state = Doctrine_Record::STATE_TDIRTY;
break;
endswitch;
}
} else {
// if not found, throws InvalidKeyException
$fk = $this->table->getForeignKey($name);
if($value->getTable()->getComponentName() != $name)
throw new InvalidKeyException();
// one-to-many or one-to-one relation
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($fk->getType()):
case Doctrine_Table::MANY_COMPOSITE:
case Doctrine_Table::MANY_AGGREGATE:
// one-to-many relation found
if( ! ($value instanceof Doctrine_Collection))
throw new InvalidTypeException("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Collection when setting one-to-many references.");
$value->setReference($this,$fk);
break;
case Doctrine_Table::ONE_COMPOSITE:
case Doctrine_Table::ONE_AGGREGATE:
// one-to-one relation found
if( ! ($value instanceof Doctrine_Record))
throw new InvalidTypeException("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Record when setting one-to-one references.");
if($fk->getLocal() == "id") {
$this->references[$name]->set($fk->getForeign(),$this);
} else {
$this->set($fk->getLocal(),$value);
}
break;
endswitch;
} elseif($fk instanceof Doctrine_Association) {
// many-to-many relation found
if( ! ($value instanceof Doctrine_Collection))
throw new InvalidTypeException("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Collection when setting one-to-many references.");
}
$this->references[$name] = $value;
}
}
/**
* applies the changes made to this object into database
* this method is smart enough to know if any changes are made
* and whether to use INSERT or UPDATE statement
*
* this method also saves the related composites
*
* @return void
*/
final public function save() {
$this->table->getSession()->beginTransaction();
// listen the onPreSave event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($this);
$saveLater = $this->table->getSession()->saveRelated($this);
$this->table->getSession()->save($this);
foreach($saveLater as $fk) {
$table = $fk->getTable();
$foreign = $fk->getForeign();
$local = $fk->getLocal();
$name = $table->getComponentName();
if(isset($this->references[$name])) {
$obj = $this->references[$name];
$obj->save();
}
}
// save the MANY-TO-MANY associations
$this->saveAssociations();
$this->table->getSession()->commit();
}
/**
* returns an array of modified fields and associated values
* @return array
*/
final public function getModified() {
$a = array();
foreach($this->modified as $k=>$v) {
$a[$v] = $this->data[$v];
}
return $a;
}
/**
* this class implements countable interface
* @return integer the number of columns
*/
public function count() {
return count($this->data);
}
/**
* getIterator
* @return ArrayIterator an ArrayIterator that iterates through the data
*/
public function getIterator() {
return new ArrayIterator($this->data);
}
/**
* saveAssociations
* save the associations of many-to-many relations
* this method also deletes associations that do not exist anymore
* @return void
*/
final public function saveAssociations() {
foreach($this->table->getForeignKeys() as $fk):
$table = $fk->getTable();
$name = $table->getComponentName();
if($fk instanceof Doctrine_Association) {
switch($fk->getType()):
case Doctrine_Table::MANY_COMPOSITE:
break;
case Doctrine_Table::MANY_AGGREGATE:
$asf = $fk->getAssociationFactory();
if(isset($this->references[$name])) {
$new = $this->references[$name];
if( ! isset($this->originals[$name])) {
$this->loadReference($name);
}
$r = $this->getRelationOperations($name,$new);
foreach($r["delete"] as $record) {
$query = "DELETE FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." = ?"
." && ".$fk->getLocal()." = ?";
$this->table->getSession()->execute($query, array($record->getID(),$this->getID()));
}
foreach($r["add"] as $record) {
$reldao = $asf->create();
$reldao->set($fk->getForeign(),$record);
$reldao->set($fk->getLocal(),$this);
$reldao->save();
}
$this->originals[$name] = clone $this->references[$name];
}
break;
endswitch;
} elseif($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($fk->getType()):
case Doctrine_Table::ONE_COMPOSITE:
if(isset($this->originals[$name]) && $this->originals[$name]->getID() != $this->references[$name]->getID())
$this->originals[$name]->delete();
break;
case Doctrine_Table::MANY_COMPOSITE:
if(isset($this->references[$name])) {
$new = $this->references[$name];
if( ! isset($this->originals[$name]))
$this->loadReference($name);
$r = $this->getRelationOperations($name,$new);
foreach($r["delete"] as $record) {
$record->delete();
}
$this->originals[$name] = clone $this->references[$name];
}
break;
endswitch;
}
endforeach;
}
/**
* get the records that need to be added
* and/or deleted in order to change the old collection
* to the new one
*
* The algorithm here is very simple and definitely not
* the fastest one, since we have to iterate through the collections twice.
* the complexity of this algorithm is O(2*n^2)
*
* First we iterate through the new collection and get the
* records that do not exist in the old collection (Doctrine_Records that need to be added).
*
* Then we iterate through the old collection and get the records
* that do not exists in the new collection (Doctrine_Records that need to be deleted).
*/
final public function getRelationOperations($name, Doctrine_Collection $new) {
$r["add"] = array();
$r["delete"] = array();
foreach($new as $k=>$record) {
$found = false;
if($record->getID() !== null) {
foreach($this->originals[$name] as $k2 => $record2) {
if($record2->getID() == $record->getID()) {
$found = true;
break;
}
}
}
if( ! $found) {
$this->originals[$name][] = $record;
$r["add"][] = $record;
}
}
foreach($this->originals[$name] as $k => $record) {
if($record->getID() === null)
continue;
$found = false;
foreach($new as $k2=>$record2) {
if($record2->getID() == $record->getID()) {
$found = true;
break;
}
}
if( ! $found) {
$r["delete"][] = $record;
unset($this->originals[$name][$k]);
}
}
return $r;
}
/**
* getOriginals
*/
final public function getOriginals($name) {
if( ! isset($this->originals[$name]))
throw new InvalidKeyException();
return $this->originals[$name];
}
/**
* deletes this data access object and all the related composites
* this operation is isolated by a transaction
*
* this event can be listened by the onPreDelete and onDelete listeners
*
* @return boolean true on success, false on failure
*/
final public function delete() {
$this->table->getSession()->delete($this);
}
/**
* returns a copy of this object
* @return DAO
*/
final public function copy() {
return $this->table->create($this->data);
}
/**
* @param integer $id
* @return void
*/
final public function setID($id = null) {
if($id === null) {
$this->id = null;
$this->cleanData();
$this->state = Doctrine_Record::STATE_TCLEAN;
$this->modified = array();
} else {
$this->id = $id;
$this->state = Doctrine_Record::STATE_CLEAN;
$this->modified = array();
}
}
/**
* return the primary key this object is pointing at
* @return int id
*/
final public function getID() {
return $this->id;
}
/**
* hasRefence
* @param string $name
*/
public function hasReference($name) {
return isset($this->references[$name]);
}
/**
* @param Doctrine_Collection $coll
* @param string $connectorField
*/
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
$name = $coll->getTable()->getComponentName();
$coll->setReference($this, $connector);
$this->references[$name] = $coll;
$this->originals[$name] = clone $coll;
}
/**
* addReference
*/
public function addReference(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->references[$name]->add($record);
$this->originals[$name]->add($record);
}
/**
* getReferences
* @return array all references
*/
public function getReferences() {
return $this->references;
}
/**
* @throws InvalidKeyException
* @param name
* @return void
*/
final public function loadReference($name) {
$fk = $this->table->getForeignKey($name);
$table = $fk->getTable();
$name = $table->getComponentName();
switch($this->getState()):
case Doctrine_Record::STATE_TDIRTY:
case Doctrine_Record::STATE_TCLEAN:
if($fk->getType() == Doctrine_Table::ONE_COMPOSITE || $fk->getType() == Doctrine_Table::ONE_AGGREGATE) {
// ONE-TO-ONE
$this->references[$name] = $table->create();
if($fk instanceof Doctrine_ForeignKey) {
$this->references[$name]->set($fk->getForeign(),$this);
} else {
$this->set($fk->getLocal(),$this->references[$name]);
}
} else {
$this->references[$name] = new Doctrine_Collection($table);
if($fk instanceof Doctrine_ForeignKey) {
// ONE-TO-MANY
$this->references[$name]->setReference($this,$fk);
}
$this->originals[$name] = new Doctrine_Collection($table);
}
break;
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_PROXY:
$local = $fk->getLocal();
$coll = false;
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
$graph = $table->getDQLParser();
// get the local identifier
$id = $this->get($local);
if(empty($id)) {
$this->references[$name] = $table->create();
if($this->table->hasPrimaryKey($fk->getLocal())) {
$this->references[$name]->set($fk->getForeign(),$this);
} else {
$this->set($fk->getLocal(),$this->references[$name]);
}
} else {
if($this->table->hasPrimaryKey($fk->getForeign())) {
try {
$coll = new Doctrine_Collection($table);
$coll[0] = $table->getCache()->fetch($id);
} catch(InvalidKeyException $e) {
$coll = false;
}
}
if( ! $coll) {
$query = "FROM ".$name." WHERE ".$name.".".$fk->getForeign()." = ?";
$coll = $graph->query($query,array($id));
}
if($fk->getType() == Doctrine_Table::ONE_COMPOSITE ||
$fk->getType() == Doctrine_Table::ONE_AGGREGATE) {
if($coll->contains(0)) {
$this->references[$name] = $coll[0];
$this->originals[$name] = clone $coll[0];
} else {
$this->references[$name] = $table->create();
if($this->table->hasPrimaryKey($fk->getLocal())) {
$this->references[$name]->set($fk->getForeign(),$this);
} else {
$this->set($fk->getLocal(),$this->references[$name]);
}
}
} else {
$this->references[$name] = $coll;
$this->references[$name]->setReference($this,$fk);
$this->originals[$name] = clone $coll;
}
}
} elseif($fk instanceof Doctrine_Association) {
$foreign = $fk->getForeign();
$asf = $fk->getAssociationFactory();
$query = "SELECT ".$foreign." FROM ".$asf->getTableName()." WHERE ".$local." = ?";
$table = $fk->getTable();
$graph = new Doctrine_DQL_Parser($table->getSession());
$q = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".id IN ($query)";
$coll = $graph->query($q, array($this->getID()));
$this->references[$name] = $coll;
$this->originals[$name] = clone $coll;
}
break;
endswitch;
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function ownsOne($componentName,$foreignKey, $localKey = "id") {
$this->table->bind($componentName,$foreignKey,Doctrine_Table::ONE_COMPOSITE, $localKey);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function ownsMany($componentName,$foreignKey, $localKey = "id") {
$this->table->bind($componentName,$foreignKey,Doctrine_Table::MANY_COMPOSITE, $localKey);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function hasOne($componentName,$foreignKey, $localKey = "id") {
$this->table->bind($componentName,$foreignKey,Doctrine_Table::ONE_AGGREGATE, $localKey);
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function hasMany($componentName,$foreignKey, $localKey = "id") {
$this->table->bind($componentName,$foreignKey,Doctrine_Table::MANY_AGGREGATE, $localKey);
}
/**
* setInheritanceMap
* @param array $inheritanceMap
* @return void
*/
final public function setInheritanceMap(array $inheritanceMap) {
$this->table->setInheritanceMap($inheritanceMap);
}
/**
* setPrimaryKey
* @param string $key
*/
final public function setPrimaryKey($key) {
$this->table->setPrimaryKey($key);
}
/**
* setTableName
* @param string $name table name
* @return void
*/
final public function setTableName($name) {
$this->table->setTableName($name);
}
/**
* setAttribute
* @param integer $attribute
* @param mixed $value
* @see Doctrine::ATTR_* constants
* @return void
*/
final public function setAttribute($attribute, $value) {
$this->table->setAttribute($attribute,$value);
}
/**
* hasColumn
* @param string $name
* @param string $type
* @param integer $length
* @param mixed $options
* @return void
*/
final public function hasColumn($name, $type, $length = 20, $options = "") {
$this->table->hasColumn($name, $type, $length, $options);
}
/**
* returns a string representation of this object
*/
public function __toString() {
return Doctrine_Lib::getRecordAsString($this);
}
}
?>

View File

@ -0,0 +1,83 @@
<?php
/**
* @class Doctrine_Relation
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*
*/
class Doctrine_Relation {
/**
* @var Doctrine_Table $table foreign factory
*/
private $table;
/**
* @var string $local local field
*/
private $local;
/**
* @var string $foreign foreign field
*/
private $foreign;
/**
* @var integer $type bind type
*/
private $type;
/**
* @param Doctrine_Table $table
* @param string $local
* @param string $foreign
* @param integer $type
*/
public function __construct(Doctrine_Table $table,$local,$foreign,$type) {
$this->table = $table;
$this->local = $local;
$this->foreign = $foreign;
$this->type = $type;
}
/**
* @see Doctrine_Table::BIND_ONE, Doctrine_Table::BIND_MANY
* @return integer bind type 1 or 0
*/
public function getType() {
return $this->type;
}
/**
* @return object Doctrine_Table foreign factory object
*/
public function getTable() {
return $this->table;
}
/**
* @return string the name of the local column
*/
public function getLocal() {
return $this->local;
}
/**
* @return string the name of the foreign column where
* the local column is pointing at
*/
public function getForeign() {
return $this->foreign;
}
/**
* __toString
*/
public function __toString() {
$r[] = "<pre>";
$r[] = "Class : ".get_class($this);
$r[] = "Component : ".$this->table->getComponentName();
$r[] = "Table : ".$this->table->getTableName();
$r[] = "Local key : ".$this->local;
$r[] = "Foreign key : ".$this->foreign;
$r[] = "Type : ".$this->type;
$r[] = "</pre>";
return implode("\n", $r);
}
}
?>

View File

@ -0,0 +1,114 @@
<?php
/**
* Doctrine_Repository
* each record is added into Doctrine_Repository at the same time they are created,
* loaded from the database or retrieved from the cache
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*
*/
class Doctrine_Repository implements Countable, IteratorAggregate {
/**
* @var object Doctrine_Table $table
*/
private $table;
/**
* @var array $registry
* an array of all records
* keys representing record object identifiers
*/
private $registry = array();
/**
* constructor
*/
public function __construct(Doctrine_Table $table) {
$this->table = $table;
}
/**
* @return object Doctrine_Table
*/
public function getTable() {
return $this->table;
}
/**
* add
* @param Doctrine_Record $record record to be added into registry
*/
public function add(Doctrine_Record $record) {
$oid = $record->getOID();
if(isset($this->registry[$oid]))
return false;
$this->registry[$oid] = $record;
return true;
}
/**
* get
* @param integer $oid
* @throws InvalidKeyException
*/
public function get($oid) {
if( ! isset($this->registry[$oid]))
throw new InvalidKeyException();
return $this->registry[$oid];
}
/**
* count
* Doctrine_Registry implements interface Countable
* @return integer the number of records this registry has
*/
public function count() {
return count($this->registry);
}
/**
* @param integer $oid object identifier
* @return boolean whether ot not the operation was successful
*/
public function evict($oid) {
if( ! isset($this->registry[$oid]))
return false;
unset($this->registry[$oid]);
return true;
}
/**
* @return integer number of records evicted
*/
public function evictAll() {
$evicted = 0;
foreach($this->registry as $oid=>$record) {
if($this->evict($oid))
$evicted++;
}
return $evicted;
}
/**
* getIterator
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->registry);
}
/**
* contains
* @param integer $oid object identifier
*/
public function contains($oid) {
return isset($this->registry[$oid]);
}
/**
* loadAll
* @return void
*/
public function loadAll() {
$this->table->findAll();
}
}
?>

736
classes/Session.class.php Normal file
View File

@ -0,0 +1,736 @@
<?php
require_once("Configurable.class.php");
require_once("Record.class.php");
/**
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
abstract class Doctrine_Session extends Doctrine_Configurable implements Countable, IteratorAggregate {
/**
* Doctrine_Session is in open state when it is opened and there are no active transactions
*/
const STATE_OPEN = 0;
/**
* Doctrine_Session is in closed state when it is closed
*/
const STATE_CLOSED = 1;
/**
* Doctrine_Session is in active state when it has one active transaction
*/
const STATE_ACTIVE = 2;
/**
* Doctrine_Session is in busy state when it has multiple active transactions
*/
const STATE_BUSY = 3;
/**
* @var $dbh the database handle
*/
private $dbh;
/**
* @var array $tables an array containing all the initialized Doctrine_Table objects
* keys representing Doctrine_Table component names and values as Doctrine_Table objects
*/
private $tables = array();
/**
* @see Doctrine_Session::STATE_* constants
* @var boolean $state the current state of the session
*/
private $state = 0;
/**
* @var array $update two dimensional pending update list, the records in
* this list will be updated when transaction is committed
*/
private $update = array(array());
/**
* @var array $insert two dimensional pending insert list, the records in
* this list will be inserted when transaction is committed
*/
private $insert = array(array());
/**
* @var array $delete two dimensional pending delete list, the records in
* this list will be deleted when transaction is committed
*/
private $delete = array(array());
/**
* @var integer $transaction_level the nesting level of transactions, used by transaction methods
*/
private $transaction_level = 0;
private $validator;
/**
* the constructor
* @param PDO $pdo -- database handle
*/
public function __construct(Doctrine_Manager $manager,PDO $pdo) {
$this->dbh = $pdo;
$this->setParent($manager);
$this->state = Doctrine_Session::STATE_OPEN;
$this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->getAttribute(Doctrine::ATTR_LISTENER)->onOpen($this);
}
/**
* @return integer the session state
*/
public function getState() {
return $this->state;
}
/**
* @return Doctrine_Manager
*/
public function getManager() {
return $this->getParent();
}
/**
* @return object PDO the database handle
*/
public function getDBH() {
return $this->dbh;
}
/**
* query
* queries the database with Doctrine Query Language
*/
final public function query($query,array $params = array()) {
$parser = new Doctrine_DQL_Parser($this);
return $parser->query($query, $params);
}
/**
* queries the database with limit and offset
* added to the query and returns a PDOStatement object
*
* @param string $query
* @param integer $limit
* @param integer $offset
* @return PDOStatement
*/
public function select($query,$limit = 0,$offset = 0) {
if($limit > 0 || $offset > 0)
$query = $this->modifyLimitQuery($query,$limit,$offset);
return $this->dbh->query($query);
}
/**
* @return object PDOStatement -- the PDOStatement object
*/
public function execute($query, array $params = array()) {
if( ! empty($params)) {
$stmt = $this->dbh->prepare($query);
$stmt->execute($params);
return $stmt;
} else {
return $this->dbh->query($query);
}
}
/**
* @param $mixed -- Doctrine_Table name
* @return boolean
*/
public function hasTable($name) {
return isset($this->tables[$name]);
}
/**
* @param string $name component name
* @throws Doctrine_Table_Exception
* @return object Doctrine_Table
*/
public function getTable($name) {
$name = ucwords(strtolower($name));
if(isset($this->tables[$name]))
return $this->tables[$name];
$class = $name."Table";
if(class_exists($class) && in_array("Doctrine_Table", class_parents($class)))
return new $class($name);
else
return new Doctrine_Table($name);
}
/**
* @return array -- an array of all initialized factories
*/
public function getTables() {
return $this->tables;
}
/**
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->tables);
}
/**
* @return integer
*/
public function count() {
return count($this->tables);
}
/**
* @param $objTable -- a Doctrine_Table object to be added into factory registry
* @return boolean
*/
public function addTable(Doctrine_Table $objTable) {
$name = $objTable->getComponentName();
if(isset($this->tables[$name]))
return false;
$this->tables[$name] = $objTable;
return true;
}
/**
* create creates a record
* @param string $name component name
* @return Doctrine_Record Doctrine_Record object
*/
public function create($name) {
return $this->getTable($name)->create();
}
/**
* buildFlushTree
* @return array
*/
public function buildFlushTree() {
$tree = array();
foreach($this->tables as $k => $table) {
$tmp = array();
$tmp[] = $table->getComponentName();
$pos = 0;
foreach($table->getForeignKeys() as $fk) {
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
$name = $fk->getTable()->getComponentName();
$index = array_search($name,$tree);
if(isset($locked[$name])) {
$pos = $index;
continue;
}
if($index !== false)
unset($tree[$index]);
switch($fk->getType()):
case Doctrine_Table::ONE_COMPOSITE:
case Doctrine_Table::ONE_AGGREGATE:
array_unshift($tmp,$name);
break;
case Doctrine_Table::MANY_COMPOSITE:
case Doctrine_Table::MANY_AGGREGATE:
$tmp[] = $name;
break;
endswitch;
$locked[$name] = true;
}
}
$index = array_search($k,$tree);
if($index === false) {
if($pos != 0) {
$first = array_splice($tree,0,$pos);
$tree = array_merge($first, $tmp, $tree);
} else {
$tree = array_merge($tree,$tmp);
}
} else {
$first = array_splice($tree,0,$index);
array_splice($tree, 0, ($index + 1));
$tree = array_merge($first, $tmp, $tree);
}
}
return $tree;
}
/**
* flush saves all the records from all tables
* this operation is isolated using a transaction
* @return void
*/
public function flush() {
$this->beginTransaction();
$this->saveAll();
$this->commit();
}
/**
* saveAll save all the records from all tables
*/
private function saveAll() {
$tree = $this->buildFlushTree();
foreach($tree as $name) {
$table = $this->tables[$name];
foreach($table->getRepository() as $record) {
$this->save($record);
}
}
foreach($tree as $name) {
$table = $this->tables[$name];
foreach($table->getRepository() as $record) {
$record->saveAssociations();
}
}
}
/**
* clear -- clears the whole registry
* @return void
*/
public function clear() {
foreach($this->tables as $k => $objTable) {
$objTable->getRepository()->evictAll();
}
$this->tables = array();
}
/**
* close
* closes the session
* @return void
*/
public function close() {
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreClose($this);
$this->clear();
$this->state = Doctrine_Session::STATE_CLOSED;
$this->getAttribute(Doctrine::ATTR_LISTENER)->onClose($this);
}
/**
* get the current transaction nesting level
* @return integer transaction nesting level
*/
public function getTransactionLevel() {
return $this->transaction_level;
}
/**
* beginTransaction
* starts a new transaction
* @return void
*/
public function beginTransaction() {
if($this->transaction_level == 0) {
if($this->getAttribute(Doctrine::ATTR_LOCKMODE) == Doctrine::LOCK_PESSIMISTIC) {
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionBegin($this);
$this->dbh->beginTransaction();
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionBegin($this);
}
$this->state = Doctrine_Session::STATE_ACTIVE;
} else {
$this->state = Doctrine_Session::STATE_BUSY;
}
$this->transaction_level++;
}
/**
* commits the current transaction
* if lockmode is optimistic this method starts a transaction
* and commits it instantly
* @return void
*/
public function commit() {
$this->transaction_level--;
if($this->transaction_level == 0) {
if($this->getAttribute(Doctrine::ATTR_LOCKMODE) == Doctrine::LOCK_OPTIMISTIC) {
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionBegin($this);
$this->dbh->beginTransaction();
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionBegin($this);
}
if($this->getAttribute(Doctrine::ATTR_VLD)) {
$this->validator = new Doctrine_Validator();
}
$this->bulkInsert();
$this->bulkUpdate();
$this->bulkDelete();
if(isset($this->validator) && $this->validator->hasErrors()) {
$this->rollback();
throw new Doctrine_Validator_Exception($this->validator);
}
$this->dbh->commit();
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionCommit($this);
$this->delete = array(array());
$this->state = Doctrine_Session::STATE_OPEN;
$this->validator = null;
} elseif($this->transaction_level == 1)
$this->state = Doctrine_Session::STATE_ACTIVE;
}
/**
* rollback
* rolls back all the transactions
* @return void
*/
public function rollback() {
$this->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionRollback($this);
$this->transaction_level = 0;
$this->dbh->rollback();
$this->state = Doctrine_Session::STATE_OPEN;
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionRollback($this);
}
/**
* bulkInsert
* inserts all the objects in the pending insert list into database
* @return void
*/
public function bulkInsert() {
foreach($this->insert as $name => $inserts) {
if( ! isset($inserts[0]))
continue;
$record = $inserts[0];
$table = $record->getTable();
$seq = $table->getSequenceName();
$increment = false;
$id = null;
$keys = $table->getPrimaryKeys();
if(count($keys) == 1 && $keys[0] == "id") {
// record uses auto_increment column
$sql = "SELECT MAX(id) FROM ".$record->getTable()->getTableName();
$stmt = $this->dbh->query($sql);
$data = $stmt->fetch(PDO::FETCH_NUM);
$id = $data[0];
$stmt->closeCursor();
$increment = true;
}
foreach($inserts as $k => $record) {
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record);
// listen the onPreInsert event
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreInsert($record);
if($increment) {
// record uses auto_increment column
$id++;
}
$this->insert($record,$id);
// listen the onInsert event
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onInsert($record);
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
$record->getTable()->getCache()->store($record);
}
}
$this->insert = array(array());
}
/**
* bulkUpdate
* updates all objects in the pending update list
* @return void
*/
public function bulkUpdate() {
foreach($this->update as $name => $updates) {
foreach($updates as $k => $record) {
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record);
// listen the onPreUpdate event
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreUpdate($record);
$this->update($record);
// listen the onUpdate event
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onUpdate($record);
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
}
}
$this->update = array(array());
}
/**
* bulkDelete
* @return void
*/
public function bulkDelete() {
foreach($this->delete as $name => $deletes) {
$record = false;
$ids = array();
foreach($deletes as $k => $record) {
$ids[] = $record->getID();
$record->setID(null);
}
if($record instanceof Doctrine_Record) {
$params = substr(str_repeat("?, ",count($ids)),0,-2);
$query = "DELETE FROM ".$record->getTable()->getTableName()." WHERE id IN(".$params.")";
$this->execute($query,$ids);
$record->getTable()->getCache()->deleteMultiple($ids);
}
}
$this->delete = array(array());
}
/**
* @param Doctrine_Collection $coll
* @return void
*/
public function saveCollection(Doctrine_Collection $coll) {
$this->beginTransaction();
foreach($coll as $key=>$record):
$record->save();
endforeach;
$this->commit();
}
/**
* @param Doctrine_Collection $coll
* @return void
*/
public function deleteCollection(Doctrine_Collection $coll) {
$this->beginTransaction();
foreach($coll as $k=>$record) {
$record->delete();
}
$this->commit();
}
/**
* @param Doctrine_Record $record
* @return void
*/
public function save(Doctrine_Record $record) {
switch($record->getState()):
case Doctrine_Record::STATE_TDIRTY:
$this->addInsert($record);
break;
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_PROXY:
$this->addUpdate($record);
break;
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_TCLEAN:
// do nothing
break;
endswitch;
}
/**
* @param Doctrine_Record $record
*/
final public function saveRelated(Doctrine_Record $record) {
$saveLater = array();
foreach($record->getReferences() as $k=>$v) {
$fk = $record->getTable()->getForeignKey($k);
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($fk->getType()):
case Doctrine_Table::ONE_COMPOSITE:
case Doctrine_Table::MANY_COMPOSITE:
$local = $fk->getLocal();
$foreign = $fk->getForeign();
if($record->getTable()->hasPrimaryKey($fk->getLocal())) {
switch($record->getState()):
case Doctrine_Record::STATE_TDIRTY:
case Doctrine_Record::STATE_TCLEAN:
$saveLater[$k] = $fk;
break;
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_DIRTY:
$v->save();
break;
endswitch;
} else {
// ONE-TO-ONE relationship
$obj = $record->get($fk->getTable()->getComponentName());
if($obj->getState() != Doctrine_Record::STATE_TCLEAN)
$obj->save();
}
break;
endswitch;
} elseif($fk instanceof Doctrine_Association) {
$v->save();
}
}
return $saveLater;
}
/**
* @param Doctrine_Record $record
* @return boolean
*/
private function update(Doctrine_Record $record) {
$array = $record->getModified();
if(empty($array))
return false;
$set = array();
foreach($array as $name => $value):
$set[] = $name." = ?";
if($value instanceof Doctrine_Record) {
$array[$name] = $value->getID();
$record->set($name, $value->getID());
}
endforeach;
if(isset($this->validator)) {
if( ! $this->validator->validateRecord($record)) {
return false;
}
}
$params = array_values($array);
$params[] = $record->getID();
$sql = "UPDATE ".$record->getTable()->getTableName()." SET ".implode(", ",$set)." WHERE ".implode(" = ? && ",$record->getTable()->getPrimaryKeys())." = ?";
$stmt = $this->dbh->prepare($sql);
$stmt->execute($params);
$record->setID($record->getID());
$record->getTable()->getCache()->delete($record->getID());
return true;
}
/**
* @param Doctrine_Record $record
* @return boolean
*/
private function insert(Doctrine_Record $record,$id = null) {
$array = $record->getModified();
if(empty($array))
return false;
foreach($record->getTable()->getInheritanceMap() as $k=>$v):
$array[$k] = $v;
endforeach;
$seq = $record->getTable()->getSequenceName();
if( ! empty($seq)) {
$id = $this->getNextID($seq);
$array["id"] = $id;
}
foreach($array as $k => $value) {
if($value instanceof Doctrine_Record) {
$array[$k] = $value->getID();
$record->set($k,$value->getID());
}
}
if(isset($this->validator)) {
if( ! $this->validator->validateRecord($record)) {
return false;
}
}
$strfields = join(", ", array_keys($array));
$strvalues = substr(str_repeat("?, ",count($array)),0,-2);
$sql = "INSERT INTO ".$record->getTable()->getTableName()." (".$strfields.") VALUES (".$strvalues.")";
$stmt = $this->dbh->prepare($sql);
$stmt->execute(array_values($array));
$record->setID($id);
return true;
}
/**
* deletes all related composites
* this method is always called internally when this data access object is deleted
*
* @return void
*/
final public function deleteComposites(Doctrine_Record $record) {
foreach($record->getTable()->getForeignKeys() as $fk) {
switch($fk->getType()):
case Doctrine_Table::ONE_COMPOSITE:
case Doctrine_Table::MANY_COMPOSITE:
$obj = $record->get($fk->getTable()->getComponentName());
$obj->delete();
break;
endswitch;
}
}
/**
* deletes this data access object and all the related composites
* this operation is isolated by a transaction
*
* this event can be listened by the onPreDelete and onDelete listeners
*
* @return boolean true on success, false on failure
*/
final public function delete(Doctrine_Record $record) {
switch($record->getState()):
case Doctrine_Record::STATE_PROXY:
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_DIRTY:
$this->beginTransaction();
$this->deleteComposites($record);
$this->addDelete($record);
$this->commit();
return true;
break;
default:
return false;
endswitch;
}
/**
* adds data access object into pending insert list
* @param Doctrine_Record $record
*/
public function addInsert(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->insert[$name][] = $record;
}
/**
* adds data access object into penging update list
* @param Doctrine_Record $record
*/
public function addUpdate(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->update[$name][] = $record;
}
/**
* adds data access object into pending delete list
* @param Doctrine_Record $record
*/
public function addDelete(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->delete[$name][] = $record;
}
/**
* returns a string representation of this object
* @return string
*/
public function __toString() {
return Doctrine_Lib::getSessionAsString($this);
}
}
?>

View File

@ -0,0 +1,10 @@
<?php
/**
* standard session, the parent of pgsql, mysql and sqlite
*/
class Doctrine_Session_Common extends Doctrine_Session {
public function modifyLimitQuery($query,$limit,$offset) {
return $query." LIMIT ".$limit." OFFSET ".$offset;
}
}
?>

View File

@ -0,0 +1,20 @@
<?php
/**
* firebird driver
*/
class Doctrine_Session_Firebird extends Doctrine_Session {
public function modifyLimitQuery($query,$limit,$offset) {
return preg_replace("/([\s(])*SELECT/i","\\1SELECT TOP($from, $count)", $query);
}
/**
* returns the next value in the given sequence
* @param string $sequence
* @return integer
*/
public function getNextID($sequence) {
$stmt = $this->query("SELECT UNIQUE FROM ".$sequence);
$data = $stmt->fetch(PDO::FETCH_NUM);
return $data[0];
}
}
?>

View File

@ -0,0 +1,6 @@
<?php
/**
* informix database driver
*/
class Doctrine_Session_Informix extends Doctrine_Session { }
?>

View File

@ -0,0 +1,18 @@
<?php
/**
* mssql driver
*/
class Doctrine_Session_Mssql extends Doctrine_Session {
/**
* returns the next value in the given sequence
* @param string $sequence
* @return integer
*/
public function getNextID($sequence) {
$this->query("INSERT INTO $sequence (vapor) VALUES (0)");
$stmt = $this->query("SELECT @@IDENTITY FROM $sequence");
$data = $stmt->fetch(PDO::FETCH_NUM);
return $data[0];
}
}
?>

View File

@ -0,0 +1,38 @@
<?php
/**
* mysql driver
*/
class Doctrine_Session_Mysql extends Doctrine_Session_Common {
/**
* deletes all data access object from the collection
* @param Doctrine_Collection $coll
*/
/**
public function deleteCollection(Doctrine_Collection $coll) {
$a = $coll->getTable()->getCompositePaths();
$a = array_merge(array($coll->getTable()->getComponentName()),$a);
$graph = new Doctrine_DQL_Parser($this);
foreach($coll as $k=>$record) {
switch($record->getState()):
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_CLEAN:
$ids[] = $record->getID();
break;
endswitch;
}
if(empty($ids))
return array();
$graph->parseQuery("FROM ".implode(", ",$a)." WHERE ".$coll->getTable()->getTableName().".id IN(".implode(", ",$ids).")");
$query = $graph->buildDelete();
$this->getDBH()->query($query);
return $ids;
}
*/
}
?>

View File

@ -0,0 +1,25 @@
<?php
/**
* oracle driver
*/
class Doctrine_Session_Oracle extends Doctrine_Session {
public function modifyLimitQuery($query,$limit,$offset) {
$e = explode("select ",strtolower($query));
$e2 = explode(" from ",$e[1]);
$fields = $e2[0];
$query = "SELECT $fields FROM (SELECT rownum as linenum, $fields FROM ($query) WHERE rownum <= ($offset + $limit)) WHERE linenum >= ".++$offset;
return $query;
}
/**
* returns the next value in the given sequence
* @param string $sequence
* @return integer
*/
public function getNextID($sequence) {
$stmt = $this->query("SELECT $sequence.nextval FROM dual");
$data = $stmt->fetch(PDO::FETCH_NUM);
return $data[0];
}
}
?>

View File

@ -0,0 +1,17 @@
<?php
/**
* pgsql driver
*/
class Doctrine_Session_Pgsql extends Doctrine_Session_Common {
/**
* returns the next value in the given sequence
* @param string $sequence
* @return integer
*/
public function getNextID($sequence) {
$stmt = $this->query("SELECT NEXTVAL('$sequence')");
$data = $stmt->fetch(PDO::FETCH_NUM);
return $data[0];
}
}
?>

View File

@ -0,0 +1,6 @@
<?php
/**
* sqlite driver
*/
class Doctrine_Session_Sqlite extends Doctrine_Session_Common { }
?>

617
classes/Table.class.php Normal file
View File

@ -0,0 +1,617 @@
<?php
require_once("Configurable.class.php");
/**
* Doctrine_Table represents a database table
* each Doctrine_Table holds the information of foreignKeys and associations
*
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Table extends Doctrine_Configurable {
/**
* constant for ONE_TO_ONE and MANY_TO_ONE aggregate relationships
*/
const ONE_AGGREGATE = 0;
/**
* constant for ONE_TO_ONE and MANY_TO_ONE composite relationships
*/
const ONE_COMPOSITE = 1;
/**
* constant for MANY_TO_MANY and ONE_TO_MANY aggregate relationships
*/
const MANY_AGGREGATE = 2;
/**
* constant for MANY_TO_MANY and ONE_TO_MANY composite relationships
*/
const MANY_COMPOSITE = 3;
/**
* @var boolean $isNewEntry whether ot not this table created a new record or not, used only internally
*/
private $isNewEntry = false;
/**
* @var array $data temporary data which is then loaded into Doctrine_Record::$data
*/
private $data = array();
/**
* @var array $foreignKeys an array containing all the Doctrine_ForeignKey objects for this table
*/
private $foreignKeys = array();
/**
* @var array $primaryKeys an array containing all primary key column names
*/
private $primaryKeys = array();
/**
* @var integer $primaryType
*/
private $primaryType;
/**
* @var string $query cached simple query
*/
private $query;
/**
* @var Doctrine_Session $session Doctrine_Session object that created this table
*/
private $session;
/**
* @var string $name name of the component, for example component name of the GroupTable is 'Group'
*/
private $name;
/**
* @var string $tableName database table name, in most cases this is the same as component name but in some cases
* where one-table-multi-class inheritance is used this will be the name of the inherited table
*/
private $tableName;
/**
* @var string $sequenceName Some databases need sequences instead of auto incrementation primary keys, you can set specific
* sequence for your table by calling setSequenceName()
*/
private $sequenceName;
/**
* @var Doctrine_Repository $repository first level cache
*/
private $repository;
/**
* @var Doctrine_Cache $cache second level cache
*/
private $cache;
/**
* @var Doctrine_Table_Description $description columns object for this table
*/
private $columns;
/**
* @var array $bound bound relations
*/
private $bound = array();
/**
* @var array $inheritanceMap inheritanceMap is used for inheritance mapping, keys representing columns and values
* the column values that should correspond to child classes
*/
private $inheritanceMap = array();
/**
* @var array $parents the parent classes of this component
*/
private $parents = array();
/**
* the constructor
* @throws Doctrine_ManagerException if there are no opened sessions
* @throws Doctrine_TableException if there is already an instance of this table
* @return void
*/
public function __construct($name) {
$this->session = Doctrine_Manager::getInstance()->getCurrentSession();
$this->setParent($this->session);
$name = ucwords(strtolower($name));
$this->name = $name;
if( ! class_exists($name) || empty($name))
throw new Doctrine_Exception("Couldn't find class $name");
$record = new $name($this);
$record->setUp();
$names = array();
$class = $name;
// get parent classes
do {
if($class == "Doctrine_Record") break;
$name = ucwords(strtolower($class));
$names[] = $name;
} while($class = get_parent_class($class));
// reverse names
$names = array_reverse($names);
// create database table
if(method_exists($record,"setTableDefinition")) {
$record->setTableDefinition();
if(isset($this->columns)) {
$method = new ReflectionMethod($name,"setTableDefinition");
$class = $method->getDeclaringClass();
if( ! isset($this->tableName))
$this->tableName = strtolower($class->getName());
switch(count($this->primaryKeys)):
case 0:
$this->columns = array_merge(array("id" => array("integer",11,"AUTOINCREMENT PRIMARY")), $this->columns);
$this->primaryKeys[] = "id";
break;
case 1:
break;
default:
endswitch;
if($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
$dict = new Doctrine_DataDict($this);
$dict->createTable($this->columns);
}
}
} else {
throw new Doctrine_Exception("Class '$name' has no table definition.");
}
// save parents
array_pop($names);
$this->parents = $names;
$this->query = "SELECT ".implode(", ",array_keys($this->columns))." FROM ".$this->getTableName();
// check if an instance of this table is already initialized
if( ! $this->session->addTable($this))
throw new Doctrine_Table_Exception();
$this->initComponents();
}
/**
* initializes components this table uses
*
* @return void
*/
final public function initComponents() {
$this->repository = new Doctrine_Repository($this);
switch($this->getAttribute(Doctrine::ATTR_CACHE)):
case Doctrine::CACHE_FILE:
$this->cache = new Doctrine_Cache_File($this);
break;
case Doctrine::CACHE_NONE:
$this->cache = new Doctrine_Cache($this);
break;
endswitch;
}
/**
* hasColumn
* @param string $name
* @param string $type
* @param integer $length
* @param mixed $options
* @return void
*/
final public function hasColumn($name, $type, $length, $options = "") {
$this->columns[$name] = array($type,$length,$options);
$e = explode("|",$options);
if(in_array("primary",$e)) {
$this->primaryKeys[] = $name;
}
}
/**
* returns all primary keys
* @return array
*/
final public function getPrimaryKeys() {
return $this->primaryKeys;
}
/**
* @return boolean
*/
final public function hasPrimaryKey($key) {
return in_array($key,$this->primaryKeys);
}
/**
* @param $sequence
* @return void
*/
final public function setSequenceName($sequence) {
$this->sequenceName = $sequence;
}
/**
* @return string sequence name
*/
final public function getSequenceName() {
return $this->sequenceName;
}
/**
* setInheritanceMap
* @param array $inheritanceMap
* @return void
*/
final public function setInheritanceMap(array $inheritanceMap) {
$this->inheritanceMap = $inheritanceMap;
}
/**
* @return array inheritance map (array keys as fields)
*/
final public function getInheritanceMap() {
return $this->inheritanceMap;
}
/**
* return all composite paths in the form [component1].[component2]. . .[componentN]
* @return array
*/
final public function getCompositePaths() {
$array = array();
$name = $this->getComponentName();
foreach($this->bound as $k=>$a) {
try {
$fk = $this->getForeignKey($k);
switch($fk->getType()):
case Doctrine_Table::ONE_COMPOSITE:
case Doctrine_Table::MANY_COMPOSITE:
$n = $fk->getTable()->getComponentName();
$array[] = $name.".".$n;
$e = $fk->getTable()->getCompositePaths();
if( ! empty($e)) {
foreach($e as $name) {
$array[] = $name.".".$n.".".$name;
}
}
break;
endswitch;
} catch(InvalidKeyException $e) {
}
}
return $array;
}
/**
* @var array bound relations
*/
final public function getBounds() {
return $this->bound;
}
/**
* @param string $name
*/
final public function getBound($name) {
if( ! isset($this->bound[$name]))
throw new InvalidKeyException();
return $this->bound[$name];
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function bind($objTableName,$fkField,$type,$localKey) {
$name = (string) $objTableName;
$field = (string) $fkField;
if(isset($this->foreignKeys[$name]))
throw new InvalidKeyException();
$e = explode(".", $field);
// is reference table used?
if($e[0] != $name && $e[0] == $this->name)
$this->bound[$name] = array($field,Doctrine_Table::MANY_COMPOSITE);
$this->bound[$name] = array($field,$type,$localKey);
}
/**
* getComponentName
* @return string the component name
*/
final public function getComponentName() {
return $this->name;
}
/**
* @return Doctrine_Session
*/
final public function getSession() {
return $this->session;
}
/**
* @return Doctrine_Cache
*/
final public function getCache() {
return $this->cache;
}
/**
* @return Doctrine_Repository
*/
final public function getRepository() {
return $this->repository;
}
/**
* @param string $name component name of which a foreign key object is bound
* @return Doctrine_ForeignKey
*/
final public function getForeignKey($name) {
if(isset($this->foreignKeys[$name]))
return $this->foreignKeys[$name];
if(isset($this->bound[$name])) {
$type = $this->bound[$name][1];
$field = $this->bound[$name][0];
$e = explode(".",$field);
$objTable = $this->session->getTable($name);
switch($e[0]):
case $name:
// ONE-TO-MANY or ONE-TO-ONE
$foreignKey = new Doctrine_ForeignKey($objTable,$this->bound[$name][2],$e[1],$type);
break;
case $this->name:
// ONE-TO-ONE
if($type <= Doctrine_Table::ONE_COMPOSITE)
$foreignKey = new Doctrine_LocalKey($objTable,$e[1],$this->bound[$name][2],$type);
else
throw new Doctrine_Mapping_Exception();
break;
default:
if(in_array($e[0], $this->parents)) {
// ONE-TO-ONE
if($type <= Doctrine_Table::ONE_COMPOSITE)
$foreignKey = new Doctrine_LocalKey($objTable,$e[1],$this->bound[$name][2],$type);
else
throw new Doctrine_Mapping_Exception();
} else {
// POSSIBLY MANY-TO-MANY
$bound = $objTable->getBound($this->name);
$e2 = explode(".",$bound[0]);
if($e2[0] != $e[0])
throw new Doctrine_Mapping_Exception();
$associationTable = $this->session->getTable($e2[0]);
$this->foreignKeys[$e2[0]] = new Doctrine_ForeignKey($associationTable,$this->bound[$name][2],$e2[1],Doctrine_Table::MANY_COMPOSITE);
$foreignKey = new Doctrine_Association($objTable,$associationTable,$e2[1],$e[1],$type);
}
endswitch;
$this->foreignKeys[$name] = $foreignKey;
return $this->foreignKeys[$name];
} else {
throw new InvalidKeyException();
}
}
/**
* @return array an array containing all foreign key objects
*/
final public function getForeignKeys() {
$a = array();
foreach($this->bound as $k=>$v) {
$a[$k] = $this->getForeignKey($k);
}
return $a;
}
/**
* @return void
*/
final public function setTableName($name) {
$this->tableName = $name;
}
/**
* @return string database table name this class represents
*/
final public function getTableName() {
return $this->tableName;
}
/**
* createDAO
* @param $array an array where keys are field names and values representing field values
* @return Doctrine_Record A new Data Access Object. Uses an sql insert statement when saved
*/
final public function create(array $array = array()) {
$this->data = $array;
$this->isNewEntry = true;
$record = $this->getRecord();
$this->isNewEntry = false;
return $record;
}
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
* @return DAOProxy a proxy for given database row, if the id is not set method
* uses internal factory data (= data that was fetched by datagraph or collection)
*/
final public function find($id = null) {
if($id !== null) {
try {
// try to get from cache
$record = $this->cache->fetch($id);
return $record;
} catch(InvalidKeyException $e) {
// do nothing
}
$query = $this->query." WHERE ".implode(" = ? && ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
$params = array_merge(array($id), array_values($this->inheritanceMap));
$this->data = $this->session->execute($query,$params)->fetch(PDO::FETCH_ASSOC);
if($this->data === false)
throw new Doctrine_Find_Exception();
}
return $this->getRecord();
}
/**
* applyInheritance
* @param $where query where part to be modified
* @return query where part with column aggregation inheritance added
*/
final public function applyInheritance($where) {
if( ! empty($this->inheritanceMap)) {
$a = array();
foreach($this->inheritanceMap as $field => $value) {
$a[] = $field." = ?";
}
$i = implode(" && ",$a);
$where .= " && $i";
}
return $where;
}
/**
* findAll
* @return Doctrine_Collection a collection of all data access objects
*/
final public function findAll() {
$graph = new Doctrine_DQL_Parser($this->session);
$users = $graph->query("FROM ".$this->name);
return $users;
}
/**
* findBySql
* @return Doctrine_Collection a collection of data access objects
*/
final public function findBySql($sql) {
$graph = new Doctrine_DQL_Parser($this->session);
$users = $graph->query("FROM ".$this->name." WHERE ".$sql);
return $users;
}
/**
* getRecord
* @return Doctrine_Record
*/
public function getRecord() {
return new $this->name($this);
}
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
* @return DAOProxy a proxy for given database row, if the id is not set method
* uses internal factory data (= data that was fetched by datagraph or collection)
*/
final public function getProxy($id = null) {
if($id !== null) {
$id = (int) $id;
try {
// try to get from cache
$record = $this->cache->fetch($id);
return $record;
} catch(InvalidKeyException $e) {
// do nothing
}
$query = "SELECT ".implode(", ",$this->primaryKeys)." FROM ".$this->getTableName()." WHERE ".implode(" = ? && ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
$params = array_merge(array($id), array_values($this->inheritanceMap));
$this->data = $this->session->execute($query,$params)->fetch(PDO::FETCH_ASSOC);
if($this->data === false)
throw new Doctrine_Find_Exception();
}
return $this->getRecord();
}
/**
* getTableDescription
* @return Doctrine_Table_Description the columns object for this factory
*/
final public function getTableDescription() {
return $this->columns;
}
/**
* @param integer $fetchMode
* @return Doctrine_DQL_Parser a Doctrine_DQL_Parser object
*/
public function getDQLParser() {
$graph = new Doctrine_DQL_Parser($this->getSession());
$graph->load($this->getComponentName());
return $graph;
}
/**
* execute
*/
public function execute($query, array $array = array()) {
$coll = new Doctrine_Collection($this);
$stmt = $this->session->getDBH()->prepare($query);
$stmt->execute($array);
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach($data as $row) {
$this->data = $row;
try {
$record = $this->getCache()->fetch($this->data["id"]);
} catch(InvalidKeyException $e) {
$record = $this->getRecord();
}
$coll->add($record);
}
return $coll;
}
/**
* @return array
*/
final public function getColumns() {
return $this->columns;
}
/**
* @return array an array containing all the column names
*/
public function getColumnNames() {
return array_keys($this->columns);
}
/**
* setData
* @param array $data internal data, users are strongly discouraged to use this function
* @return void
*/
public function setData(array $data) {
$this->data = $data;
}
/**
* @return boolean whether or not a newly created object is new or not
*/
final public function isNewEntry() {
return $this->isNewEntry;
}
/**
* @return string simple cached query
*/
final public function getQuery() {
return $this->query;
}
/**
* @return array internal data, used by Doctrine_Record instances when retrieving data from database
*/
final public function getData() {
return $this->data;
}
/**
* @return string string representation of this object
*/
public function __toString() {
return Doctrine_Lib::getTableAsString($this);
}
}
?>

111
classes/Validator.class.php Normal file
View File

@ -0,0 +1,111 @@
<?php
class Doctrine_Validator {
const ERR_LENGTH = 0;
const ERR_TYPE = 1;
const ERR_VALID = 2;
const ERR_UNIQUE = 3;
/**
* @var array $stack error stack
*/
private $stack = array();
/**
* @var array $validators
*/
private static $validators = array();
/**
* @param string $name
*/
public static function getValidator($name) {
if( ! isset(self::$validators[$name])) {
$class = "Doctrine_Validator_".ucwords(strtolower($name));
if(class_exists($class)) {
self::$validators[$name] = new $class;
} elseif(class_exists($name."Validator")) {
self::$validators[$name] = new $name."Validator";
} else
throw new Doctrine_Exception("Validator named '$name' not availible.");
}
return self::$validators[$name];
}
/**
* @param Doctrine_Record $record
* @return void
*/
public function validateRecord(Doctrine_Record $record) {
$modified = $record->getModified();
$columns = $record->getTable()->getColumns();
$name = $record->getTable()->getComponentName();
$err = array();
foreach($modified as $key => $value) {
$column = $columns[$key];
if(strlen($value) > $column[1]) {
$err[$key] = Doctrine_Validator::ERR_LENGTH;
continue;
}
if(self::gettype($value) !== $column[0]) {
$err[$key] = Doctrine_Validator::ERR_TYPE;
continue;
}
$e = explode("|",$column[2]);
foreach($e as $k => $arg) {
if(empty($arg) || $arg == "primary")
continue;
$validator = self::getValidator($arg);
if( ! $validator->validate($record,$key,$value)) {
switch(strtolower($arg)):
case "unique":
$err[$key] = Doctrine_Validator::ERR_UNIQUE;
break;
default:
$err[$key] = Doctrine_Validator::ERR_VALID;
break;
endswitch;
}
if(isset($err[$key]))
break;
}
}
if( ! empty($err)) {
$this->stack[$name][] = $err;
return false;
}
return true;
}
/**
* @return boolean
*/
public function hasErrors() {
return (count($this->stack) > 0);
}
/**
* @return array
*/
public function getErrorStack() {
return $this->stack;
}
/**
* @param mixed $var
*/
public static function gettype($var) {
$type = gettype($var);
switch($type):
case "string":
if(preg_match("/^[0-9]*$/",$var)) return "integer";
elseif(is_numeric($var)) return "float";
else return $type;
break;
default:
return $type;
endswitch;
}
}
?>

View File

@ -0,0 +1,18 @@
<?php
class Doctrine_Validator_Blank {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
$string = str_replace("\n","",$value);
$string = str_replace("\r","",$string);
$string = str_replace("\t","",$string);
$string = str_replace("\s","",$string);
$string = str_replace(" ","",$string);
if($string == "") return true;
}
}
?>

View File

@ -0,0 +1,264 @@
<?php
class Doctrine_Validator_Country {
private static $countries = array(
"ad" => "Andorra",
"ae" => "United Arab Emirates",
"af" => "Afghanistan",
"ag" => "Antigua and Barbuda",
"ai" => "Anguilla",
"al" => "Albania",
"am" => "Armenia",
"an" => "Netherlands Antilles",
"ao" => "Angola",
"aq" => "Antarctica",
"ar" => "Argentina",
"as" => "American Samoa",
"at" => "Austria",
"au" => "Australia",
"aw" => "Aruba",
"az" => "Azerbaijan",
"ba" => "Bosnia Hercegovina",
"bb" => "Barbados",
"bd" => "Bangladesh",
"be" => "Belgium",
"bf" => "Burkina Faso",
"bg" => "Bulgaria",
"bh" => "Bahrain",
"bi" => "Burundi",
"bj" => "Benin",
"bm" => "Bermuda",
"bn" => "Brunei Darussalam",
"bo" => "Bolivia",
"br" => "Brazil",
"bs" => "Bahamas",
"bt" => "Bhutan",
"bv" => "Bouvet Island",
"bw" => "Botswana",
"by" => "Belarus (Byelorussia)",
"bz" => "Belize",
"ca" => "Canada",
"cc" => "Cocos Islands",
"cd" => 'Congo, The Democratic Republic of the',
"cf" => "Central African Republic",
"cg" => "Congo",
"ch" => "Switzerland",
"ci" => "Ivory Coast",
"ck" => "Cook Islands",
"cl" => "Chile",
"cm" => "Cameroon",
"cn" => "China",
"co" => "Colombia",
"cr" => "Costa Rica",
"cs" => "Czechoslovakia",
"cu" => "Cuba",
"cv" => "Cape Verde",
"cx" => "Christmas Island",
"cy" => "Cyprus",
"cz" => 'Czech Republic',
"de" => "Germany",
"dj" => "Djibouti",
"dk" => 'Denmark',
"dm" => "Dominica",
"do" => "Dominican Republic",
"dz" => "Algeria",
"ec" => "Ecuador",
"ee" => "Estonia",
"eg" => "Egypt",
"eh" => "Western Sahara",
"er" => 'Eritrea',
"es" => "Spain",
"et" => "Ethiopia",
"fi" => "Finland",
"fj" => "Fiji",
"fk" => "Falkland Islands",
"fm" => "Micronesia",
"fo" => "Faroe Islands",
"fr" => "France",
"fx" => 'France, Metropolitan FX',
"ga" => "Gabon",
"gb" => 'United Kingdom (Great Britain)',
"gd" => "Grenada",
"ge" => "Georgia",
"gf" => "French Guiana",
"gh" => "Ghana",
"gi" => "Gibraltar",
"gl" => "Greenland",
"gm" => "Gambia",
"gn" => "Guinea",
"gp" => "Guadeloupe",
"gq" => "Equatorial Guinea",
"gr" => "Greece",
"gs" => 'South Georgia and the South Sandwich Islands',
"gt" => "Guatemala",
"gu" => "Guam",
"gw" => "Guinea-bissau",
"gy" => "Guyana",
"hk" => "Hong Kong",
"hm" => "Heard and McDonald Islands",
"hn" => "Honduras",
"hr" => "Croatia",
"ht" => "Haiti",
"hu" => "Hungary",
"id" => "Indonesia",
"ie" => "Ireland",
"il" => "Israel",
"in" => "India",
"io" => "British Indian Ocean Territory",
"iq" => "Iraq",
"ir" => "Iran",
"is" => "Iceland",
"it" => "Italy",
"jm" => "Jamaica",
"jo" => "Jordan",
"jp" => "Japan",
"ke" => "Kenya",
"kg" => "Kyrgyzstan",
"kh" => "Cambodia",
"ki" => "Kiribati",
"km" => "Comoros",
"kn" => "Saint Kitts and Nevis",
"kp" => "North Korea",
"kr" => "South Korea",
"kw" => "Kuwait",
"ky" => "Cayman Islands",
"kz" => "Kazakhstan",
"la" => "Laos",
"lb" => "Lebanon",
"lc" => "Saint Lucia",
"li" => "Lichtenstein",
"lk" => "Sri Lanka",
"lr" => "Liberia",
"ls" => "Lesotho",
"lt" => "Lithuania",
"lu" => "Luxembourg",
"lv" => "Latvia",
"ly" => "Libya",
"ma" => "Morocco",
"mc" => "Monaco",
"md" => "Moldova Republic",
"mg" => "Madagascar",
"mh" => "Marshall Islands",
"mk" => 'Macedonia, The Former Yugoslav Republic of',
"ml" => "Mali",
"mm" => "Myanmar",
"mn" => "Mongolia",
"mo" => "Macau",
"mp" => "Northern Mariana Islands",
"mq" => "Martinique",
"mr" => "Mauritania",
"ms" => "Montserrat",
"mt" => "Malta",
"mu" => "Mauritius",
"mv" => "Maldives",
"mw" => "Malawi",
"mx" => "Mexico",
"my" => "Malaysia",
"mz" => "Mozambique",
"na" => "Namibia",
"nc" => "New Caledonia",
"ne" => "Niger",
"nf" => "Norfolk Island",
"ng" => "Nigeria",
"ni" => "Nicaragua",
"nl" => "Netherlands",
"no" => "Norway",
"np" => "Nepal",
"nr" => "Nauru",
"nt" => "Neutral Zone",
"nu" => "Niue",
"nz" => "New Zealand",
"om" => "Oman",
"pa" => "Panama",
"pe" => "Peru",
"pf" => "French Polynesia",
"pg" => "Papua New Guinea",
"ph" => "Philippines",
"pk" => "Pakistan",
"pl" => "Poland",
"pm" => "St. Pierre and Miquelon",
"pn" => "Pitcairn",
"pr" => "Puerto Rico",
"pt" => "Portugal",
"pw" => "Palau",
"py" => "Paraguay",
"qa" => 'Qatar',
"re" => "Reunion",
"ro" => "Romania",
"ru" => "Russia",
"rw" => "Rwanda",
"sa" => "Saudi Arabia",
"sb" => "Solomon Islands",
"sc" => "Seychelles",
"sd" => "Sudan",
"se" => "Sweden",
"sg" => "Singapore",
"sh" => "St. Helena",
"si" => "Slovenia",
"sj" => "Svalbard and Jan Mayen Islands",
"sk" => 'Slovakia (Slovak Republic)',
"sl" => "Sierra Leone",
"sm" => "San Marino",
"sn" => "Senegal",
"so" => "Somalia",
"sr" => "Suriname",
"st" => "Sao Tome and Principe",
"sv" => "El Salvador",
"sy" => "Syria",
"sz" => "Swaziland",
"tc" => "Turks and Caicos Islands",
"td" => "Chad",
"tf" => "French Southern Territories",
"tg" => "Togo",
"th" => "Thailand",
"tj" => "Tajikistan",
"tk" => "Tokelau",
"tm" => "Turkmenistan",
"tn" => "Tunisia",
"to" => "Tonga",
"tp" => "East Timor",
"tr" => "Turkey",
"tt" => "Trinidad, Tobago",
"tv" => "Tuvalu",
"tw" => "Taiwan",
"tz" => "Tanzania",
"ua" => "Ukraine",
"ug" => "Uganda",
"uk" => "United Kingdom",
"um" => "United States Minor Islands",
"us" => "United States of America",
"uy" => "Uruguay",
"uz" => "Uzbekistan",
"va" => "Vatican City",
"vc" => "Saint Vincent, Grenadines",
"ve" => "Venezuela",
"vg" => "Virgin Islands (British)",
"vi" => "Virgin Islands (USA)",
"vn" => "Viet Nam",
"vu" => "Vanuatu",
"wf" => 'Wallis and Futuna Islands',
"ws" => "Samoa",
"ye" => 'Yemen',
"yt" => 'Mayotte',
"yu" => "Yugoslavia",
"za" => "South Africa",
"zm" => "Zambia",
"zr" => "Zaire",
"zw" => "Zimbabwe");
/**
* @return array
*/
public static function getCountries() {
return self::$countries;
}
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
return isset(self::$countries[$value]);
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
class Doctrine_Validator_Date {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
return checkdate($value);
}
}
?>

View File

@ -0,0 +1,46 @@
<?php
class Doctrine_Validator_Email {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
$parts = explode("@", $value);
if(count($parts) != 2)
return false;
if(strlen($parts[0]) < 1 || strlen($parts[0]) > 64)
return false;
if(strlen($parts[1]) < 1 || strlen($parts[1]) > 255)
return false;
$local_array = explode(".", $parts[0]);
for ($i = 0; $i < sizeof($local_array); $i++) {
if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $parts[$i])) {
return false;
}
}
if (!ereg("^\[?[0-9\.]+\]?$", $parts[1])) { // Check if domain is IP. If not, it should be valid domain name
$domain_array = explode(".", $parts[1]);
if (count($domain_array) < 2) {
return false; // Not enough parts to domain
}
for ($i = 0; $i < sizeof($domain_array); $i++) {
if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i])) {
return false;
}
}
}
if(function_exists("checkdnsrr")) {
if( ! checkdnsrr($parts[1], "MX"))
return false;
}
return true;
}
}
?>

View File

@ -0,0 +1,16 @@
<?php
class Doctrine_Validator_HtmlColor {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
if( ! preg_match("/^#{0,1}[0-9]{6}$/",$color)) {
return false;
}
return true;
}
}
?>

View File

@ -0,0 +1,21 @@
<?php
class Doctrine_Validator_IP {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
$e = explode(".",$request);
if(count($e) != 4) return false;
foreach($e as $k=>$v):
if(! is_numeric($v)) return false;
$v = (int) $v;
if($v < 0 || $v > 255) return false;
endforeach;
return true;
}
}
?>

View File

@ -0,0 +1,16 @@
<?php
class Doctrine_Validator_NoSpace {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
if(preg_match("/[\s\r\t\n]/", $value))
return false;
return true;
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
class Doctrine_Validator_Notnull {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
return ($value === null);
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
class Doctrine_Validator_Range {
/**
* @param integer $max
*/
public function setMin($min) {
$this->min = $min;
}
/**
* @param integer $max
*/
public function setMax($max) {
$this->max = $max;
}
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
if($var < $this->min)
return false;
if($var > $this->max)
return false;
return true;
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
class Doctrine_Validator_Regexp {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
return $value;
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
class Doctrine_Validator_Required {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
return ($value === null);
}
}
?>

View File

@ -0,0 +1,17 @@
<?php
class Doctrine_Validator_Unique {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
$table = $record->getTable();
$sql = "SELECT id FROM ".$table->getTableName()." WHERE ".$key." = ?";
$stmt = $table->getSession()->getDBH()->prepare($sql);
$stmt->execute(array($value));
return ( ! is_array($stmt->fetch()));
}
}
?>

View File

@ -0,0 +1,71 @@
<?php
class ValidatorUSState {
private static $states = array (
"AK" => true,
"AL" => true,
"AR" => true,
"AZ" => true,
"CA" => true,
"CO" => true,
"CT" => true,
"DC" => true,
"DE" => true,
"FL" => true,
"GA" => true,
"HI" => true,
"IA" => true,
"ID" => true,
"IL" => true,
"IN" => true,
"KS" => true,
"KY" => true,
"LA" => true,
"MA" => true,
"MD" => true,
"ME" => true,
"MI" => true,
"MN" => true,
"MO" => true,
"MS" => true,
"MT" => true,
"NC" => true,
"ND" => true,
"NE" => true,
"NH" => true,
"NJ" => true,
"NM" => true,
"NV" => true,
"NY" => true,
"OH" => true,
"OK" => true,
"OR" => true,
"PA" => true,
"PR" => true,
"RI" => true,
"SC" => true,
"SD" => true,
"TN" => true,
"TX" => true,
"UT" => true,
"VA" => true,
"VI" => true,
"VT" => true,
"WA" => true,
"WI" => true,
"WV" => true,
"WY" => true
);
public function getStates() {
return self::$states;
}
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value) {
return isset(self::$states[$value]);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
<?php
/**
* ADOdb Lite is a PHP class to encapsulate multiple database APIs and is compatible with
* a subset of the ADODB Command Syntax.
* Currently supports Frontbase, MaxDB, miniSQL, MSSQL, MSSQL Pro, MySQLi, MySQLt, MySQL, PostgresSQL,
* PostgresSQL64, PostgresSQL7, PostgresSQL8, SqLite, SqLite Pro, Sybase and Sybase ASE.
*
*/
if (!defined('_ADODB_LAYER'))
define('_ADODB_LAYER',1);
if (!defined('ADODB_DIR'))
define('ADODB_DIR', dirname(__FILE__));
$ADODB_vers = 'V1.15 ADOdb Lite 25 March 2006 (c) 2005, 2006 Mark Dickenson. All rights reserved. Released LGPL.';
define('ADODB_FETCH_DEFAULT',0);
define('ADODB_FETCH_NUM',1);
define('ADODB_FETCH_ASSOC',2);
define('ADODB_FETCH_BOTH',3);
GLOBAL $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT; // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
function NewDataDictionary(PDO $conn) {
$dbtype = $conn->getAttribute(PDO::ATTR_DRIVER_NAME);
include_once ADODB_DIR . '/adodb-datadict.inc.php';
include_once ADODB_DIR . '/drivers/datadict-' . $dbtype . '.inc.php';
$class = "ADODB2_$dbtype";
$dict = new $class();
$dict->connection = $conn;
$dict->upperName = strtoupper($dbtype);
//$dict->quote = $conn->nameQuote;
//$dict->debug_echo = $conn->debug_echo;
return $dict;
}
class ADOFieldObject {
var $name = '';
var $max_length=0;
var $type="";
}
?>

View File

@ -0,0 +1,95 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_access extends ADODB_DataDict {
var $databaseType = 'access';
var $seqField = false;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'TEXT';
case 'XL':
case 'X': return 'MEMO';
case 'C2': return 'TEXT'; // up to 32K
case 'X2': return 'MEMO';
case 'B': return 'BINARY';
case 'D': return 'DATETIME';
case 'T': return 'DATETIME';
case 'L': return 'BYTE';
case 'I': return 'INTEGER';
case 'I1': return 'BYTE';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'INTEGER';
case 'F': return 'DOUBLE';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
// return string must begin with space
function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
{
if ($fautoinc) {
$ftype = 'COUNTER';
return '';
}
if (substr($ftype,0,7) == 'DECIMAL') $ftype = 'DECIMAL';
$suffix = '';
if (strlen($fdefault)) {
//$suffix .= " DEFAULT $fdefault";
if ($this->debug) ADOConnection::outp("Warning: Access does not supported DEFAULT values (field $fname)");
}
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function CreateDatabase($dbname,$options=false)
{
return array();
}
function SetSchema($schema)
{
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
}
?>

View File

@ -0,0 +1,143 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_db2 extends ADODB_DataDict {
var $databaseType = 'db2';
var $seqField = false;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL': return 'CLOB';
case 'X': return 'VARCHAR(3600)';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR(3600)'; // up to 32000, but default page size too small
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'BIGINT';
case 'F': return 'DOUBLE';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
{
$suffix = '';
if ($fautoinc) return ' GENERATED ALWAYS AS IDENTITY'; # as identity start with
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
function ChangeTableSQL($tablename, $flds, $tableoptions = false)
{
/**
Allow basic table changes to DB2 databases
DB2 will fatally reject changes to non character columns
*/
$validTypes = array("CHAR","VARC");
$invalidTypes = array("BIGI","BLOB","CLOB","DATE", "DECI","DOUB", "INTE", "REAL","SMAL", "TIME");
// check table exists
$cols = &$this->MetaColumns($tablename);
if ( empty($cols)) {
return $this->CreateTableSQL($tablename, $flds, $tableoptions);
}
// already exists, alter table instead
list($lines,$pkey) = $this->_GenFields($flds);
$alter = 'ALTER TABLE ' . $this->TableName($tablename);
$sql = array();
foreach ( $lines as $id => $v ) {
if ( isset($cols[$id]) && is_object($cols[$id]) ) {
/**
If the first field of $v is the fieldname, and
the second is the field type/size, we assume its an
attempt to modify the column size, so check that it is allowed
$v can have an indeterminate number of blanks between the
fields, so account for that too
*/
$vargs = explode(' ' , $v);
// assume that $vargs[0] is the field name.
$i=0;
// Find the next non-blank value;
for ($i=1;$i<sizeof($vargs);$i++)
if ($vargs[$i] != '')
break;
// if $vargs[$i] is one of the following, we are trying to change the
// size of the field, if not allowed, simply ignore the request.
if (in_array(substr($vargs[$i],0,4),$invalidTypes))
continue;
// insert the appropriate DB2 syntax
if (in_array(substr($vargs[$i],0,4),$validTypes)) {
array_splice($vargs,$i,0,array('SET','DATA','TYPE'));
}
// Now Look for the NOT NULL statement as this is not allowed in
// the ALTER table statement. If it is in there, remove it
if (in_array('NOT',$vargs) && in_array('NULL',$vargs)) {
for ($i=1;$i<sizeof($vargs);$i++)
if ($vargs[$i] == 'NOT')
break;
array_splice($vargs,$i,2,'');
}
$v = implode(' ',$vargs);
$sql[] = $alter . $this->alterCol . ' ' . $v;
} else {
$sql[] = $alter . $this->addCol . ' ' . $v;
}
}
return $sql;
}
}
?>

View File

@ -0,0 +1,151 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
class ADODB2_firebird extends ADODB_DataDict {
var $databaseType = 'firebird';
var $seqField = false;
var $seqPrefix = 'gen_';
var $blobSize = 40000;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL': return 'VARCHAR(32000)';
case 'X': return 'VARCHAR(4000)';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR(4000)';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'INTEGER';
case 'F': return 'DOUBLE PRECISION';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function NameQuote($name = NULL)
{
if (!is_string($name)) {
return FALSE;
}
$name = trim($name);
if ( !is_object($this->connection) ) {
return $name;
}
$quote = $this->connection->nameQuote;
// if name is of the form `name`, quote it
if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
return $quote . $matches[1] . $quote;
}
// if name contains special characters, quote it
if ( !preg_match('/^[' . $this->nameRegex . ']+$/', $name) ) {
return $quote . $name . $quote;
}
return $quote . $name . $quote;
}
function CreateDatabase($dbname, $options=false)
{
$options = $this->_Options($options);
$sql = array();
$sql[] = "DECLARE EXTERNAL FUNCTION LOWER CSTRING(80) RETURNS CSTRING(80) FREE_IT ENTRY_POINT 'IB_UDF_lower' MODULE_NAME 'ib_udf'";
return $sql;
}
function _DropAutoIncrement($t)
{
if (strpos($t,'.') !== false) {
$tarr = explode('.',$t);
return 'DROP GENERATOR '.$tarr[0].'."gen_'.$tarr[1].'"';
}
return 'DROP GENERATOR "GEN_'.$t;
}
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fautoinc) $this->seqField = $fname;
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE or replace TRIGGER jaddress_insert
before insert on jaddress
for each row
begin
IF ( NEW."seqField" IS NULL OR NEW."seqField" = 0 ) THEN
NEW."seqField" = GEN_ID("GEN_tabname", 1);
end;
*/
function _Triggers($tabname,$tableoptions)
{
if (!$this->seqField) return array();
$tab1 = preg_replace( '/"/', '', $tabname );
if ($this->schema) {
$t = strpos($tab1,'.');
if ($t !== false) $tab = substr($tab1,$t+1);
else $tab = $tab1;
$seqField = $this->seqField;
$seqname = $this->schema.'.'.$this->seqPrefix.$tab;
$trigname = $this->schema.'.trig_'.$this->seqPrefix.$tab;
} else {
$seqField = $this->seqField;
$seqname = $this->seqPrefix.$tab1;
$trigname = 'trig_'.$seqname;
}
if (isset($tableoptions['REPLACE']))
{ $sql[] = "DROP GENERATOR \"$seqname\"";
$sql[] = "CREATE GENERATOR \"$seqname\"";
$sql[] = "ALTER TRIGGER \"$trigname\" BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
}
else
{ $sql[] = "CREATE GENERATOR \"$seqname\"";
$sql[] = "CREATE TRIGGER \"$trigname\" FOR $tabname BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
}
$this->seqField = false;
return $sql;
}
}
?>

View File

@ -0,0 +1,125 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_generic extends ADODB_DataDict {
var $databaseType = 'generic';
var $seqField = false;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'VARCHAR(250)';
case 'C2': return 'VARCHAR';
case 'X2': return 'VARCHAR(250)';
case 'B': return 'VARCHAR';
case 'D': return 'DATE';
case 'T': return 'DATE';
case 'L': return 'DECIMAL(1)';
case 'I': return 'DECIMAL(10)';
case 'I1': return 'DECIMAL(3)';
case 'I2': return 'DECIMAL(5)';
case 'I4': return 'DECIMAL(10)';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'DECIMAL(32,8)';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
}
/*
//db2
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'X': return 'VARCHAR';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'BIGINT';
case 'F': return 'DOUBLE';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
// ifx
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';// 255
case 'X': return 'TEXT';
case 'C2': return 'NVARCHAR';
case 'X2': return 'TEXT';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'DATETIME';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'FLOAT';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
*/
?>

View File

@ -0,0 +1,67 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_ibase extends ADODB_DataDict {
var $databaseType = 'ibase';
var $seqField = false;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'VARCHAR(4000)';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR(4000)';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'INTEGER';
case 'F': return 'DOUBLE PRECISION';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
}
?>

View File

@ -0,0 +1,80 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_informix extends ADODB_DataDict {
var $databaseType = 'informix';
var $seqField = false;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';// 255
case 'XL':
case 'X': return 'TEXT';
case 'C2': return 'NVARCHAR';
case 'X2': return 'TEXT';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'DATETIME';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'FLOAT';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
// return string must begin with space
function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
{
if ($fautoinc) {
$ftype = 'SERIAL';
return '';
}
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
}
?>

View File

@ -0,0 +1,282 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
/*
In ADOdb, named quotes for MS SQL Server use ". From the MSSQL Docs:
Note Delimiters are for identifiers only. Delimiters cannot be used for keywords,
whether or not they are marked as reserved in SQL Server.
Quoted identifiers are delimited by double quotation marks ("):
SELECT * FROM "Blanks in Table Name"
Bracketed identifiers are delimited by brackets ([ ]):
SELECT * FROM [Blanks In Table Name]
Quoted identifiers are valid only when the QUOTED_IDENTIFIER option is set to ON. By default,
the Microsoft OLE DB Provider for SQL Server and SQL Server ODBC driver set QUOTED_IDENTIFIER ON
when they connect.
In Transact-SQL, the option can be set at various levels using SET QUOTED_IDENTIFIER,
the quoted identifier option of sp_dboption, or the user options option of sp_configure.
When SET ANSI_DEFAULTS is ON, SET QUOTED_IDENTIFIER is enabled.
Syntax
SET QUOTED_IDENTIFIER { ON | OFF }
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_mssql extends ADODB_DataDict {
var $databaseType = 'mssql';
var $dropIndex = 'DROP INDEX %2$s.%1$s';
var $renameTable = "EXEC sp_rename '%s','%s'";
var $renameColumn = "EXEC sp_rename '%s.%s','%s'";
var $typeX = 'TEXT'; ## Alternatively, set it to VARCHAR(4000)
var $typeXL = 'TEXT';
//var $alterCol = ' ALTER COLUMN ';
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
$len = -1; // mysql max_length is not accurate
switch (strtoupper($t)) {
case 'R':
case 'INT':
case 'INTEGER': return 'I';
case 'BIT':
case 'TINYINT': return 'I1';
case 'SMALLINT': return 'I2';
case 'BIGINT': return 'I8';
case 'REAL':
case 'FLOAT': return 'F';
default: return parent::MetaType($t,$len,$fieldobj);
}
}
function ActualType($meta)
{
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
case 'XL': return (isset($this)) ? $this->typeXL : 'TEXT';
case 'X': return (isset($this)) ? $this->typeX : 'TEXT'; ## could be varchar(8000), but we want compat with oracle
case 'C2': return 'NVARCHAR';
case 'X2': return 'NTEXT';
case 'B': return 'IMAGE';
case 'D': return 'DATETIME';
case 'T': return 'DATETIME';
case 'L': return 'BIT';
case 'R':
case 'I': return 'INT';
case 'I1': return 'TINYINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INT';
case 'I8': return 'BIGINT';
case 'F': return 'REAL';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$f = array();
list($lines,$pkey) = $this->_GenFields($flds);
$s = "ALTER TABLE $tabname $this->addCol";
foreach($lines as $v) {
$f[] = "\n $v";
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
/*
function AlterColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
foreach($lines as $v) {
$sql[] = "ALTER TABLE $tabname $this->alterCol $v";
}
return $sql;
}
*/
function DropColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
if (!is_array($flds))
$flds = explode(',',$flds);
$f = array();
$s = 'ALTER TABLE ' . $tabname;
foreach($flds as $v) {
$f[] = "\n$this->dropCol ".$this->NameQuote($v);
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
{
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' IDENTITY(1,1)';
if ($fnotnull) $suffix .= ' NOT NULL';
else if ($suffix == '') $suffix .= ' NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE TABLE
[ database_name.[ owner ] . | owner. ] table_name
( { < column_definition >
| column_name AS computed_column_expression
| < table_constraint > ::= [ CONSTRAINT constraint_name ] }
| [ { PRIMARY KEY | UNIQUE } [ ,...n ]
)
[ ON { filegroup | DEFAULT } ]
[ TEXTIMAGE_ON { filegroup | DEFAULT } ]
< column_definition > ::= { column_name data_type }
[ COLLATE < collation_name > ]
[ [ DEFAULT constant_expression ]
| [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]
]
[ ROWGUIDCOL]
[ < column_constraint > ] [ ...n ]
< column_constraint > ::= [ CONSTRAINT constraint_name ]
{ [ NULL | NOT NULL ]
| [ { PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
[ WITH FILLFACTOR = fillfactor ]
[ON {filegroup | DEFAULT} ] ]
]
| [ [ FOREIGN KEY ]
REFERENCES ref_table [ ( ref_column ) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]
]
| CHECK [ NOT FOR REPLICATION ]
( logical_expression )
}
< table_constraint > ::= [ CONSTRAINT constraint_name ]
{ [ { PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
{ ( column [ ASC | DESC ] [ ,...n ] ) }
[ WITH FILLFACTOR = fillfactor ]
[ ON { filegroup | DEFAULT } ]
]
| FOREIGN KEY
[ ( column [ ,...n ] ) ]
REFERENCES ref_table [ ( ref_column [ ,...n ] ) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]
| CHECK [ NOT FOR REPLICATION ]
( search_conditions )
}
*/
/*
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON { table | view } ( column [ ASC | DESC ] [ ,...n ] )
[ WITH < index_option > [ ,...n] ]
[ ON filegroup ]
< index_option > :: =
{ PAD_INDEX |
FILLFACTOR = fillfactor |
IGNORE_DUP_KEY |
DROP_EXISTING |
STATISTICS_NORECOMPUTE |
SORT_IN_TEMPDB
}
*/
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
$clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : '';
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
function _GetSize($ftype, $ty, $fsize, $fprec)
{
switch ($ftype) {
case 'INT':
case 'SMALLINT':
case 'TINYINT':
case 'BIGINT':
return $ftype;
}
if ($ty == 'T') return $ftype;
return parent::_GetSize($ftype, $ty, $fsize, $fprec);
}
}
?>

View File

@ -0,0 +1,182 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_mysql extends ADODB_DataDict {
var $databaseType = 'mysql';
var $alterCol = ' MODIFY COLUMN';
var $alterTableAddIndex = true;
var $dropTable = 'DROP TABLE IF EXISTS %s'; // requires mysql 3.22 or later
var $dropIndex = 'DROP INDEX %s ON %s';
var $renameColumn = 'ALTER TABLE %s CHANGE COLUMN %s %s %s'; // needs column-definition!
var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
$is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->auto_increment;
$len = -1; // mysql max_length is not accurate
switch (strtoupper($t)) {
case 'STRING':
case 'CHAR':
case 'VARCHAR':
case 'TINYBLOB':
case 'TINYTEXT':
case 'ENUM':
case 'SET':
if ($len <= $this->blobSize) return 'C';
case 'TEXT':
case 'LONGTEXT':
case 'MEDIUMTEXT':
return 'X';
// php_mysql extension always returns 'blob' even if 'text'
// so we have to check whether binary...
case 'IMAGE':
case 'LONGBLOB':
case 'BLOB':
case 'MEDIUMBLOB':
return !empty($fieldobj->binary) ? 'B' : 'X';
case 'YEAR':
case 'DATE': return 'D';
case 'TIME':
case 'DATETIME':
case 'TIMESTAMP': return 'T';
case 'FLOAT':
case 'DOUBLE':
return 'F';
case 'INT':
case 'INTEGER': return $is_serial ? 'R' : 'I';
case 'TINYINT': return $is_serial ? 'R' : 'I1';
case 'SMALLINT': return $is_serial ? 'R' : 'I2';
case 'MEDIUMINT': return $is_serial ? 'R' : 'I4';
case 'BIGINT': return $is_serial ? 'R' : 'I8';
default: return 'N';
}
}
function ActualType($meta)
{
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
case 'XL':return 'LONGTEXT';
case 'X': return 'TEXT';
case 'C2': return 'VARCHAR';
case 'X2': return 'LONGTEXT';
case 'B': return 'LONGBLOB';
case 'D': return 'DATE';
case 'T': return 'DATETIME';
case 'L': return 'TINYINT';
case 'R':
case 'I4':
case 'I': return 'INTEGER';
case 'I1': return 'TINYINT';
case 'I2': return 'SMALLINT';
case 'I8': return 'BIGINT';
case 'F': return 'DOUBLE';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($funsigned) $suffix .= ' UNSIGNED';
if ($fnotnull) $suffix .= ' NOT NULL';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' AUTO_INCREMENT';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
[table_options] [select_statement]
create_definition:
col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
[PRIMARY KEY] [reference_definition]
or PRIMARY KEY (index_col_name,...)
or KEY [index_name] (index_col_name,...)
or INDEX [index_name] (index_col_name,...)
or UNIQUE [INDEX] [index_name] (index_col_name,...)
or FULLTEXT [INDEX] [index_name] (index_col_name,...)
or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
[reference_definition]
or CHECK (expr)
*/
/*
CREATE [UNIQUE|FULLTEXT] INDEX index_name
ON tbl_name (col_name[(length)],... )
*/
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
if ($this->alterTableAddIndex) $sql[] = "ALTER TABLE $tabname DROP INDEX $idxname";
else $sql[] = sprintf($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
if (isset($idxoptions['FULLTEXT'])) {
$unique = ' FULLTEXT';
} elseif (isset($idxoptions['UNIQUE'])) {
$unique = ' UNIQUE';
} else {
$unique = '';
}
if ( is_array($flds) ) $flds = implode(', ',$flds);
if ($this->alterTableAddIndex) $s = "ALTER TABLE $tabname ADD $unique INDEX $idxname ";
else $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname;
$s .= ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
}
?>

View File

@ -0,0 +1,282 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_oci8 extends ADODB_DataDict {
var $databaseType = 'oci8';
var $seqField = false;
var $seqPrefix = 'SEQ_';
var $dropTable = "DROP TABLE %s CASCADE CONSTRAINTS";
var $trigPrefix = 'TRIG_';
var $alterCol = ' MODIFY ';
var $typeX = 'VARCHAR(4000)';
var $typeXL = 'CLOB';
function MetaType($t,$len=-1)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
switch (strtoupper($t)) {
case 'VARCHAR':
case 'VARCHAR2':
case 'CHAR':
case 'VARBINARY':
case 'BINARY':
if (isset($this) && $len <= $this->blobSize) return 'C';
return 'X';
case 'NCHAR':
case 'NVARCHAR2':
case 'NVARCHAR':
if (isset($this) && $len <= $this->blobSize) return 'C2';
return 'X2';
case 'NCLOB':
case 'CLOB':
return 'XL';
case 'LONG RAW':
case 'LONG VARBINARY':
case 'BLOB':
return 'B';
case 'DATE':
return 'T';
case 'INT':
case 'SMALLINT':
case 'INTEGER':
return 'I';
default:
return 'N';
}
}
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'X': return $this->typeX;
case 'XL': return $this->typeXL;
case 'C2': return 'NVARCHAR';
case 'X2': return 'NVARCHAR(2000)';
case 'B': return 'BLOB';
case 'D':
case 'T': return 'DATE';
case 'L': return 'DECIMAL(1)';
case 'I1': return 'DECIMAL(3)';
case 'I2': return 'DECIMAL(5)';
case 'I':
case 'I4': return 'DECIMAL(10)';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'DECIMAL';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function CreateDatabase($dbname, $options=false)
{
$options = $this->_Options($options);
$password = isset($options['PASSWORD']) ? $options['PASSWORD'] : 'tiger';
$tablespace = isset($options["TABLESPACE"]) ? " DEFAULT TABLESPACE ".$options["TABLESPACE"] : '';
$sql[] = "CREATE USER ".$dbname." IDENTIFIED BY ".$password.$tablespace;
$sql[] = "GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO $dbname";
return $sql;
}
function AddColumnSQL($tabname, $flds)
{
$f = array();
list($lines,$pkey) = $this->_GenFields($flds);
$s = "ALTER TABLE $tabname ADD (";
foreach($lines as $v) {
$f[] = "\n $v";
}
$s .= implode(', ',$f).')';
$sql[] = $s;
return $sql;
}
function AlterColumnSQL($tabname, $flds)
{
$f = array();
list($lines,$pkey) = $this->_GenFields($flds);
$s = "ALTER TABLE $tabname MODIFY(";
foreach($lines as $v) {
$f[] = "\n $v";
}
$s .= implode(', ',$f).')';
$sql[] = $s;
return $sql;
}
function DropColumnSQL($tabname, $flds)
{
if (!is_array($flds)) $flds = explode(',',$flds);
foreach ($flds as $k => $v) $flds[$k] = $this->NameQuote($v);
$sql = array();
$s = "ALTER TABLE $tabname DROP(";
$s .= implode(', ',$flds).') CASCADE CONSTRAINTS';
$sql[] = $s;
return $sql;
}
function _DropAutoIncrement($t)
{
if (strpos($t,'.') !== false) {
$tarr = explode('.',$t);
return "drop sequence ".$tarr[0].".seq_".$tarr[1];
}
return "drop sequence seq_".$t;
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($fdefault == "''" && $fnotnull) {// this is null in oracle
$fnotnull = false;
if ($this->debug) ADOConnection::outp("NOT NULL and DEFAULT='' illegal in Oracle");
}
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fautoinc) $this->seqField = $fname;
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE or replace TRIGGER jaddress_insert
before insert on jaddress
for each row
begin
select seqaddress.nextval into :new.A_ID from dual;
end;
*/
function _Triggers($tabname,$tableoptions)
{
if (!$this->seqField) return array();
if ($this->schema) {
$t = strpos($tabname,'.');
if ($t !== false) $tab = substr($tabname,$t+1);
else $tab = $tabname;
$seqname = $this->schema.'.'.$this->seqPrefix.$tab;
$trigname = $this->schema.'.'.$this->trigPrefix.$this->seqPrefix.$tab;
} else {
$seqname = $this->seqPrefix.$tabname;
$trigname = $this->trigPrefix.$seqname;
}
if (isset($tableoptions['REPLACE'])) $sql[] = "DROP SEQUENCE $seqname";
$seqCache = '';
if (isset($tableoptions['SEQUENCE_CACHE'])){$seqCache = $tableoptions['SEQUENCE_CACHE'];}
$seqIncr = '';
if (isset($tableoptions['SEQUENCE_INCREMENT'])){$seqIncr = ' INCREMENT BY '.$tableoptions['SEQUENCE_INCREMENT'];}
$seqStart = '';
if (isset($tableoptions['SEQUENCE_START'])){$seqIncr = ' START WITH '.$tableoptions['SEQUENCE_START'];}
$sql[] = "CREATE SEQUENCE $seqname $seqStart $seqIncr $seqCache";
$sql[] = "CREATE OR REPLACE TRIGGER $trigname BEFORE insert ON $tabname FOR EACH ROW WHEN (NEW.$this->seqField IS NULL OR NEW.$this->seqField = 0) BEGIN select $seqname.nextval into :new.$this->seqField from dual; END;";
$this->seqField = false;
return $sql;
}
/*
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
[table_options] [select_statement]
create_definition:
col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
[PRIMARY KEY] [reference_definition]
or PRIMARY KEY (index_col_name,...)
or KEY [index_name] (index_col_name,...)
or INDEX [index_name] (index_col_name,...)
or UNIQUE [INDEX] [index_name] (index_col_name,...)
or FULLTEXT [INDEX] [index_name] (index_col_name,...)
or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
[reference_definition]
or CHECK (expr)
*/
function _IndexSQL($idxname, $tabname, $flds,$idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
if (isset($idxoptions['BITMAP'])) {
$unique = ' BITMAP';
} elseif (isset($idxoptions['UNIQUE'])) {
$unique = ' UNIQUE';
} else {
$unique = '';
}
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
if (isset($idxoptions['oci8']))
$s .= $idxoptions['oci8'];
$sql[] = $s;
return $sql;
}
function GetCommentSQL($table,$col)
{
$table = $this->connection->qstr($table);
$col = $this->connection->qstr($col);
return "select comments from USER_COL_COMMENTS where TABLE_NAME=$table and COLUMN_NAME=$col";
}
function SetCommentSQL($table,$col,$cmt)
{
$cmt = $this->connection->qstr($cmt);
return "COMMENT ON COLUMN $table.$col IS $cmt";
}
}
?>

View File

@ -0,0 +1,371 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_pgsql extends ADODB_DataDict {
var $databaseType = 'postgres';
var $seqField = false;
var $seqPrefix = 'SEQ_';
var $addCol = ' ADD COLUMN';
var $quote = '"';
var $renameTable = 'ALTER TABLE %s RENAME TO %s'; // at least since 7.1
var $dropTable = 'DROP TABLE %s CASCADE';
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
$is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->unique &&
$fieldobj->has_default && substr($fieldobj->default_value,0,8) == 'nextval(';
switch (strtoupper($t)) {
case 'INTERVAL':
case 'CHAR':
case 'CHARACTER':
case 'VARCHAR':
case 'NAME':
case 'BPCHAR':
if ($len <= $this->blobSize) return 'C';
case 'TEXT':
return 'X';
case 'IMAGE': // user defined type
case 'BLOB': // user defined type
case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
case 'VARBIT':
case 'BYTEA':
return 'B';
case 'BOOL':
case 'BOOLEAN':
return 'L';
case 'DATE':
return 'D';
case 'TIME':
case 'DATETIME':
case 'TIMESTAMP':
case 'TIMESTAMPTZ':
return 'T';
case 'INTEGER': return !$is_serial ? 'I' : 'R';
case 'SMALLINT':
case 'INT2': return !$is_serial ? 'I2' : 'R';
case 'INT4': return !$is_serial ? 'I4' : 'R';
case 'BIGINT':
case 'INT8': return !$is_serial ? 'I8' : 'R';
case 'OID':
case 'SERIAL':
return 'R';
case 'FLOAT4':
case 'FLOAT8':
case 'DOUBLE PRECISION':
case 'REAL':
return 'F';
default:
return 'N';
}
}
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'TEXT';
case 'C2': return 'VARCHAR';
case 'X2': return 'TEXT';
case 'B': return 'BYTEA';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'BOOLEAN';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'INT2';
case 'I4': return 'INT4';
case 'I8': return 'INT8';
case 'F': return 'FLOAT8';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
/**
* Adding a new Column
*
* reimplementation of the default function as postgres does NOT allow to set the default in the same statement
*
* @param string $tabname table-name
* @param string $flds column-names and types for the changed columns
* @return array with SQL strings
*/
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
$alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
foreach($lines as $v) {
if (($not_null = preg_match('/NOT NULL/i',$v))) {
$v = preg_replace('/NOT NULL/i','',$v);
}
if (preg_match('/^([^ ]+) .*DEFAULT ([^ ]+)/',$v,$matches)) {
list(,$colname,$default) = $matches;
$sql[] = $alter . str_replace('DEFAULT '.$default,'',$v);
$sql[] = 'UPDATE '.$tabname.' SET '.$colname.'='.$default;
$sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET DEFAULT ' . $default;
} else {
$sql[] = $alter . $v;
}
if ($not_null) {
list($colname) = explode(' ',$v);
$sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL';
}
}
return $sql;
}
/**
* Change the definition of one column
*
* Postgres can't do that on it's own, you need to supply the complete defintion of the new table,
* to allow, recreating the table and copying the content over to the new table
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds complete defintion of the new table, eg. for postgres, default ''
* @param array/ $tableoptions options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
if (!$tableflds) {
if ($this->debug) ADOConnection::outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL");
return array();
}
return $this->_recreate_copy_table($tabname,False,$tableflds,$tableoptions);
}
/**
* Drop one column
*
* Postgres < 7.3 can't do that on it's own, you need to supply the complete defintion of the new table,
* to allow, recreating the table and copying the content over to the new table
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds complete defintion of the new table, eg. for postgres, default ''
* @param array/ $tableoptions options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$has_drop_column = 7.3 <= (float) @$this->serverInfo['version'];
if (!$has_drop_column && !$tableflds) {
if ($this->debug) ADOConnection::outp("DropColumnSQL needs complete table-definiton for PostgreSQL < 7.3");
return array();
}
if ($has_drop_column) {
return ADODB_DataDict::DropColumnSQL($tabname, $flds);
}
return $this->_recreate_copy_table($tabname,$flds,$tableflds,$tableoptions);
}
/**
* Save the content into a temp. table, drop and recreate the original table and copy the content back in
*
* We also take care to set the values of the sequenz and recreate the indexes.
* All this is done in a transaction, to not loose the content of the table, if something went wrong!
* @internal
* @param string $tabname table-name
* @param string $dropflds column-names to drop
* @param string $tableflds complete defintion of the new table, eg. for postgres
* @param array/string $tableoptions options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function _recreate_copy_table($tabname,$dropflds,$tableflds,$tableoptions='')
{
if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds);
$copyflds = array();
foreach($this->MetaColumns($tabname) as $fld) {
if (!$dropflds || !in_array($fld->name,$dropflds)) {
// we need to explicit convert varchar to a number to be able to do an AlterColumn of a char column to a nummeric one
if (preg_match('/'.$fld->name.' (I|I2|I4|I8|N|F)/i',$tableflds,$matches) &&
in_array($fld->type,array('varchar','char','text','bytea'))) {
$copyflds[] = "to_number($fld->name,'S9999999999999D99')";
} else {
$copyflds[] = $fld->name;
}
// identify the sequence name and the fld its on
if ($fld->primary_key && $fld->has_default &&
preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) {
$seq_name = $matches[1];
$seq_fld = $fld->name;
}
}
}
$copyflds = implode(', ',$copyflds);
$tempname = $tabname.'_tmp';
$aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table
$aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname";
$aSql = array_merge($aSql,$this->DropTableSQL($tabname));
$aSql = array_merge($aSql,$this->CreateTableSQL($tabname,$tableflds,$tableoptions));
$aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname";
if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again
$seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence
$aSql[] = "SELECT setval('$seq_name',MAX($seq_fld)) FROM $tabname";
}
$aSql[] = "DROP TABLE $tempname";
// recreate the indexes, if they not contain one of the droped columns
foreach($this->MetaIndexes($tabname) as $idx_name => $idx_data)
{
if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) {
$aSql = array_merge($aSql,$this->CreateIndexSQL($idx_name,$tabname,$idx_data['columns'],
$idx_data['unique'] ? array('UNIQUE') : False));
}
}
$aSql[] = 'COMMIT';
return $aSql;
}
function DropTableSQL($tabname)
{
$sql = ADODB_DataDict::DropTableSQL($tabname);
$drop_seq = $this->_DropAutoIncrement($tabname);
if ($drop_seq) $sql[] = $drop_seq;
return $sql;
}
// return string must begin with space
function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
{
if ($fautoinc) {
$ftype = 'SERIAL';
return '';
}
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
// search for a sequece for the given table (asumes the seqence-name contains the table-name!)
// if yes return sql to drop it
// this is still necessary if postgres < 7.3 or the SERIAL was created on an earlier version!!!
function _DropAutoIncrement($tabname)
{
$tabname = $this->connection->quote('%'.$tabname.'%');
$seq = $this->connection->GetOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'");
// check if a tables depends on the sequenz and it therefor cant and dont need to be droped separatly
if (!$seq || $this->connection->GetOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) {
return False;
}
return "DROP SEQUENCE ".$seq;
}
/*
CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name (
{ column_name data_type [ DEFAULT default_expr ] [ column_constraint [, ... ] ]
| table_constraint } [, ... ]
)
[ INHERITS ( parent_table [, ... ] ) ]
[ WITH OIDS | WITHOUT OIDS ]
where column_constraint is:
[ CONSTRAINT constraint_name ]
{ NOT NULL | NULL | UNIQUE | PRIMARY KEY |
CHECK (expression) |
REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL ]
[ ON DELETE action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
and table_constraint is:
[ CONSTRAINT constraint_name ]
{ UNIQUE ( column_name [, ... ] ) |
PRIMARY KEY ( column_name [, ... ] ) |
CHECK ( expression ) |
FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL ] [ ON DELETE action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
*/
/*
CREATE [ UNIQUE ] INDEX index_name ON table
[ USING acc_method ] ( column [ ops_name ] [, ...] )
[ WHERE predicate ]
CREATE [ UNIQUE ] INDEX index_name ON table
[ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] )
[ WHERE predicate ]
*/
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
$s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
if (isset($idxoptions['HASH']))
$s .= 'USING HASH ';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s .= '(' . $flds . ')';
$sql[] = $s;
return $sql;
}
function _GetSize($ftype, $ty, $fsize, $fprec)
{
if (strlen($fsize) && $ty != 'X' && $ty != 'B' && $ty != 'I' && strpos($ftype,'(') === false) {
$ftype .= "(".$fsize;
if (strlen($fprec)) $ftype .= ",".$fprec;
$ftype .= ')';
}
return $ftype;
}
}
?>

View File

@ -0,0 +1,121 @@
<?php
/**
V4.50 6 July 2004 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
Modified from datadict-generic.inc.php for sapdb by RalfBecker-AT-outdoor-training.de
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_sapdb extends ADODB_DataDict {
var $databaseType = 'sapdb';
var $seqField = false;
var $renameColumn = 'RENAME COLUMN %s.%s TO %s';
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'LONG';
case 'C2': return 'VARCHAR UNICODE';
case 'X2': return 'LONG UNICODE';
case 'B': return 'LONG';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'BOOLEAN';
case 'I': return 'INTEGER';
case 'I1': return 'FIXED(3)';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'FIXED(20)';
case 'F': return 'FLOAT(38)';
case 'N': return 'FIXED';
default:
return $meta;
}
}
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
static $maxdb_type2adodb = array(
'VARCHAR' => 'C',
'CHARACTER' => 'C',
'LONG' => 'X', // no way to differ between 'X' and 'B' :-(
'DATE' => 'D',
'TIMESTAMP' => 'T',
'BOOLEAN' => 'L',
'INTEGER' => 'I4',
'SMALLINT' => 'I2',
'FLOAT' => 'F',
'FIXED' => 'N',
);
$type = isset($maxdb_type2adodb[$t]) ? $maxdb_type2adodb[$t] : 'C';
// convert integer-types simulated with fixed back to integer
if ($t == 'FIXED' && !$fieldobj->scale && ($len == 20 || $len == 3)) {
$type = $len == 20 ? 'I8' : 'I1';
}
if ($fieldobj->auto_increment) $type = 'R';
return $type;
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($funsigned) $suffix .= ' UNSIGNED';
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fautoinc) $suffix .= ' DEFAULT SERIAL';
elseif (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
return array( 'ALTER TABLE ' . $tabname . ' ADD (' . implode(', ',$lines) . ')' );
}
function AlterColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
return array( 'ALTER TABLE ' . $tabname . ' MODIFY (' . implode(', ',$lines) . ')' );
}
function DropColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
if (!is_array($flds)) $flds = explode(',',$flds);
foreach($flds as $k => $v) {
$flds[$k] = $this->NameQuote($v);
}
return array( 'ALTER TABLE ' . $tabname . ' DROP (' . implode(', ',$flds) . ')' );
}
}
?>

View File

@ -0,0 +1,228 @@
<?php
/**
V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_sybase extends ADODB_DataDict {
var $databaseType = 'sybase';
var $dropIndex = 'DROP INDEX %2$s.%1$s';
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
$len = -1; // mysql max_length is not accurate
switch (strtoupper($t)) {
case 'INT':
case 'INTEGER': return 'I';
case 'BIT':
case 'TINYINT': return 'I1';
case 'SMALLINT': return 'I2';
case 'BIGINT': return 'I8';
case 'REAL':
case 'FLOAT': return 'F';
default: return parent::MetaType($t,$len,$fieldobj);
}
}
function ActualType($meta)
{
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'TEXT';
case 'C2': return 'NVARCHAR';
case 'X2': return 'NTEXT';
case 'B': return 'IMAGE';
case 'D': return 'DATETIME';
case 'T': return 'DATETIME';
case 'L': return 'BIT';
case 'I': return 'INT';
case 'I1': return 'TINYINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INT';
case 'I8': return 'BIGINT';
case 'F': return 'REAL';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$f = array();
list($lines,$pkey) = $this->_GenFields($flds);
$s = "ALTER TABLE $tabname $this->addCol";
foreach($lines as $v) {
$f[] = "\n $v";
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
function AlterColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
foreach($lines as $v) {
$sql[] = "ALTER TABLE $tabname $this->alterCol $v";
}
return $sql;
}
function DropColumnSQL($tabname, $flds)
{
$tabname = $this->TableName($tabname);
if (!is_array($flds)) $flds = explode(',',$flds);
$f = array();
$s = "ALTER TABLE $tabname";
foreach($flds as $v) {
$f[] = "\n$this->dropCol ".$this->NameQuote($v);
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
{
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' DEFAULT AUTOINCREMENT';
if ($fnotnull) $suffix .= ' NOT NULL';
else if ($suffix == '') $suffix .= ' NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE TABLE
[ database_name.[ owner ] . | owner. ] table_name
( { < column_definition >
| column_name AS computed_column_expression
| < table_constraint > ::= [ CONSTRAINT constraint_name ] }
| [ { PRIMARY KEY | UNIQUE } [ ,...n ]
)
[ ON { filegroup | DEFAULT } ]
[ TEXTIMAGE_ON { filegroup | DEFAULT } ]
< column_definition > ::= { column_name data_type }
[ COLLATE < collation_name > ]
[ [ DEFAULT constant_expression ]
| [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]
]
[ ROWGUIDCOL]
[ < column_constraint > ] [ ...n ]
< column_constraint > ::= [ CONSTRAINT constraint_name ]
{ [ NULL | NOT NULL ]
| [ { PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
[ WITH FILLFACTOR = fillfactor ]
[ON {filegroup | DEFAULT} ] ]
]
| [ [ FOREIGN KEY ]
REFERENCES ref_table [ ( ref_column ) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]
]
| CHECK [ NOT FOR REPLICATION ]
( logical_expression )
}
< table_constraint > ::= [ CONSTRAINT constraint_name ]
{ [ { PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
{ ( column [ ASC | DESC ] [ ,...n ] ) }
[ WITH FILLFACTOR = fillfactor ]
[ ON { filegroup | DEFAULT } ]
]
| FOREIGN KEY
[ ( column [ ,...n ] ) ]
REFERENCES ref_table [ ( ref_column [ ,...n ] ) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]
| CHECK [ NOT FOR REPLICATION ]
( search_conditions )
}
*/
/*
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON { table | view } ( column [ ASC | DESC ] [ ,...n ] )
[ WITH < index_option > [ ,...n] ]
[ ON filegroup ]
< index_option > :: =
{ PAD_INDEX |
FILLFACTOR = fillfactor |
IGNORE_DUP_KEY |
DROP_EXISTING |
STATISTICS_NORECOMPUTE |
SORT_IN_TEMPDB
}
*/
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
$clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : '';
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
}
?>

View File

@ -0,0 +1,89 @@
<?php
/**
V4.65 22 July 2005 (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
Modified 28 August, 2005 for use with ADOdb Lite by Mark Dickenson
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_odbc extends ADODB_DataDict {
var $dbtype = 'odbc';
var $seqField = false;
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'VARCHAR(250)';
case 'C2': return 'VARCHAR';
case 'X2': return 'VARCHAR(250)';
case 'B': return 'VARCHAR';
case 'D': return 'DATE';
case 'T': return 'DATE';
case 'L': return 'DECIMAL(1)';
case 'I': return 'DECIMAL(10)';
case 'I1': return 'DECIMAL(3)';
case 'I2': return 'DECIMAL(5)';
case 'I4': return 'DECIMAL(10)';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'DECIMAL(32,8)';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) $this->outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) $this->outp("DropColumnSQL not supported");
return array();
}
// function MetaType($t,$len=-1,$fieldobj=false)
// {
// }
// function &MetaTables($ttype=false,$showSchema=false,$mask=false)
// {
// global $ADODB_FETCH_MODE;
// }
// function &MetaColumns($table,$upper=true)
// {
// global $ADODB_FETCH_MODE;
// }
// function MetaPrimaryKeys($table, $owner=false)
// {
// }
// function &MetaIndexes($table, $primary = false, $owner = false)
// {
// }
}
?>

View File

@ -0,0 +1,90 @@
<?php
/**
V4.65 22 July 2005 (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved.
Released under both BSD license and Lesser GPL library license.
Whenever there is any discrepancy between the two licenses,
the BSD license will take precedence.
Set tabs to 4 for best viewing.
Modified 28 August, 2005 for use with ADOdb Lite by Mark Dickenson
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
class ADODB2_sqlite extends ADODB_DataDict {
var $dbtype = 'sqlite';
var $seqField = false;
var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'VARCHAR(250)';
case 'C2': return 'VARCHAR';
case 'X2': return 'VARCHAR(250)';
case 'B': return 'VARCHAR';
case 'D': return 'DATE';
case 'T': return 'DATE';
case 'L': return 'DECIMAL(1)';
case 'I': return 'DECIMAL(10)';
case 'I1': return 'DECIMAL(3)';
case 'I2': return 'DECIMAL(5)';
case 'I4': return 'DECIMAL(10)';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'DECIMAL(32,8)';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds)
{
if ($this->debug) $this->outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds)
{
if ($this->debug) $this->outp("DropColumnSQL not supported");
return array();
}
// function MetaType($t,$len=-1,$fieldobj=false)
// {
// }
// function &MetaTables($ttype=false,$showSchema=false,$mask=false)
// {
// global $ADODB_FETCH_MODE;
// }
// function &MetaColumns($table,$upper=true)
// {
// global $ADODB_FETCH_MODE;
// }
// function MetaPrimaryKeys($table, $owner=false)
// {
// }
// function &MetaIndexes($table, $primary = false, $owner = false)
// {
// }
}
?>

View File

@ -0,0 +1,39 @@
<?php
class Doctrine_AccessTestCase extends Doctrine_UnitTestCase {
public function testOffsetMethods() {
$this->assertEqual($this->new["name"],null);
$this->new["name"] = "Jack";
$this->assertEqual($this->new["name"],"Jack");
$this->assertEqual($this->old["name"],"zYne");
$this->old["name"] = "Jack";
$this->assertEqual($this->old["name"],"Jack");
}
public function testOverload() {
$this->assertEqual($this->new->name,null);
$this->new->name = "Jack";
$this->assertEqual($this->new->name,"Jack");
$this->assertEqual($this->old->name,"zYne");
$this->old->name = "Jack";
$this->assertEqual($this->old->name,"Jack");
}
public function testSet() {
$this->assertEqual($this->new->get("name"),null);
$this->new->set("name","Jack");
$this->assertEqual($this->new->get("name"),"Jack");
$this->assertEqual($this->old->get("name"),"zYne");
$this->old->set("name","Jack");
$this->assertEqual($this->old->get("name"),"Jack");
$this->assertEqual($this->old->getID(),4);
}
}
?>

View File

@ -0,0 +1,15 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_BatchIteratorTestCase extends Doctrine_UnitTestCase {
public function testIterator() {
$graph = new Doctrine_DQL_Parser($this->session);
$entities = $graph->query("FROM Entity");
$i = 0;
foreach($entities as $entity) {
$this->assertTrue(is_string($entity->name));
$i++;
}
$this->assertTrue($i == $entities->count());
}
}
?>

View File

@ -0,0 +1,56 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_Cache_FileTestCase extends Doctrine_UnitTestCase {
public function testStore() {
$this->cache->store($this->old);
$this->assertTrue($this->cache->exists(4));
$record = $this->cache->fetch(4);
$this->assertTrue($record instanceof Doctrine_Record);
$this->assertTrue($record->getID() == $this->old->getID());
$this->assertTrue($this->cache->getTable() == $this->objTable);
}
public function testGetFetched() {
$this->assertTrue(is_array($this->cache->getFetched()));
}
public function testGetFileName() {
$this->assertEqual($this->manager->getRoot().DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."entity".DIRECTORY_SEPARATOR."4.cache", $this->cache->getFileName(4));
}
public function testGetStats() {
$this->assertTrue(gettype($this->cache->getStats()) == "array");
}
public function testDestructor() {
$this->objTable->setAttribute(Doctrine::ATTR_CACHE_TTL,1);
$this->objTable->setAttribute(Doctrine::ATTR_CACHE_SIZE,5);
$this->cache->__destruct();
$this->assertTrue($this->cache->count() == 5);
$this->objTable->setAttribute(Doctrine::ATTR_CACHE_TTL,1);
$this->objTable->setAttribute(Doctrine::ATTR_CACHE_SIZE,1);
$this->cache->__destruct();
$this->assertTrue($this->cache->count() == 1);
}
public function testDeleteMultiple() {
$this->objTable->find(5);
$this->objTable->find(6);
$deleted = $this->cache->deleteMultiple(array(5,6));
$this->assertTrue($deleted == 2);
}
public function testDeleteAll() {
$this->cache->deleteAll();
$this->assertTrue($this->cache->count() == 0);
}
public function testExists() {
$this->assertFalse($this->cache->exists(313213123));
$this->assertTrue($this->cache->exists(4));
}
public function testGetFactory() {
$this->assertTrue($this->cache->getTable() == $this->objTable);
}
}
?>

View File

@ -0,0 +1,7 @@
<?php
class Doctrine_CollectionTestCase extends Doctrine_UnitTestCase {
public function testAdd() {
}
}
?>

View File

@ -0,0 +1,3 @@
<?php
?>

View File

@ -0,0 +1,74 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_ConfigurableTestCase extends Doctrine_UnitTestCase {
public function testSetAttribute() {
$this->manager->setAttribute(Doctrine::ATTR_CACHE_TTL,100);
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_CACHE_TTL),100);
$this->manager->setAttribute(Doctrine::ATTR_CACHE_SIZE,1);
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_CACHE_SIZE),1);
$this->manager->setAttribute(Doctrine::ATTR_CACHE_DIR,"%ROOT%".DIRECTORY_SEPARATOR."cache");
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_CACHE_DIR),$this->manager->getRoot().DIRECTORY_SEPARATOR."cache");
$this->manager->setAttribute(Doctrine::ATTR_FETCHMODE,Doctrine::FETCH_LAZY);
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_FETCHMODE),Doctrine::FETCH_LAZY);
$this->manager->setAttribute(Doctrine::ATTR_BATCH_SIZE, 5);
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_BATCH_SIZE),5);
$this->manager->setAttribute(Doctrine::ATTR_LISTENER, new Doctrine_Debugger());
$this->assertTrue($this->manager->getAttribute(Doctrine::ATTR_LISTENER) instanceof Doctrine_Debugger);
$this->manager->setAttribute(Doctrine::ATTR_PK_COLUMNS, array("id"));
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_PK_COLUMNS), array("id"));
$this->manager->setAttribute(Doctrine::ATTR_PK_TYPE, Doctrine::INCREMENT_KEY);
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_PK_TYPE), Doctrine::INCREMENT_KEY);
$this->manager->setAttribute(Doctrine::ATTR_LOCKMODE, Doctrine::LOCK_PESSIMISTIC);
$this->assertEqual($this->manager->getAttribute(Doctrine::ATTR_LOCKMODE), Doctrine::LOCK_PESSIMISTIC);
// test invalid arguments
try {
$this->manager->setAttribute(Doctrine::ATTR_CACHE_TTL,-12);
} catch(Exception $e) {
$this->assertTrue($e instanceof Exception);
}
try {
$this->manager->setAttribute(Doctrine::ATTR_CACHE_SIZE,-12);
} catch(Exception $e) {
$this->assertTrue($e instanceof Exception);
}
try {
$this->manager->setAttribute(Doctrine::ATTR_BATCH_SIZE,-12);
} catch(Exception $e) {
$this->assertTrue($e instanceof Exception);
}
try {
$this->session->beginTransaction();
$this->manager->setAttribute(Doctrine::ATTR_LOCKMODE, Doctrine::LOCK_OPTIMISTIC);
} catch(Exception $e) {
$this->assertTrue($e instanceof Exception);
$this->session->commit();
}
try {
$this->session->beginTransaction();
$this->session->setAttribute(Doctrine::ATTR_LOCKMODE, Doctrine::LOCK_PESSIMISTIC);
} catch(Exception $e) {
$this->assertTrue($e instanceof Exception);
$this->session->commit();
}
try {
$this->manager->setAttribute(Doctrine::ATTR_PK_TYPE,-12);
} catch(Exception $e) {
$this->assertTrue($e instanceof Exception);
}
}
public function testGetAttributes() {
$this->assertTrue(is_array($this->manager->getAttributes()));
}
}
?>

View File

@ -0,0 +1,194 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_DQL_ParserTestCase extends Doctrine_UnitTestCase {
public function testPrepared() {
$coll = $this->session->query("FROM User WHERE User.name = :name", array(":name" => "zYne"));
$this->assertEqual($coll->count(), 1);
}
public function testQuery() {
$graph = new Doctrine_DQL_Parser($this->session);
$this->graph = $graph;
$user = $this->objTable->find(5);
$album = $this->session->create("Album");
$album->Song[0];
$user->Album[0]->name = "Damage Done";
$user->Album[1]->name = "Haven";
$user->Album[0]->Song[0]->title = "Damage Done";
$user->Album[0]->Song[1]->title = "The Treason Wall";
$user->Album[0]->Song[2]->title = "Monochromatic Stains";
$this->assertEqual(count($user->Album[0]->Song), 3);
$user->Album[1]->Song[0]->title = "Not Built To Last";
$user->Album[1]->Song[1]->title = "The Wonders At Your Feet";
$user->Album[1]->Song[2]->title = "Feast Of Burden";
$user->Album[1]->Song[3]->title = "Fabric";
$this->assertEqual(count($user->Album[1]->Song), 4);
$user->save();
$user = $this->objTable->find(5);
$this->assertEqual(count($user->Album[0]->Song), 3);
$this->assertEqual(count($user->Album[1]->Song), 4);
$users = $graph->query("FROM User WHERE User.Album.name like '%Damage%'");
// DYNAMIC COLLECTION EXPANDING
$user = $this->objTable->find(5);
$user->Group[1]->name = "Tough guys inc.";
$user->Group[2]->name = "Terminators";
$this->assertEqual($user->Group[0]->name, "Action Actors");
$user->save();
$this->assertEqual($user->Group[0]->name, "Action Actors");
$this->assertEqual(count($user->Group), 3);
$user = $this->objTable->find(5);
$this->assertEqual(count($user->Group), 3);
$users = $graph->query("FROM User, User.Group WHERE User.Group.name LIKE 'Action Actors'");
$this->assertEqual(count($users),1);
//$this->assertEqual($users[0]->Group[0]->name, "Action Actors");
//$this->assertEqual(count($users[0]->Group), 1);
//$this->assertEqual($users[0]->Group[1]->name, "Tough guys inc.");
//$this->assertEqual($users[0]->Group[2]->name, "Terminators");
//$this->assertEqual(count($users[0]->Group), 3);
$this->clearCache();
$users = $graph->query("FROM User, User.Phonenumber-l WHERE User.Phonenumber.phonenumber LIKE '%123%'");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id, phonenumber.id AS Phonenumber__id FROM entity LEFT JOIN phonenumber ON entity.id = phonenumber.entity_id WHERE (phonenumber.phonenumber LIKE '%123%') && (entity.type = 0)");
$count = $this->session->getDBH()->count();
$users[1]->Phonenumber[0]->phonenumber;
$users[1]->Phonenumber[1]->phonenumber;
$this->assertEqual($users[1]->Phonenumber[1]->getState(),Doctrine_Record::STATE_CLEAN);
$users[1]->Phonenumber[2]->phonenumber;
$this->assertEqual($users[1]->Phonenumber[1]->getState(),Doctrine_Record::STATE_CLEAN);
$count2 = $this->session->getDBH()->count();
$this->assertEqual($count + 4,$count2);
// DYNAMIC FETCHMODES
try {
$users = $graph->query("FROM User-unknown");
} catch(Exception $e) {
}
$this->assertTrue($e instanceof DQLException);
$users = $graph->query("FROM User-i");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id, entity.name AS User__name, entity.loginname AS User__loginname, entity.password AS User__password, entity.type AS User__type, entity.created AS User__created, entity.updated AS User__updated, entity.email_id AS User__email_id FROM entity WHERE (entity.type = 0)");
$count = $this->session->getDBH()->count();
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Immediate);
$count2 = $this->session->getDBH()->count();
$this->assertEqual($count,$count2);
$users = $graph->query("FROM User-b");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.type = 0)");
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Batch);
$users = $graph->query("FROM User-l");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.type = 0)");
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Lazy);
//$this->clearCache();
$users = $graph->query("FROM User, User.Phonenumber");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id, phonenumber.id AS Phonenumber__id FROM entity LEFT JOIN phonenumber ON entity.id = phonenumber.entity_id WHERE (entity.type = 0)");
$this->assertEqual($users->count(),8);
// EXPECTED THAT ONE NEW QUERY IS NEEDED TO GET THE FIRST USER's PHONENUMBER
$count = $this->session->getDBH()->count();
$users[0]->Phonenumber[0]->phonenumber;
$count2 = $this->session->getDBH()->count();
$this->assertEqual($count + 1,$count2);
$users = $graph->query("FROM User, User.Email");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id, email.id AS Email__id FROM entity, email WHERE (entity.email_id = email.id) && (entity.type = 0)");
$this->assertEqual($users->count(),8);
$users = $graph->query("FROM Email WHERE Email.address LIKE '%@example%'");
$this->assertEqual($graph->getQuery(),
"SELECT email.id AS Email__id FROM email WHERE (email.address LIKE '%@example%')");
$this->assertEqual($users->count(),8);
$users = $graph->query("FROM User WHERE User.name LIKE '%Jack%'");
$this->assertTrue($graph->getQuery() == "SELECT entity.id AS User__id FROM entity WHERE (entity.name LIKE '%Jack%') && (entity.type = 0)");
$this->assertEqual($users->count(),0);
$users = $graph->query("FROM User ORDER BY User.name ASC, User.Email.address");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id FROM entity, email WHERE (entity.email_id = email.id) && (entity.type = 0) ORDER BY entity.name ASC, email.address");
$this->assertEqual($users->count(),8);
$this->assertTrue($users[0]->name == "Arnold Schwarzenegger");
$users = $graph->query("FROM User WHERE User.Phonenumber.phonenumber REGEXP '[123]'");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id FROM entity LEFT JOIN phonenumber ON entity.id = phonenumber.entity_id WHERE (phonenumber.phonenumber REGEXP '[123]') && (entity.type = 0)");
$this->assertEqual($users->count(),8);
$users = $graph->query("FROM User WHERE User.Group.name = 'Action Actors'");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.id IN (SELECT user_id FROM groupuser WHERE group_id IN (SELECT entity.id AS Group__id FROM entity WHERE (entity.name = 'Action Actors') && (entity.type = 1)))) && (entity.type = 0)");
$this->assertTrue($users instanceof Doctrine_Collection);
$this->assertEqual($users->count(),1);
$users = $graph->query("FROM User WHERE User.Group.Phonenumber.phonenumber LIKE '123 123'");
$this->assertEqual(trim($graph->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.id IN (SELECT user_id FROM groupuser WHERE group_id IN (SELECT entity.id AS Group__id FROM entity, phonenumber WHERE (phonenumber.phonenumber LIKE '123 123') && (entity.type = 1)))) && (entity.type = 0)");
$this->assertTrue($users instanceof Doctrine_Collection);
$this->assertEqual($users->count(),1);
$values = $graph->query("SELECT COUNT(User.name) AS users, MAX(User.name) AS max FROM User");
$this->assertEqual(trim($graph->getQuery()),"SELECT COUNT(entity.name) AS users, MAX(entity.name) AS max FROM entity WHERE (entity.type = 0)");
$this->assertTrue(is_array($values));
$this->assertTrue(isset($values['users']));
$this->assertTrue(isset($values['max']));
}
}
?>

View File

@ -0,0 +1,13 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase {
public function testEvents() {
$session = $this->manager->openSession(Doctrine_DB::getConnection());
$debug = $this->listener->getMessages();
$last = end($debug);
$this->assertTrue($last->getObject() instanceof Doctrine_Session);
$this->assertTrue($last->getCode() == Doctrine_Debugger::EVENT_OPEN);
}
}
?>

View File

@ -0,0 +1,7 @@
<?php
class Doctrine_FormBuilderTestCase extends Doctrine_UnitTestCase {
public function testBuildForm() {
}
}
?>

View File

@ -0,0 +1,23 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_ManagerTestCase extends Doctrine_UnitTestCase {
public function testGetInstance() {
$this->assertTrue(Doctrine_Manager::getInstance() instanceOf Doctrine_Manager);
}
public function testOpenSession() {
$this->assertTrue($this->session instanceOf Doctrine_Session);
}
public function testGetIterator() {
$this->assertTrue($this->manager->getIterator() instanceof ArrayIterator);
}
public function testCount() {
$this->assertEqual(count($this->manager),1);
}
public function testGetCurrentSession() {
$this->assertEqual($this->manager->getCurrentSession(), $this->session);
}
public function testGetSessions() {
$this->assertEqual(count($this->manager->getSessions()),1);
}
}
?>

View File

@ -0,0 +1,440 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_RecordTestCase extends Doctrine_UnitTestCase {
public function testGet() {
$user = new User();
$user->name = "Jack Daniels";
$this->assertEqual($user->name, "Jack Daniels");
$this->assertEqual($user->created, null);
$this->assertEqual($user->updated, null);
$user->save();
$id = $user->getID();
$user = $user->getTable()->find($id);
$this->assertEqual($user->name, "Jack Daniels");
$this->assertEqual($user->created, null);
$this->assertEqual($user->updated, null);
}
public function testNewOperator() {
$user = new User();
$this->assertTrue($user->getState() == Doctrine_Record::STATE_TCLEAN);
$user->name = "John Locke";
$this->assertTrue($user->name,"John Locke");
$this->assertTrue($user->getState() == Doctrine_Record::STATE_TDIRTY);
$user->save();
$this->assertTrue($user->getState() == Doctrine_Record::STATE_CLEAN);
$this->assertTrue($user->name,"John Locke");
}
public function testTreeStructure() {
$e = new Element();
$e->name = "parent";
$e->Element[0]->name = "child 1";
$e->Element[1]->name = "child 2";
$e->Element[1]->Element[0]->name = "child 1's child 1";
$e->Element[1]->Element[1]->name = "child 1's child 1";
$this->assertEqual($e->name,"parent");
$this->assertEqual($e->Element[0]->name,"child 1");
$this->assertEqual($e->Element[1]->name,"child 2");
$this->assertEqual($e->Element[1]->Element[0]->name,"child 1's child 1");
$this->assertEqual($e->Element[1]->Element[1]->name,"child 1's child 1");
$this->session->flush();
$e = $e->getTable()->find($e->getID());
$this->assertEqual($e->name,"parent");
$this->assertEqual($e->Element[0]->name,"child 1");
$this->assertEqual($e->Element[1]->name,"child 2");
$this->assertEqual($e->Element[1]->Element[0]->name,"child 1's child 1");
$this->assertEqual($e->Element[1]->Element[1]->name,"child 1's child 1");
}
public function testUniqueKeyComponent() {
$e = new Error();
$e->message = "user error";
$e->file_md5 = md5(0);
$e->code = 1;
/**
* ADDING NEW RECORD
*/
$this->assertEqual($e->code,1);
$this->assertEqual($e->file_md5, md5(0));
$this->assertEqual($e->message, "user error");
$e2 = new Error();
$e2->message = "user error2";
$e2->file_md5 = md5(1);
$e2->code = 2;
$this->assertEqual($e2->code,2);
$this->assertEqual($e2->file_md5, md5(1));
$this->assertEqual($e2->message, "user error2");
$fk = $e->getTable()->getForeignKey("Description");
$this->assertTrue($fk instanceof Doctrine_ForeignKey);
$this->assertEqual($fk->getLocal(),"file_md5");
$this->assertEqual($fk->getForeign(),"file_md5");
$this->assertTrue($fk->getTable() instanceof Doctrine_Table);
$e->Description[0]->description = "This is the 1st description";
$e->Description[1]->description = "This is the 2nd description";
$this->assertEqual($e->Description[0]->description, "This is the 1st description");
$this->assertEqual($e->Description[1]->description, "This is the 2nd description");
$this->assertEqual($e->Description[0]->file_md5, $e->file_md5);
$this->assertEqual($e->Description[1]->file_md5, $e->file_md5);
$this->assertEqual($e2->Description[0]->description, null);
$this->assertEqual($e2->Description[1]->description, null);
$this->assertEqual($e2->Description[0]->file_md5, $e2->file_md5);
$this->assertEqual($e2->Description[1]->file_md5, $e2->file_md5);
$e->save();
$coll = $this->session->query("FROM Error-I");
$e = $coll[0];
$this->assertEqual($e->code,1);
$this->assertEqual($e->file_md5, md5(0));
$this->assertEqual($e->message, "user error");
$this->assertTrue($e->Description instanceof Doctrine_Collection);
$this->assertTrue($e->Description[0] instanceof Description);
$this->assertTrue($e->Description[1] instanceof Description);
$this->assertEqual($e->Description[0]->description, "This is the 1st description");
$this->assertEqual($e->Description[1]->description, "This is the 2nd description");
/**
* UPDATING
*/
$e->code = 2;
$e->message = "changed message";
$e->Description[0]->description = "1st changed description";
$e->Description[1]->description = "2nd changed description";
$this->assertEqual($e->code,2);
$this->assertEqual($e->message,"changed message");
$this->assertEqual($e->Description[0]->description, "1st changed description");
$this->assertEqual($e->Description[1]->description, "2nd changed description");
$e->save();
$this->assertEqual($e->code,2);
$this->assertEqual($e->message,"changed message");
$this->assertEqual($e->Description[0]->description, "1st changed description");
$this->assertEqual($e->Description[1]->description, "2nd changed description");
}
public function testInsert() {
$this->new->name = "John Locke";
$this->new->save();
$this->assertTrue($this->new->getModified() == array());
$this->assertTrue($this->new->getState() == Doctrine_Record::STATE_CLEAN);
$debug = $this->listener->getMessages();
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Session);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_COMMIT);
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Record);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_SLEEP);
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Record);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_SAVE);
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Record);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_INSERT);
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Record);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_PREINSERT);
$this->new->delete();
$this->assertTrue($this->new->getState() == Doctrine_Record::STATE_TCLEAN);
}
public function testUpdate() {
$this->old->set("name","Jack Daniels",true);
$this->old->save(true);
//print $this->old->name;
$this->assertEqual($this->old->getModified(), array());
$this->assertEqual($this->old->name, "Jack Daniels");
$debug = $this->listener->getMessages();
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Session);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_COMMIT);
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Record);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_SAVE);
$p = array_pop($debug);
$this->assertTrue($p->getObject() instanceof Doctrine_Record);
$this->assertTrue($p->getCode() == Doctrine_Debugger::EVENT_UPDATE);
}
public function testCopy() {
$new = $this->old->copy();
$this->assertTrue($new instanceof Doctrine_Record);
$this->assertTrue($new->getState() == Doctrine_Record::STATE_TDIRTY);
}
public function testReferences() {
$user = $this->objTable->find(5);
$pf = $this->session->getTable("Phonenumber");
$this->assertTrue($user->Phonenumber instanceof Doctrine_Collection);
$this->assertTrue($user->Phonenumber->count() == 3);
$coll = new Doctrine_Collection($pf);
$user->Phonenumber = $coll;
$this->assertTrue($user->Phonenumber->count() == 0);
$user->save();
unset($user);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 0);
// ADDING REFERENCES
$user->Phonenumber[0]->phonenumber = "123 123";
$this->assertEqual(gettype($user->Phonenumber[0]->entity_id),"integer");
$user->Phonenumber[1]->phonenumber = "123 123";
$user->save();
$this->assertTrue($user->Phonenumber->count() == 2);
unset($user);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 2);
$user->Phonenumber[3]->phonenumber = "123 123";
$user->save();
$this->assertTrue($user->Phonenumber->count() == 3);
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Phonenumber->count() == 3);
// DELETING REFERENCES
$user->Phonenumber->delete();
$this->assertTrue($user->Phonenumber->count() == 0);
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Phonenumber->count() == 0);
// ADDING REFERENCES WITH STRING KEYS
$user->Phonenumber["home"]->phonenumber = "123 123";
$user->Phonenumber["work"]->phonenumber = "444 444";
$user->save();
$this->assertTrue($user->Phonenumber->count() == 2);
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Phonenumber->count() == 2);
// REPLACING ONE-TO-MANY REFERENCE
unset($coll);
$coll = new Doctrine_Collection($pf);
$coll[0]->phonenumber = "123 123";
$coll["home"]->phonenumber = "444 444";
$coll["work"]->phonenumber = "444 444";
$user->Phonenumber = $coll;
$user->save();
$this->assertEqual($user->Phonenumber->count(), 3);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 3);
// ONE-TO-ONE REFERENCES
$user->Email->address = "drinker@drinkmore.info";
$this->assertTrue($user->Email instanceof Email);
$user->save();
$this->assertTrue($user->Email instanceof Email);
$user = $this->objTable->find(5);
$this->assertEqual($user->Email->address, "drinker@drinkmore.info");
$id = $user->Email->getID();
// REPLACING ONE-TO-ONE REFERENCES
$email = $this->session->create("Email");
$email->address = "absolutist@nottodrink.com";
$user->Email = $email;
$this->assertTrue($user->Email instanceof Email);
$this->assertEqual($user->Email->address, "absolutist@nottodrink.com");
$user->save();
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Email instanceof Email);
$this->assertEqual($user->Email->address, "absolutist@nottodrink.com");
$emails = $this->session->query("FROM Email WHERE Email.id = $id");
$this->assertEqual(count($emails),0);
}
public function testDeleteReference() {
$user = $this->objTable->find(5);
$int = $user->Phonenumber->delete();
$this->assertTrue($user->Phonenumber->count() == 0);
}
public function testSaveAssociations() {
$user = $this->objTable->find(5);
$gf = $this->session->getTable("Group");
$this->assertTrue($user->Group instanceof Doctrine_Collection);
// ADDING ASSOCIATED REFERENCES
$record = $gf->find(1);
$record2 = $gf->find(2);
$user->Group[0] = $record;
$user->Group[1] = $record2;
$this->assertTrue($user->Group->count() == 2);
$user->save();
// UNSETTING ASSOCIATED REFERENCES
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Group->count() == 2);
unset($user->Group[0]);
$this->assertTrue($user->Group->count() == 1);
unset($user->Group[1]);
$this->assertTrue($user->Group->count() == 0);
$user->save();
$this->assertTrue($user->Group->count() == 0);
unset($user);
// CHECKING THE PERSISTENCE OF UNSET ASSOCIATED REFERENCES
$user = $this->objTable->find(5);
$this->assertTrue($user->Group->count() == 0);
// REPLACING OLD ASSOCIATED REFERENCE
$user->Group[0] = $record;
$user->save();
$user->Group[0] = $record2;
$user->save();
$this->assertEqual($user->Group->count(), 1);
$this->assertEqual($user->Group[0]->getID(), $record2->getID());
$this->assertFalse($user->Group[0]->getID() == $record->getID());
$user->Group[0] = $record;
$user->Group[1] = $gf->find(3);
$user->save();
$this->assertEqual($user->Group->count(), 2);
$user = $this->objTable->find(5);
$this->assertEqual($user->Group->count(), 2);
$user->Group = new Doctrine_Collection($gf);
$user->save();
$this->assertEqual($user->Group->count(), 0);
$user = $this->objTable->find(5);
$this->assertEqual($user->Group->count(), 0);
// ACCESSING ASSOCIATION OBJECT PROPERTIES
$user = new User();
$this->assertTrue($user->getTable()->getForeignKey("Groupuser") instanceof Doctrine_ForeignKey);
$this->assertTrue($user->Groupuser instanceof Doctrine_Collection);
$this->assertTrue($user->Groupuser[0] instanceof Groupuser);
$user->name = "Jack Daniels";
$user->Group[0]->name = "Group #1";
$user->Group[1]->name = "Group #2";
$t1 = time();
$t2 = time();
$user->Groupuser[0]->added = $t1;
$user->Groupuser[1]->added = $t2;
$this->assertEqual($user->Groupuser[0]->added, $t1);
$this->assertEqual($user->Groupuser[1]->added, $t2);
$user->save();
$user->refresh();
$this->assertEqual($user->Groupuser[0]->added, $t1);
$this->assertEqual($user->Groupuser[1]->added, $t2);
}
public function testCount() {
$this->assertTrue(is_integer($this->old->count()));
}
public function testGetReference() {
$this->assertTrue($this->old->Email instanceof Doctrine_Record);
$this->assertTrue($this->old->Phonenumber instanceof Doctrine_Collection);
$this->assertTrue($this->old->Group instanceof Doctrine_Collection);
$this->assertTrue($this->old->Phonenumber->count() == 1);
}
public function testSerialize() {
$old = $this->old;
$old = serialize($old);
$this->assertEqual(unserialize($old)->getID(),$this->old->getID());
}
public function testGetIterator() {
$this->assertTrue($this->old->getIterator() instanceof ArrayIterator);
}
}
?>

View File

@ -0,0 +1,7 @@
<?php
class Doctrine_RepositoryTestCase extends Doctrine_UnitTestCase {
public function testAdd() {
}
}
?>

View File

@ -0,0 +1,263 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_SessionTestCase extends Doctrine_UnitTestCase {
public function testGetFactory() {
$objTable = $this->session->getTable("User");
$this->assertTrue($objTable instanceOf Doctrine_Table);
}
public function testFlush() {
$this->assertEqual(gettype($this->old->Phonenumber[0]->entity_id), "integer");
$user = $this->session->create("Email");
$user = $this->session->create("User");
$record = $this->session->create("Phonenumber");
$user->Email->address = "example@drinkmore.info";
$this->assertTrue($user->email_id instanceof Email);
$user->name = "Example user";
$user->Group[0]->name = "Example group 1";
$user->Group[1]->name = "Example group 2";
$user->Phonenumber[0]->phonenumber = "123 123";
$user->Phonenumber[1]->phonenumber = "321 2132";
$user->Phonenumber[2]->phonenumber = "123 123";
$user->Phonenumber[3]->phonenumber = "321 2132";
$this->assertTrue($user->Phonenumber[0]->entity_id instanceof User);
$this->assertTrue($user->Phonenumber[2]->entity_id instanceof User);
$this->session->flush();
$this->assertTrue(gettype($user->getID()) == "integer");
$this->assertTrue(gettype($user->email_id) == "integer");
$this->assertTrue(gettype($user->Phonenumber[0]->entity_id) == "integer");
$this->assertEqual(count($user->Group), 2);
$user = $this->objTable->find(12);
$this->assertEqual($user->getID(), 12);
$this->assertTrue(gettype($user->getID()) == "integer");
$this->assertTrue(gettype($user->email_id) == "integer");
$this->assertEqual(gettype($user->Phonenumber[0]->entity_id), "integer");
$this->assertTrue($user->Phonenumber->count(), 4);
$this->assertEqual($user->Group->count(), 2);
$user = $this->objTable->find(5);
$pf = $this->session->getTable("Phonenumber");
$this->assertTrue($user->Phonenumber instanceof Doctrine_Collection);
$this->assertTrue($user->Phonenumber->count() == 3);
$coll = new Doctrine_Collection($pf);
$user->Phonenumber = $coll;
$this->assertTrue($user->Phonenumber->count() == 0);
$this->session->flush();
unset($user);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 0);
// ADDING REFERENCES
$user->Phonenumber[0]->phonenumber = "123 123";
$this->assertEqual(gettype($user->Phonenumber[0]->entity_id),"integer");
$user->Phonenumber[1]->phonenumber = "123 123";
$this->session->flush();
$this->assertTrue($user->Phonenumber->count() == 2);
unset($user);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 2);
$user->Phonenumber[3]->phonenumber = "123 123";
$this->session->flush();
$this->assertTrue($user->Phonenumber->count() == 3);
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Phonenumber->count() == 3);
// DELETING REFERENCES
$user->Phonenumber->delete();
$this->assertTrue($user->Phonenumber->count() == 0);
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Phonenumber->count() == 0);
// ADDING REFERENCES WITH STRING KEYS
$user->Phonenumber["home"]->phonenumber = "123 123";
$user->Phonenumber["work"]->phonenumber = "444 444";
$this->assertEqual($user->Phonenumber->count(), 2);
$this->session->flush();
$this->assertTrue($user->Phonenumber->count() == 2);
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Phonenumber->count() == 2);
// REPLACING ONE-TO-MANY REFERENCE
unset($coll);
$coll = new Doctrine_Collection($pf);
$coll[0]->phonenumber = "123 123";
$coll["home"]->phonenumber = "444 444";
$coll["work"]->phonenumber = "444 444";
$user->Phonenumber = $coll;
$this->session->flush();
$this->assertEqual($user->Phonenumber->count(), 3);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 3);
// ONE-TO-ONE REFERENCES
$user->Email->address = "drinker@drinkmore.info";
$this->assertTrue($user->Email instanceof Email);
$this->session->flush();
$this->assertTrue($user->Email instanceof Email);
$user = $this->objTable->find(5);
$this->assertEqual($user->Email->address, "drinker@drinkmore.info");
$id = $user->Email->getID();
// REPLACING ONE-TO-ONE REFERENCES
$email = $this->session->create("Email");
$email->address = "absolutist@nottodrink.com";
$user->Email = $email;
$this->assertTrue($user->Email instanceof Email);
$this->assertEqual($user->Email->address, "absolutist@nottodrink.com");
$this->session->flush();
unset($user);
$user = $this->objTable->find(5);
$this->assertTrue($user->Email instanceof Email);
$this->assertEqual($user->Email->address, "absolutist@nottodrink.com");
$emails = $this->session->query("FROM Email WHERE Email.id = $id");
$this->assertEqual(count($emails),0);
}
public function testGetManager() {
$this->assertEqual($this->session->getManager(),$this->manager);
}
public function testQuery() {
$this->assertTrue($this->session->query("FROM User") instanceof Doctrine_Collection);
}
public function testDelete() {
$user = $this->session->create("User");
$this->session->delete($user);
$this->assertEqual($user->getState(),Doctrine_Record::STATE_TCLEAN);
}
public function testGetTable() {
$table = $this->session->getTable("Group");
$this->assertTrue($table instanceof Doctrine_Table);
try {
$table = $this->session->getTable("Unknown");
$f = false;
} catch(Doctrine_Exception $e) {
$f = true;
}
$this->assertTrue($f);
$table = $this->session->getTable("User");
$this->assertTrue($table instanceof UserTable);
}
public function testCreate() {
$email = $this->session->create("Email");
$this->assertTrue($email instanceof Email);
}
public function testGetDBH() {
$this->assertTrue($this->session->getDBH() instanceof PDO);
}
public function testCount() {
$this->assertTrue(is_integer(count($this->session)));
}
public function testGetIterator() {
$this->assertTrue($this->session->getIterator() instanceof ArrayIterator);
}
public function testGetState() {
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_OPEN);
$this->assertEqual(Doctrine_Lib::getSessionStateAsString($this->session->getState()), "open");
}
public function testGetTables() {
$this->assertTrue(is_array($this->session->getTables()));
}
public function testTransactions() {
$this->session->beginTransaction();
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_ACTIVE);
$this->session->commit();
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_OPEN);
$this->session->beginTransaction();
$user = $this->objTable->find(6);
$user->name = "Jack Daniels";
$this->session->flush();
$this->session->commit();
$user = $this->objTable->find(6);
$this->assertEqual($user->name, "Jack Daniels");
}
public function testRollback() {
$this->session->beginTransaction();
$this->assertEqual($this->session->getTransactionLevel(),1);
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_ACTIVE);
$this->session->rollback();
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_OPEN);
$this->assertEqual($this->session->getTransactionLevel(),0);
}
public function testNestedTransactions() {
$this->assertEqual($this->session->getTransactionLevel(),0);
$this->session->beginTransaction();
$this->assertEqual($this->session->getTransactionLevel(),1);
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_ACTIVE);
$this->session->beginTransaction();
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_BUSY);
$this->assertEqual($this->session->getTransactionLevel(),2);
$this->session->commit();
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_ACTIVE);
$this->assertEqual($this->session->getTransactionLevel(),1);
$this->session->commit();
$this->assertEqual($this->session->getState(),Doctrine_Session::STATE_OPEN);
$this->assertEqual($this->session->getTransactionLevel(),0);
}
public function testClear() {
$this->session->clear();
$this->assertEqual($this->session->getTables(), array());
}
}
?>

View File

@ -0,0 +1,94 @@
<?php
require_once("UnitTestCase.class.php");
class Doctrine_TableTestCase extends Doctrine_UnitTestCase {
public function testGetForeignKey() {
$fk = $this->objTable->getForeignKey("Group");
$this->assertTrue($fk instanceof Doctrine_Association);
$this->assertTrue($fk->getTable() instanceof Doctrine_Table);
$this->assertTrue($fk->getType() == Doctrine_Table::MANY_AGGREGATE);
$this->assertTrue($fk->getLocal() == "user_id");
$this->assertTrue($fk->getForeign() == "group_id");
$fk = $this->objTable->getForeignKey("Email");
$this->assertTrue($fk instanceof Doctrine_LocalKey);
$this->assertTrue($fk->getTable() instanceof Doctrine_Table);
$this->assertTrue($fk->getType() == Doctrine_Table::ONE_COMPOSITE);
$this->assertTrue($fk->getLocal() == "email_id");
$this->assertTrue($fk->getForeign() == "id");
$fk = $this->objTable->getForeignKey("Phonenumber");
$this->assertTrue($fk instanceof Doctrine_ForeignKey);
$this->assertTrue($fk->getTable() instanceof Doctrine_Table);
$this->assertTrue($fk->getType() == Doctrine_Table::MANY_COMPOSITE);
$this->assertTrue($fk->getLocal() == "id");
$this->assertTrue($fk->getForeign() == "entity_id");
}
public function testGetComponentName() {
$this->assertTrue($this->objTable->getComponentName() == "User");
}
public function testGetTableName() {
$this->assertTrue($this->objTable->getTableName() == "entity");
}
public function testGetSession() {
$this->assertTrue($this->objTable->getSession() instanceof Doctrine_Session);
}
public function testGetCache() {
$this->assertTrue($this->objTable->getCache() instanceof Doctrine_Cache_File);
}
public function testGetData() {
$this->assertTrue($this->objTable->getData() == array());
}
public function testSetSequenceName() {
$this->objTable->setSequenceName("test-seq");
$this->assertEqual($this->objTable->getSequenceName(),"test-seq");
$this->objTable->setSequenceName(null);
}
public function testCreate() {
$record = $this->objTable->create();
$this->assertTrue($record instanceof Doctrine_Record);
$this->assertTrue($record->getState() == Doctrine_Record::STATE_TCLEAN);
}
public function testFind() {
$record = $this->objTable->find(4);
$this->assertTrue($record instanceof Doctrine_Record);
try {
$record = $this->objTable->find(123);
} catch(Exception $e) {
$this->assertTrue($e instanceOf Doctrine_Find_Exception);
}
}
public function testFindAll() {
$users = $this->objTable->findAll();
$this->assertEqual($users->count(), 8);
$this->assertTrue($users instanceof Doctrine_Collection_Batch);
}
public function testFindBySql() {
$users = $this->objTable->findBySql("name LIKE '%Arnold%'");
$this->assertEqual($users->count(), 1);
$this->assertTrue($users instanceof Doctrine_Collection_Batch);
}
public function testGetProxy() {
$user = $this->objTable->getProxy(4);
$this->assertTrue($user instanceof Doctrine_Record);
try {
$record = $this->objTable->find(123);
} catch(Exception $e) {
$this->assertTrue($e instanceOf Doctrine_Find_Exception);
}
}
public function testGetColumns() {
$columns = $this->objTable->getColumns();
$this->assertTrue(is_array($columns));
}
public function testIsNewEntry() {
$this->assertFalse($this->objTable->isNewEntry());
}
public function testApplyInheritance() {
$this->assertEqual($this->objTable->applyInheritance("id = 3"), "id = 3 && type = ?");
}
}
?>

View File

@ -0,0 +1,146 @@
<?php
require_once("../classes/Doctrine.class.php");
/**
function __autoload($class) {
Doctrine::autoload($class);
}
*/
Doctrine::loadAll();
require_once("classes.php");
ini_set('include_path',ucwords($_SERVER["DOCUMENT_ROOT"]));
require_once("simpletest/unit_tester.php");
require_once("simpletest/reporter.php");
class Doctrine_UnitTestCase extends UnitTestCase {
protected $manager;
protected $session;
protected $objTable;
protected $repository;
protected $new;
protected $old;
protected $dbh;
protected $listener;
protected $cache;
protected $users;
protected $tables;
private static $instances;
private $init = false;
public function init() {
$name = get_class($this);
if( ! isset($instances[$name]))
$instances[$name] = $this;
$this->manager = Doctrine_Manager::getInstance();
if($this->manager->count() > 0) {
$this->session = $this->manager->getSession(0);
$this->session->clear();
$this->dbh = $this->session->getDBH();
$this->listener = $this->manager->getAttribute(Doctrine::ATTR_LISTENER);
} else {
$this->dbh = Doctrine_DB::getConnection();
$this->session = $this->manager->openSession($this->dbh);
$this->listener = new Doctrine_Debugger();
$this->manager->setAttribute(Doctrine::ATTR_LISTENER, $this->listener);
}
$this->tables = array("entity","email","phonenumber","groupuser","album","song","element","error","description");
$tables = $this->tables;
foreach($tables as $name) {
$this->dbh->query("DROP TABLE IF EXISTS $name");
}
foreach($tables as $name) {
$table = $this->session->getTable($name);
$table->getCache()->deleteAll();
}
$this->objTable = $this->session->getTable("User");
$this->repository = $this->objTable->getRepository();
$this->cache = $this->objTable->getCache();
$this->prepareData();
}
public function prepareData() {
$groups = new Doctrine_Collection($this->session->getTable("Group"));
$groups[0]->name = "Drama Actors";
$groups[0]->save();
$groups[1]->name = "Quality Actors";
$groups[1]->save();
$groups[2]->name = "Action Actors";
$groups[2]["Phonenumber"][0]->phonenumber = "123 123";
$groups[2]->save();
$users = new Doctrine_Collection($this->session->getTable("User"));
$users[0]->name = "zYne";
$users[0]["Email"]->address = "zYne@example.com";
$users[0]["Phonenumber"][0]->phonenumber = "123 123";
$users[1]->name = "Arnold Schwarzenegger";
$users[1]->Email->address = "arnold@example.com";
$users[1]["Phonenumber"][0]->phonenumber = "123 123";
$users[1]["Phonenumber"][1]->phonenumber = "456 456";
$users[1]->Phonenumber[2]->phonenumber = "789 789";
$users[1]->Group[0] = $groups[2];
$users[2]->name = "Michael Caine";
$users[2]->Email->address = "caine@example.com";
$users[2]->Phonenumber[0]->phonenumber = "123 123";
$users[3]->name = "Takeshi Kitano";
$users[3]->Email->address = "kitano@example.com";
$users[3]->Phonenumber[0]->phonenumber = "111 222 333";
$users[4]->name = "Sylvester Stallone";
$users[4]->Email->address = "stallone@example.com";
$users[4]->Phonenumber[0]->phonenumber = "111 555 333";
$users[4]["Phonenumber"][1]->phonenumber = "123 213";
$users[4]["Phonenumber"][2]->phonenumber = "444 555";
$users[5]->name = "Kurt Russell";
$users[5]->Email->address = "russell@example.com";
$users[5]->Phonenumber[0]->phonenumber = "111 222 333";
$users[6]->name = "Jean Reno";
$users[6]->Email->address = "reno@example.com";
$users[6]->Phonenumber[0]->phonenumber = "111 222 333";
$users[6]["Phonenumber"][1]->phonenumber = "222 123";
$users[6]["Phonenumber"][2]->phonenumber = "123 456";
$users[7]->name = "Edward Furlong";
$users[7]->Email->address = "furlong@example.com";
$users[7]->Phonenumber[0]->phonenumber = "111 567 333";
$this->users = $users;
$this->session->flush();
}
public function clearCache() {
foreach($this->tables as $name) {
$table = $this->session->getTable($name);
$table->getCache()->deleteAll();
}
}
public function setUp() {
if( ! $this->init) $this->init();
$this->init = true;
$this->new = $this->objTable->create();
$this->old = $this->objTable->find(4);
}
}
?>

View File

@ -0,0 +1,73 @@
<?php
class Doctrine_ValidatorTestCase extends Doctrine_UnitTestCase {
public function testValidate() {
$set = array("password" => "this is an example of too long password",
"loginname" => "this is an example of too long loginname",
"name" => "valid name",
"created" => "invalid");
$this->old->setArray($set);
$email = $this->old->Email;
$email->address = "zYne@invalid";
$this->assertTrue($this->old->isLoaded());
$this->assertTrue($this->old->getModified() == $set);
$validator = new Doctrine_Validator();
$validator->validateRecord($this->old);
$validator->validateRecord($email);
$stack = $validator->getErrorStack();
$this->assertTrue(is_array($stack));
$this->assertEqual($stack["User"][0]["loginname"], Doctrine_Validator::ERR_LENGTH);
$this->assertEqual($stack["User"][0]["password"], Doctrine_Validator::ERR_LENGTH);
$this->assertEqual($stack["User"][0]["created"], Doctrine_Validator::ERR_TYPE);
$this->assertEqual($stack["Email"][0]["address"], Doctrine_Validator::ERR_VALID);
$email->address = "arnold@example.com";
$validator->validateRecord($email);
$stack = $validator->getErrorStack();
$this->assertEqual($stack["Email"][1]["address"], Doctrine_Validator::ERR_UNIQUE);
}
public function testIsValidEmail() {
$validator = new Doctrine_Validator_Email();
$email = $this->session->create("Email");
$this->assertFalse($validator->validate($email,"address","example@example"));
$this->assertFalse($validator->validate($email,"address","example@@example"));
$this->assertFalse($validator->validate($email,"address","example@example."));
$this->assertFalse($validator->validate($email,"address","example@e.."));
$this->assertFalse($validator->validate($email,"address","example@e.."));
$this->assertTrue($validator->validate($email,"address","example@e.e.e.e.e"));
}
public function testSave() {
$this->manager->setAttribute(Doctrine::ATTR_VLD, true);
try {
$this->old->name = "this is an example of too long name not very good example but an example nevertheless";
$this->old->save();
} catch(Doctrine_Validator_Exception $e) {
$this->assertEqual($e->getErrorStack(),array("User" => array(array("name" => 0))));
}
try {
$user = $this->session->create("User");
$user->Email->address = "jackdaniels@drinkmore.info...";
$user->name = "this is an example of too long user name not very good example but an example nevertheles";
$user->save();
} catch(Doctrine_Validator_Exception $e) {
$a = $e->getErrorStack();
}
$this->assertTrue(is_array($a));
$this->assertEqual($a["Email"][0]["address"], Doctrine_Validator::ERR_VALID);
$this->assertEqual($a["User"][0]["name"], Doctrine_Validator::ERR_LENGTH);
}
}
?>

103
tests/classes.php Normal file
View File

@ -0,0 +1,103 @@
<?php
class Entity extends Doctrine_Record {
public function setUp() {
$this->ownsOne("Email","Entity.email_id");
$this->ownsMany("Phonenumber","Phonenumber.entity_id");
$this->setAttribute(Doctrine::ATTR_FETCHMODE,Doctrine::FETCH_BATCH);
}
public function setTableDefinition() {
$this->hasColumn("name","string",50);
$this->hasColumn("loginname","string",20);
$this->hasColumn("password","string",16);
$this->hasColumn("type","integer",1);
$this->hasColumn("created","integer",11);
$this->hasColumn("updated","integer",11);
$this->hasColumn("email_id","integer");
}
}
// grouptable doesn't extend Doctrine_Table -> Doctrine_Session
// won't initialize grouptable when Doctrine_Session->getTable("Group") is called
class GroupTable { }
class Group extends Entity {
public function setUp() {
parent::setUp();
$this->hasMany("User","Groupuser.user_id");
$this->setInheritanceMap(array("type"=>1));
}
}
class Error extends Doctrine_Record {
public function setUp() {
$this->ownsMany("Description","Description.file_md5","file_md5");
}
public function setTableDefinition() {
$this->hasColumn("message","string",200);
$this->hasColumn("code","integer",11);
$this->hasColumn("file_md5","string",32,"primary");
}
}
class Description extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("description","string",3000);
$this->hasColumn("file_md5","string",32);
}
}
class UserTable extends Doctrine_Table { }
class User extends Entity {
public function setUp() {
parent::setUp();
$this->ownsMany("Album","Album.user_id");
$this->hasMany("Group","Groupuser.group_id");
$this->setInheritanceMap(array("type"=>0));
}
}
class Groupuser extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("added","integer");
$this->hasColumn("group_id","integer");
$this->hasColumn("user_id","integer");
}
}
class Phonenumber extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("phonenumber","string",20);
$this->hasColumn("entity_id","integer");
}
}
class Element extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("name", "string", 100);
$this->hasColumn("parent_id", "integer");
}
public function setUp() {
$this->hasMany("Element","Element.parent_id");
}
}
class Email extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("address","string",150,"email|unique");
}
}
class Album extends Doctrine_Record {
public function setUp() {
$this->ownsMany("Song","Song.album_id");
}
public function setTableDefinition() {
$this->hasColumn("user_id","integer");
$this->hasColumn("name","string",20);
}
}
class Song extends Doctrine_Record {
public function setUp() {
$this->hasColumn("genre","string","30");
}
public function setTableDefinition() {
$this->hasColumn("album_id","integer");
$this->hasColumn("genre","string",20);
$this->hasColumn("title","string",30);
}
}
?>

55
tests/run.php Normal file
View File

@ -0,0 +1,55 @@
<?php
require_once("ConfigurableTestCase.class.php");
require_once("ManagerTestCase.class.php");
require_once("SessionTestCase.class.php");
require_once("TableTestCase.class.php");
require_once("EventListenerTestCase.class.php");
require_once("BatchIteratorTestCase.class.php");
require_once("CacheFileTestCase.class.php");
require_once("RecordTestCase.class.php");
require_once("DQLParserTestCase.class.php");
require_once("AccessTestCase.class.php");
require_once("ValidatorTestCase.class.php");
print "<pre>";
error_reporting(E_ALL);
$test = new GroupTest("Doctrine Framework Unit Tests");
$test->addTestCase(new Doctrine_RecordTestCase());
/**
$test->addTestCase(new Doctrine_SessionTestCase());
$test->addTestCase(new Doctrine_ValidatorTestCase());
$test->addTestCase(new Doctrine_ManagerTestCase());
$test->addTestCase(new Doctrine_TableTestCase());
$test->addTestCase(new Doctrine_AccessTestCase());
$test->addTestCase(new Doctrine_ConfigurableTestCase());
$test->addTestCase(new Doctrine_EventListenerTestCase());
$test->addTestCase(new Doctrine_BatchIteratorTestCase());
$test->addTestCase(new Doctrine_Cache_FileTestCase());
$test->addTestCase(new Doctrine_DQL_ParserTestCase());
*/
$test->run(new HtmlReporter());
$a = Doctrine_Manager::getInstance()->getCurrentSession()->getDBH()->getQueries();
print "Executed queries: ".count($a)."\n";
foreach($a as $query) {
$e = explode(" ",$query);
print $query."\n";
}
?>