Commit ff99e2e3 authored by doctrine's avatar doctrine

Removed file/folder

parent 98dc74b6
<?php
/**
* Doctrine_Access
*
* the purpose of Doctrine_Access is to provice array access
* and property overload interface for subclasses
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
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);
}
/**
* @param mixed $offset
* @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);
}
}
}
?>
<?php
require_once("Relation.class.php");
/**
* Doctrine_Association this class takes care of association mapping
* (= many-to-many relationships, where the relationship is handled with an additional relational table
* which holds 2 foreign keys)
*
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
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;
}
}
?>
<?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 array $keys
* @return boolean
*/
public function fetchMultiple($keys) {
return false;
}
/**
* implemented by child classes
* @param integer $id
* @return boolean
*/
public function exists($id) {
return false;
}
/**
* implemented by child classes
*/
public function deleteMultiple($keys) {
return 0;
}
/**
* implemented by child classes
* @return integer
*/
public function deleteAll() {
return 0;
}
}
?>
<?php
/**
* Doctrine_CacheFile
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Cache_File 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();
}
}
?>
<?php
class Doctrine_Cache_Sqlite {
/**
* STATS_FILE constant
* the name of the statistics file
*/
const STATS_FILE = "stats.cache";
/**
* SELECT constant
* used as a base for SQL SELECT queries
*/
const SELECT = "SELECT object FROM %s WHERE id %s";
/**
* INSERT constant
* used as a base for SQL INSERT queries
*/
const INSERT = "REPLACE INTO %s (id, object) VALUES (?, ?)";
/**
* DELETE constant
* used as a base for SQL DELETE queries
*/
const DELETE = "DELETE FROM %s WHERE id %s";
/**
* @var Doctrine_Table $table
*/
private $table;
/**
* @var PDO $dbh
*/
private $dbh;
/**
* @var array $fetched an array of fetched primary keys
*/
private $fetched = array();
public function __construct(Doctrine_Table $table) {
$this->table = $table;
$dir = $this->table->getSession()->getAttribute(Doctrine::ATTR_CACHE_DIR);
if( ! is_dir($dir))
mkdir($dir, 0777);
$this->path = $dir.DIRECTORY_SEPARATOR;
$this->dbh = $this->table->getSession()->getCacheHandler();
try {
$this->dbh->query("CREATE TABLE ".$this->table->getTableName()." (id INTEGER UNIQUE, object TEXT)");
} catch(PDOException $e) {
}
/**
* create stats file
*/
if( ! file_exists($this->path.self::STATS_FILE))
touch($this->path.self::STATS_FILE);
}
/*
* stores a Doctrine_Record into cache
* @param Doctrine_Record $record record 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;
$clone = clone $record;
$id = $clone->getID();
$stmt = $this->dbh->query(sprintf(self::INSERT,$this->table->getTableName()));
$stmt->execute(array($id, serialize($clone)));
return true;
}
/**
* fetches a Doctrine_Record from the cache
* @param mixed $id
* @return mixed false on failure, Doctrine_Record on success
*/
public function fetch($id) {
$stmt = $this->dbh->query(sprintf(self::SELECT,$this->table->getTableName(),"= ?"));
$stmt->execute(array($id));
$data = $stmt->fetch(PDO::FETCH_NUM);
if($data === false)
throw new InvalidKeyException();
$this->fetched[] = $id;
$record = unserialize($data[0]);
if(is_string($record)) {
$this->delete($id);
throw new InvalidKeyException();
}
return $record;
}
/**
* fetches multiple records from the cache
* @param array $keys
* @return mixed false on failure, an array of Doctrine_Record objects on success
*/
public function fetchMultiple(array $keys) {
$count = (count($keys)-1);
$keys = array_values($keys);
$sql = sprintf(self::SELECT,$this->table->getTableName(),"IN (".str_repeat("?, ",$count)."?)");
$stmt = $this->dbh->query($sql);
$stmt->execute($keys);
while($data = $stmt->fetch(PDO::FETCH_NUM)) {
$array[] = unserialize($data[0]);
}
$this->fetched = array_merge($this->fetched, $keys);
if( ! isset($array))
return false;
return $array;
}
/**
* deletes all records from cache
* @return void
*/
public function deleteAll() {
$stmt = $this->dbh->query("DELETE FROM ".$this->table->getTableName());
return $stmt->rowCount();
}
/**
* @param mixed $id
* @return void
*/
public function delete($id) {
$stmt = $this->dbh->query(sprintf(self::DELETE,$this->table->getTableName(),"= ?"));
$stmt->execute(array($id));
if($stmt->rowCount() > 0)
return true;
return false;
}
/**
* count
* @return integer
*/
public function count() {
$stmt = $this->dbh->query("SELECT COUNT(*) FROM ".$this->table->getTableName());
$data = $stmt->fetch(PDO::FETCH_NUM);
// table has two columns so we have to divide the count by two
return ($data[0] / 2);
}
/**
* @param array $keys
* @return integer
*/
public function deleteMultiple(array $keys) {
if(empty($keys))
return 0;
$keys = array_values($keys);
$count = (count($keys)-1);
$sql = sprintf(self::DELETE,$this->table->getTableName(),"IN (".str_repeat("?, ",$count)."?)");
$stmt = $this->dbh->query($sql);
$stmt->execute($keys);
return $stmt->rowCount();
}
/**
* 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);
}
/**
* clean
* @return void
*/
public function clean() {
$stats = $this->getStats();
asort($stats);
$size = $this->table->getAttribute(Doctrine::ATTR_CACHE_SIZE);
$count = count($stats);
if($count <= $size)
return 0;
$e = $count - $size;
$keys = array();
foreach($stats as $id => $count) {
if( ! $e--)
break;
$keys[] = $id;
}
return $this->deleteMultiple($keys);
}
/**
* saves statistics
* @return boolean
*/
public function saveStats() {
if( ! empty($this->fetched)) {
$fp = fopen($this->path.self::STATS_FILE,"a");
fwrite($fp,":".implode(":",$this->fetched));
fclose($fp);
$this->fetched = array();
return true;
}
return false;
}
/**
* autoClean
* $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)
* @return boolean
*/
public function autoClean() {
$ttl = $this->table->getAttribute(Doctrine::ATTR_CACHE_TTL);
$l1 = (mt_rand(1,$ttl) / $ttl);
$l2 = (1 - 1/$ttl);
if($l1 > $l2) {
$this->clean();
return true;
}
return false;
}
/**
* @param mixed $id
*/
public function addDelete($id) {
$this->delete[] = $id;
}
/**
* destructor
* the purpose of this destructor is to save all the fetched
* primary keys into the cache stats and to clean cache if necessary
*
*/
public function __destruct() {
$this->saveStats();
$this->autoClean();
}
}
?>
<?php
require_once("Access.class.php");
/**
* Doctrine_Collection
* Collection of Doctrine_Record objects.
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
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 the record this collection is related to, if any
*/
protected $relation;
/**
* @var boolean $expandable whether or not this collection has been expanded
*/
protected $expandable = true;
/**
* @var array $expanded
*/
protected $expanded = array();
/**
* @var mixed $generator
*/
protected $generator;
/**
* @var Doctrine_Null $null used for extremely fast SQL null value testing
*/
protected static $null;
/**
* constructor
*/
public function __construct(Doctrine_Table $table) {
$this->table = $table;
$name = $table->getAttribute(Doctrine::ATTR_COLL_KEY);
if($name !== null) {
$this->generator = new Doctrine_IndexGenerator($name);
}
}
/**
* initNullObject
*/
public static function initNullObject(Doctrine_Null $null) {
self::$null = $null;
}
/**
* @return object Doctrine_Table
*/
public function getTable() {
return $this->table;
}
/**
* whether or not an offset batch has been expanded
* @return boolean
*/
public function isExpanded($offset) {
return isset($this->expanded[$offset]);
}
/**
* whether or not this collection is expandable
* @return boolean
*/
public function isExpandable() {
return $this->expandable;
}
/**
* @param Doctrine_IndexGenerator $generator
* @return void
*/
public function setGenerator($generator) {
$this->generator = $generator;
}
/**
* @return Doctrine_IndexGenerator
*/
public function getGenerator() {
return $this->generator;
}
/**
* @return array
*/
public function getData() {
return $this->data;
}
/**
* @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->getNormalIterator() as $record) {
if($value !== null) {
$record->rawSet($this->reference_field, $value);
} else {
$record->rawSet($this->reference_field, $this->reference);
}
}
}
}
/**
* @return mixed
*/
public function getReference() {
return $this->reference;
}
/**
* @return boolean
*/
public function expand($key) {
$where = array();
$params = array();
$limit = null;
$offset = null;
switch(get_class($this)):
case "Doctrine_Collection_Offset":
$limit = $this->getLimit();
$offset = (floor($key / $limit) * $limit);
if( ! $this->expandable && isset($this->expanded[$offset]))
return false;
$fields = implode(", ",$this->table->getColumnNames());
break;
default:
if( ! $this->expandable)
return false;
if( ! isset($this->reference))
return false;
$id = $this->reference->getID();
if(empty($id))
return false;
switch(get_class($this)):
case "Doctrine_Collection_Immediate":
$fields = implode(", ",$this->table->getColumnNames());
break;
default:
$fields = implode(", ",$this->table->getPrimaryKeys());
endswitch;
endswitch;
if(isset($this->relation)) {
if($this->relation instanceof Doctrine_ForeignKey) {
$params = array($this->reference->getID());
$where[] = $this->reference_field." = ?";
if( ! isset($offset)) {
$ids = $this->getPrimaryKeys();
if( ! empty($ids)) {
$where[] = $this->table->getIdentifier()." NOT IN (".substr(str_repeat("?, ",count($ids)),0,-2).")";
$params = array_merge($params,$ids);
}
$this->expandable = false;
}
} 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().".".$table->getIdentifier()." IN ($query)";
}
}
$query = "SELECT ".$fields." FROM ".$this->table->getTableName();
// apply column aggregation inheritance
foreach($this->table->getInheritanceMap() as $k => $v) {
$where[] = $k." = ?";
$params[] = $v;
}
if( ! empty($where)) {
$query .= " WHERE ".implode(" AND ",$where);
}
$params = array_merge($params, array_values($this->table->getInheritanceMap()));
$coll = $this->table->execute($query, $params, $limit, $offset);
if( ! isset($offset)) {
foreach($coll as $record) {
if(isset($this->reference_field))
$record->rawSet($this->reference_field,$this->reference);
$this->reference->addReference($record);
}
} else {
$i = $offset;
foreach($coll as $record) {
if(isset($this->reference)) {
$this->reference->addReference($record,$i);
} else
$this->data[$i] = $record;
$i++;
}
$this->expanded[$offset] = true;
// check if the fetched collection's record count is smaller
// than the query limit, if so this collection has been expanded to its max size
if(count($coll) < $limit) {
$this->expandable = false;
}
}
return $coll;
}
/**
* @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 record
*/
public function get($key) {
if( ! isset($this->data[$key])) {
$this->expand($key);
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]->rawSet($this->reference_field, $value);
} else {
$this->data[$key]->rawSet($this->reference_field, $this->reference);
}
}
}
return $this->data[$key];
}
/**
* @return array an array containing all primary keys
*/
public function getPrimaryKeys() {
$list = array();
$name = $this->table->getIdentifier();
foreach($this->data as $record):
if(is_array($record) && isset($record[$name])) {
$list[] = $record[$name];
} else {
$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 records 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->rawSet($this->reference_field,$this->reference);
$this->data[$key] = $record;
}
/**
* adds a record to collection
* @param Doctrine_Record $record record to be added
* @param string $key optional key for the record
* @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;
return true;
}
if(isset($this->generator)) {
$key = $this->generator->getIndex($record);
$this->data[$key] = $record;
} else
$this->data[] = $record;
return true;
}
/**
* @param Doctrine_Query $query
* @param integer $key
*/
public function populate(Doctrine_Query $query) {
$name = $this->table->getComponentName();
if($this instanceof Doctrine_Collection_Immediate ||
$this instanceof Doctrine_Collection_Offset) {
$data = $query->getData($name);
if(is_array($data)) {
foreach($data as $k=>$v):
$this->table->setData($v);
$this->add($this->table->getRecord());
endforeach;
}
} elseif($this instanceof Doctrine_Collection_Batch) {
$this->data = $query->getData($name);
if(isset($this->generator)) {
foreach($this->data as $k => $v) {
$record = $this->get($k);
$i = $this->generator->getIndex($record);
$this->data[$i] = $record;
unset($this->data[$k]);
}
}
}
}
/**
* @return Doctrine_Iterator_Normal
*/
public function getNormalIterator() {
return new Doctrine_Iterator_Normal($this);
}
/**
* save
* saves all records
*/
public function save() {
$this->table->getSession()->saveCollection($this);
}
/**
* single shot delete
* deletes all records 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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Collection.class.php");
/**
* Doctrine_Collection_Batch a collection of records,
* 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_Table $table) {
parent::__construct($table);
$this->batchSize = $this->getTable()->getAttribute(Doctrine::ATTR_BATCH_SIZE);
}
/**
* @param integer $batchSize batch size
* @return boolean
*/
public function setBatchSize($batchSize) {
$batchSize = (int) $batchSize;
if($batchSize <= 0)
return false;
$this->batchSize = $batchSize;
return true;
}
/**
* returns the batch size of this collection
*
* @return integer
*/
public function getBatchSize() {
return $this->batchSize;
}
/**
* load
* loads a specified element, by loading the batch the element is part of
*
* @param Doctrine_Record $record record to be loaded
* @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();
$identifier = $this->table->getIdentifier();
foreach($this->data as $key => $v) {
if(is_object($v)) {
if($v->getID() == $id)
break;
} elseif(is_array($v[$identifier])) {
if($v[$identifier] == $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($this->data[$i] instanceof Doctrine_Record)
$id = $this->data[$i]->getID();
elseif(is_array($this->data[$i]))
$id = $this->data[$i][$identifier];
$a[$i] = $id;
endfor;
$c = count($a);
$pk = $this->table->getPrimaryKeys();
$query = $this->table->getQuery()." WHERE ";
$query .= ($c > 1)?$identifier." IN (":$pk[0]." = ";
$query .= substr(str_repeat("?, ",count($a)),0,-2);
$query .= ($c > 1)?") ORDER BY ".$pk[0]." ASC":"";
$stmt = $this->table->getSession()->execute($query,array_values($a));
foreach($a as $k => $id) {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if($row === false)
break;
$this->table->setData($row);
if(is_object($this->data[$k])) {
$this->data[$k]->factoryRefresh($this->table);
} else {
$this->data[$k] = $this->table->getRecord();
}
}
$this->loaded[$x] = true;
return true;
} else {
return false;
}
}
/**
* get
* @param mixed $key the key of the record
* @return object Doctrine_Record record
*/
public function get($key) {
if(isset($this->data[$key])) {
switch(gettype($this->data[$key])):
case "array":
// Doctrine_Record didn't exist in cache
$this->table->setData($this->data[$key]);
$this->data[$key] = $this->table->getProxy();
$this->data[$key]->addCollection($this);
break;
endswitch;
} else {
$this->expand($key);
if( ! isset($this->data[$key]))
$this->data[$key] = $this->table->create();
}
if(isset($this->reference_field))
$this->data[$key]->rawSet($this->reference_field,$this->reference);
return $this->data[$key];
}
/**
* @return Doctrine_Iterator
*/
public function getIterator() {
return new Doctrine_Iterator_Expandable($this);
}
}
?>
<?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_Table $table) {
parent::__construct($table);
}
}
?>
<?php
require_once("Batch.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_Table $table) {
parent::__construct($table);
parent::setBatchSize(1);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Collection.class.php");
/**
* Offset Collection
*/
class Doctrine_Collection_Offset extends Doctrine_Collection {
/**
* @var integer $limit
*/
private $limit;
/**
* @param Doctrine_Table $table
*/
public function __construct(Doctrine_Table $table) {
parent::__construct($table);
$this->limit = $table->getAttribute(Doctrine::ATTR_COLL_LIMIT);
}
/**
* @return integer
*/
public function getLimit() {
return $this->limit;
}
/**
* @return Doctrine_Iterator_Offset
*/
public function getIterator() {
return new Doctrine_Iterator_Expandable($this);
}
}
?>
<?php
/**
* Doctrine_Configurable
* the base for Doctrine_Table, Doctrine_Manager and Doctrine_Session
*
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
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;
/**
* sets a given attribute
*
* @throws Doctrine_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. 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_COLL_LIMIT:
if($value < 1) {
throw new Doctrine_Exception("Collection limit should be a value greater than or equal to 1.");
}
break;
case Doctrine::ATTR_COLL_KEY:
if( ! ($this instanceof Doctrine_Table))
throw new Doctrine_Exception("This attribute can only be set at table level.");
if( ! $this->hasColumn($value))
throw new Doctrine_Exception("Couldn't set collection key attribute. No such column '$value'");
break;
case Doctrine::ATTR_VLD:
break;
case Doctrine::ATTR_CACHE:
if($value != Doctrine::CACHE_SQLITE && $value != Doctrine::CACHE_NONE)
throw new Doctrine_Exception("Unknown cache container. See Doctrine::CACHE_* constants for availible containers.");
break;
default:
throw new Doctrine_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;
}
/**
* returns the value of an attribute
*
* @param integer $attribute
* @return mixed
*/
final public function getAttribute($attribute) {
$attribute = (int) $attribute;
if($attribute < 1 || $attribute > 16)
throw new InvalidKeyException();
if( ! isset($this->attributes[$attribute])) {
if(isset($this->parent))
return $this->parent->getAttribute($attribute);
return null;
}
return $this->attributes[$attribute];
}
/**
* getAttributes
* returns all attributes as an array
*
* @return array
*/
final public function getAttributes() {
return $this->attributes;
}
/**
* sets a parent for this configurable component
* the parent must be configurable component itself
*
* @param Doctrine_Configurable $component
* @return void
*/
final public function setParent(Doctrine_Configurable $component) {
$this->parent = $component;
}
/**
* getParent
* returns the parent of this component
*
* @return Doctrine_Configurable
*/
final public function getParent() {
return $this->parent;
}
}
?>
<?php
class Doctrine_DB extends PDO implements Countable, IteratorAggregate {
/**
* default DSN
*/
const DSN = "mysql://root: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)));
}
public static function getConn($dsn,$username = null, $password = null) {
static $instance;
if( ! isset($instance)) {
$instance = new Doctrine_DB($dsn,$username,$password);
}
return $instance;
}
/**
* @param string $dsn PEAR::DB like DSN
* format: schema://user:password@address/dbname
*/
public static function getConnection($dsn = null) {
static $instance = array();
$md5 = md5($dsn);
if( ! isset($instance[$md5])) {
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[$md5] = new Doctrine_DB($e[0],$e[1],$e[2]);
}
return $instance[$md5];
}
/**
* @param string $query query to be executed
*/
public function query($query) {
try {
$this->queries[] = $query;
$time = microtime();
$stmt = parent::query($query);
$this->exectimes[] = (microtime() - $time);
return $stmt;
} catch(PDOException $e) {
throw $e;
}
}
/**
* @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(array $params = null) {
$time = microtime();
$result = parent::execute($params);
$exectime = (microtime() - $time);
$this->dbh->addExecTime($exectime);
return $result;
}
}
?>
<?php
class Doctrine_DataDict {
private $dbh;
public function __construct(PDO $dbh) {
$manager = Doctrine_Manager::getInstance();
require_once($manager->getRoot()."/adodb-hack/adodb.inc.php");
$this->dbh = $dbh;
$this->dict = NewDataDictionary($dbh);
}
public function metaColumns(Doctrine_Table $table) {
return $this->dict->metaColumns($table->getTableName());
}
public function createTable($tablename, $columns) {
foreach($columns as $name => $args) {
$r[] = $name." ".$this->getADOType($args[0],$args[1])." ".str_replace("|"," ",$args[2]);
}
$r = implode(", ",$r);
$a = $this->dict->createTableSQL($tablename,$r);
$return = true;
foreach($a as $sql) {
try {
$this->dbh->query($sql);
} catch(PDOException $e) {
if($this->dbh->getAttribute(PDO::ATTR_DRIVER_NAME) == "sqlite")
throw $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";
else
return "X2";
break;
case "mbstring":
if($length < 255)
return "C2($length)";
return "X2";
case "clob":
return "XL";
break;
case "d":
case "date":
return "D";
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;
}
}
?>
<?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);
}
}
?>
<?php
require_once("Exception.class.php");
/**
* Doctrine
* the base class of Doctrine framework
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
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;
/**
* collection key attribute
*/
const ATTR_COLL_KEY = 15;
/**
* collection limit attribute
*/
const ATTR_COLL_LIMIT = 16;
/**
* CACHE CONSTANTS
*/
/**
* sqlite cache constant
*/
const CACHE_SQLITE = 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;
/**
* LAZY FETCHING
* mode for offset fetching
*/
const FETCH_OFFSET = 3;
/**
* LAZY OFFSET FETCHING
* mode for lazy offset fetching
*/
const FETCH_LAZY_OFFSET = 4;
/**
* 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;
/**
* returns the doctrine root
*
* @return string
*/
public static function getPath() {
if(! self::$path)
self::$path = dirname(__FILE__);
return self::$path;
}
/**
* loads all runtime classes
*
* @return void
*/
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":
case "Sensei":
case "Iterator":
$a[] = self::$path.DIRECTORY_SEPARATOR.$entry;
break;
default:
if(is_file(self::$path.DIRECTORY_SEPARATOR.$entry) && substr($entry,-4) == ".php") {
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) && substr($entry,-4) == ".php") {
require_once($path.$entry);
}
}
}
}
/**
* simple autoload function
* returns true if the class was loaded, otherwise false
*
* @param string $classname
* @return boolean
*/
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;
}
}
?>
<?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 { }
?>
<?php
class InvalidKeyException extends Exception { }
class InvalidTypeException extends Exception { }
class Doctrine_Exception extends Exception { }
class DQLException extends Doctrine_Exception { }
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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($message = "An error occured in the mapping logic.") {
parent::__construct($message,Doctrine::ERR_MAPPING);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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();
}
}
?>
<?php
require_once("Relation.class.php");
/**
* Foreign Key
*/
class Doctrine_ForeignKey extends Doctrine_Relation { }
?>
<?php
class Doctrine_Identifier {
/**
* constant for unique identifier
*/
const UNIQUE = 0;
/**
* constant for auto_increment identifier
*/
const AUTO_INCREMENT = 1;
/**
* constant for sequence identifier
*/
const SEQUENCE = 2;
/**
* constant for normal identifier
*/
const NORMAL = 3;
/**
* constant for composite identifier
*/
const COMPOSITE = 4;
}
?>
<?php
class Doctrine_IndexGenerator {
/**
* @var string $name
*/
private $name;
/**
* @param string $name
*/
public function __construct($name) {
$this->name = $name;
}
/**
* @param Doctrine_Record $record
* @return mixed
*/
public function getIndex(Doctrine_Record $record) {
$value = $record->get($this->name);
if($value === null)
throw new Doctrine_Exception("Couldn't create collection index. Record field '".$this->name."' was null.");
return $value;
}
}
?>
<?php
/**
* Doctrine_Iterator
* iterates through Doctrine_Collection
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
abstract class Doctrine_Iterator implements Iterator {
/**
* @var Doctrine_Collection $collection
*/
protected $collection;
/**
* @var array $keys
*/
protected $keys;
/**
* @var mixed $key
*/
protected $key;
/**
* @var integer $index
*/
protected $index;
/**
* @var integer $count
*/
protected $count;
/**
* constructor
* @var Doctrine_Collection $collection
*/
public function __construct(Doctrine_Collection $collection) {
$this->collection = $collection;
$this->keys = $this->collection->getKeys();
$this->count = $this->collection->count();
}
/**
* rewinds the iterator
*
* @return void
*/
public function rewind() {
$this->index = 0;
$i = $this->index;
if(isset($this->keys[$i]))
$this->key = $this->keys[$i];
}
/**
* returns the current key
*
* @return integer
*/
public function key() {
return $this->key;
}
/**
* returns the current record
*
* @return Doctrine_Record
*/
public function current() {
return $this->collection->get($this->key);
}
/**
* advances the internal pointer
*
* @return void
*/
public function next() {
$this->index++;
$i = $this->index;
if(isset($this->keys[$i]))
$this->key = $this->keys[$i];
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Iterator.class.php");
class Doctrine_Iterator_Expandable extends Doctrine_Iterator {
public function valid() {
if($this->index < $this->count)
return true;
elseif($this->index == $this->count) {
$coll = $this->collection->expand($this->index);
if($coll instanceof Doctrine_Collection) {
$count = count($coll);
if($count > 0) {
$this->keys = array_merge($this->keys, $coll->getKeys());
$this->count += $count;
return true;
}
}
return false;
}
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Iterator.class.php");
class Doctrine_Iterator_Normal extends Doctrine_Iterator {
/**
* @return boolean whether or not the iteration will continue
*/
public function valid() {
return ($this->index < $this->count);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Iterator.class.php");
class Doctrine_Iterator_Offset extends Doctrine_Iterator {
public function valid() { }
}
?>
<?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_Lib::getSessionStateAsString($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($session->getDBH()->getQueries());
$sum = array_sum($session->getDBH()->getExecTimes());
} elseif($session->getDBH() 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($table->getCache() 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);
}
}
?>
<?php
require_once("Relation.class.php");
/**
* Local Key
*/
class Doctrine_LocalKey extends Doctrine_Relation { }
?>
<?php
require_once("Configurable.class.php");
require_once("EventListener.class.php");
/**
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*
* Doctrine_Manager is the base component of all doctrine based projects.
* It opens and keeps track of all sessions (database connections).
*/
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 the incremented index
*/
private $index = 0;
/**
* @var integer $currIndex the current session index
*/
private $currIndex = 0;
/**
* @var string $root root directory
*/
private $root;
/**
* @var Doctrine_Null $null Doctrine_Null object, used for extremely fast null value checking
*/
private $null;
/**
* constructor
*/
private function __construct() {
$this->root = dirname(__FILE__);
$this->null = new Doctrine_Null;
Doctrine_Record::initNullObject($this->null);
Doctrine_Collection::initNullObject($this->null);
}
/**
* @return Doctrine_Null
*/
final public function getNullObject() {
return $this->null;
}
/**
* setDefaultAttributes
* sets default attributes
*
* @return boolean
*/
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_NONE,
Doctrine::ATTR_BATCH_SIZE => 5,
Doctrine::ATTR_COLL_LIMIT => 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 true;
}
return false;
}
/**
* returns the root directory of Doctrine
*
* @return string
*/
final public function getRoot() {
return $this->root;
}
/**
* getInstance
* returns an instance of this class
* (this class uses the singleton pattern)
*
* @return Doctrine_Manager
*/
final public static function getInstance() {
static $instance;
if( ! isset($instance))
$instance = new self();
return $instance;
}
/**
* openSession
* opens a new session and saves 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
*/
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
* returns all opened sessions
*
* @return array
*/
final public function getSessions() {
return $this->sessions;
}
/**
* setCurrentSession
* sets the current session to $key
*
* @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
* returns the number of opened sessions
*
* @return integer
*/
public function count() {
return count($this->sessions);
}
/**
* getIterator
* returns an ArrayIterator that iterates through all sessions
*
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->sessions);
}
/**
* getCurrentSession
* returns the current session
*
* @throws Doctrine_Session_Exception if there are no open sessions
* @return Doctrine_Session
*/
final public function getCurrentSession() {
$i = $this->currIndex;
if( ! isset($this->sessions[$i]))
throw new Doctrine_Session_Exception();
return $this->sessions[$i];
}
/**
* __toString
* returns a string representation of this object
*
* @return string
*/
public function __toString() {
$r[] = "<pre>";
$r[] = "Doctrine_Manager";
$r[] = "Sessions : ".count($this->sessions);
$r[] = "</pre>";
return implode("\n",$r);
}
}
?>
<?php
/**
* Doctrine_Null
*/
class Doctrine_Null { }
?>
<?php
require_once("Access.class.php");
/**
* Doctrine_Query
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Query extends Doctrine_Access {
/**
* @var array $fetchmodes an array containing all fetchmodes
*/
private $fetchModes = array();
/**
* @var array $tables an array containing all the tables used in the query
*/
private $tables = array();
/**
* @var array $collections an array containing all collections this parser has created/will create
*/
private $collections = array();
private $joined = array();
private $joins = array();
/**
* @var array $data fetched data
*/
private $data = array();
/**
* @var Doctrine_Session $session Doctrine_Session object
*/
private $session;
private $inheritanceApplied = false;
private $aggregate = false;
/**
* @var array $connectors component connectors
*/
private $connectors = array();
/**
* @var array $dql DQL query string parts
*/
protected $dql = array(
"columns" => array(),
"from" => array(),
"join" => array(),
"where" => array(),
"group" => array(),
"having" => array(),
"orderby" => array(),
"limit" => false,
"offset" => false,
);
/**
* @var array $parts SQL query string parts
*/
protected $parts = array(
"columns" => array(),
"from" => array(),
"join" => array(),
"where" => array(),
"group" => array(),
"having" => array(),
"orderby" => array(),
"limit" => false,
"offset" => false,
);
/**
* constructor
*
* @param Doctrine_Session $session
*/
public function __construct(Doctrine_Session $session) {
$this->session = $session;
}
/**
* clear
* resets all the variables
*
* @return void
*/
private function clear() {
$this->fetchModes = array();
$this->tables = array();
$this->parts = array(
"columns" => array(),
"from" => array(),
"join" => array(),
"where" => array(),
"group" => array(),
"having" => array(),
"orderby" => array(),
"limit" => false,
"offset" => false,
);
$this->inheritanceApplied = false;
$this->aggregate = false;
$this->data = array();
$this->connectors = array();
$this->collections = array();
$this->joined = array();
$this->joins = array();
}
/**
* loadFields
* loads fields for a given table and
* constructs a little bit of sql for every field
*
* fields of the tables 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
* @param array $names fields to be loaded (only used in lazy property loading)
* @return void
*/
private function loadFields(Doctrine_Table $table, $fetchmode, array $names) {
$name = $table->getComponentName();
switch($fetchmode):
case Doctrine::FETCH_OFFSET:
$this->limit = $table->getAttribute(Doctrine::ATTR_COLL_LIMIT);
case Doctrine::FETCH_IMMEDIATE:
if( ! empty($names))
throw new Doctrine_Exception("Lazy property loading can only be used with fetching strategies lazy, batch and lazyoffset.");
$names = $table->getColumnNames();
break;
case Doctrine::FETCH_LAZY_OFFSET:
$this->limit = $table->getAttribute(Doctrine::ATTR_COLL_LIMIT);
case Doctrine::FETCH_LAZY:
case Doctrine::FETCH_BATCH:
$names = array_merge($table->getPrimaryKeys(), $names);
break;
default:
throw new Doctrine_Exception("Unknown fetchmode.");
endswitch;
$cname = $table->getComponentName();
$this->fetchModes[$cname] = $fetchmode;
$tablename = $table->getTableName();
$count = count($this->tables);
foreach($names as $name) {
if($count == 0) {
$this->parts["columns"][] = $tablename.".".$name;
} else {
$this->parts["columns"][] = $tablename.".".$name." AS ".$cname."__".$name;
}
}
}
/**
* sets a query part
*
* @param string $name
* @param array $args
* @return void
*/
public function __call($name, $args) {
$name = strtolower($name);
if(isset($this->parts[$name])) {
$method = "parse".ucwords($name);
switch($name):
case "where":
$this->parts[$name] = array($this->$method($args[0]));
break;
case "limit":
case "offset":
if($args[0] == null)
$args[0] = false;
$this->parts[$name] = $args[0];
break;
case "from":
$this->parts['columns'] = array();
$this->joins = array();
$this->tables = array();
$this->fetchModes = array();
default:
$this->parts[$name] = array();
$this->$method($args[0]);
endswitch;
}
return $this;
}
/**
* returns a query part
*
* @param $name query part name
* @return mixed
*/
public function get($name) {
if( ! isset($this->parts[$name]))
return false;
return $this->parts[$name];
}
/**
* sets a query part
*
* @param $name query part name
* @param $value query part value
* @return boolean
*/
public function set($name, $value) {
if(isset($this->parts[$name])) {
$method = "parse".ucwords($name);
switch($name):
case "where":
$this->parts[$name] = array($this->$method($value));
break;
case "limit":
case "offset":
if($value == null)
$value = false;
$this->parts[$name] = $value;
break;
case "from":
$this->parts['columns'] = array();
$this->joins = array();
$this->tables = array();
$this->fetchModes = array();
default:
$this->parts[$name] = array();
$this->$method($value);
endswitch;
return true;
}
return false;
}
/**
* returns the built sql query
*
* @return string
*/
final public function getQuery() {
if(empty($this->parts["columns"]) || empty($this->parts["from"]))
return false;
// build the basic query
$q = "SELECT ".implode(", ",$this->parts["columns"]).
" FROM ";
foreach($this->parts["from"] as $tname => $bool) {
$a[] = $tname;
}
$q .= implode(", ",$a);
if( ! empty($this->parts['join'])) {
foreach($this->parts['join'] as $part) {
$q .= " ".implode(' ', $part);
}
}
$this->applyInheritance();
if( ! empty($this->parts["where"]))
$q .= " WHERE ".implode(" ",$this->parts["where"]);
if( ! empty($this->parts["orderby"]))
$q .= " ORDER BY ".implode(", ",$this->parts["orderby"]);
if( ! empty($this->parts["limit"]) || ! empty($this->offset))
$q = $this->session->modifyLimitQuery($q,$this->parts["limit"],$this->offset);
return $q;
}
/**
* sql delete for mysql
*/
final public function buildDelete() {
if(empty($this->parts["columns"]) || empty($this->parts["from"]))
return false;
$a = array_merge(array_keys($this->parts["from"]),$this->joined);
$q = "DELETE ".implode(", ",$a)." FROM ";
$a = array();
foreach($this->parts["from"] as $tname => $bool) {
$str = $tname;
if(isset($this->parts["join"][$tname]))
$str .= " ".$this->parts["join"][$tname];
$a[] = $str;
}
$q .= implode(", ",$a);
$this->applyInheritance();
if( ! empty($this->parts["where"]))
$q .= " WHERE ".implode(" ",$this->parts["where"]);
if( ! empty($this->parts["orderby"]))
$q .= " ORDER BY ".implode(", ",$this->parts["orderby"]);
if( ! empty($this->parts["limit"]) && ! empty($this->offset))
$q = $this->session->modifyLimitQuery($q,$this->parts["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->tables 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(" AND ",$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;
if($this->parts["where"]) {
$this->parts["where"][] = "AND (".$where.")";
} else {
$this->parts["where"][] = "(".$where.")";
}
return true;
}
/**
* getData
* @param $key the component name
* @return array the data row for the specified component
*/
final public function getData($key) {
if(isset($this->data[$key]) && is_array($this->data[$key]))
return $this->data[$key];
return array();
}
/**
* execute
* executes the dql query and populates all collections
*
* @param string $params
* @return Doctrine_Collection the root collection
*/
public function execute($params = array()) {
$this->data = array();
$this->collections = array();
switch(count($this->tables)):
case 0:
throw new DQLException();
break;
case 1:
$query = $this->getQuery();
$keys = array_keys($this->tables);
$name = $this->tables[$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->tables);
$root = $keys[0];
$stmt = $this->session->execute($query,$params);
$previd = array();
$coll = $this->getCollection($root);
$prev[$root] = $coll;
$array = $this->parseData($stmt);
$colls = array();
foreach($array as $data) {
/**
* remove duplicated data rows and map data into objects
*/
foreach($data as $key => $row) {
if(empty($row))
continue;
$ids = $this->tables[$key]->getIdentifier();
if(is_array($ids)) {
$emptyID = false;
foreach($ids as $id) {
if($row[$id] == null) {
$emptyID = true;
break;
}
}
if($emptyID)
continue;
} else {
if($row[$ids] === null)
continue;
}
$name = $this->tables[$key]->getComponentName();
if( ! isset($previd[$name]))
$previd[$name] = array();
if($previd[$name] !== $row) {
// set internal data
$this->tables[$name]->setData($row);
// initialize a new record
$record = $this->tables[$name]->getRecord();
if($name == $root) {
// add record into root collection
$coll->add($record);
} else {
$pointer = $this->joins[$name];
$fk = $this->tables[$pointer]->getForeignKey($this->tables[$pointer]->getAlias($name));
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::ONE_AGGREGATE:
$last = $prev[$pointer]->getLast();
$last->rawSet($this->connectors[$name]->getLocal(), $record->getID());
$last->initSingleReference($record);
$prev[$name] = $record;
break;
default:
// one-to-many relation or many-to-many relation
$last = $prev[$pointer]->getLast();
if( ! $last->hasReference($name)) {
$prev[$name] = $this->getCollection($name);
$last->initReference($prev[$name],$this->connectors[$name]);
}
$last->addReference($record);
endswitch;
}
}
$previd[$name] = $row;
}
}
return $coll;
endswitch;
}
/**
* parseData
* parses the data returned by PDOStatement
*
* @return array
*/
public function parseData(PDOStatement $stmt) {
$array = array();
$keys = array();
foreach(array_keys($this->tables) as $key) {
$k = strtolower($key);
$keys[$k] = $key;
}
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[$keys[$e[0]]][$e[1]] = $value;
} else {
$data[0][$e[0]] = $value;
}
unset($data[$key]);
endforeach;
$array[] = $data;
endwhile;
$stmt->closeCursor();
return $array;
}
/**
* returns a Doctrine_Table for given name
*
* @param string $name component name
* @return Doctrine_Table
*/
public function getTable($name) {
return $this->tables[$name];
}
/**
* getCollection
*
* @parma string $name component name
* @param integer $index
*/
private function getCollection($name) {
$table = $this->session->getTable($name);
switch($this->fetchModes[$name]):
case Doctrine::FETCH_BATCH:
$coll = new Doctrine_Collection_Batch($table);
break;
case Doctrine::FETCH_LAZY:
$coll = new Doctrine_Collection_Lazy($table);
break;
case Doctrine::FETCH_OFFSET:
$coll = new Doctrine_Collection_Offset($table);
break;
case Doctrine::FETCH_IMMEDIATE:
$coll = new Doctrine_Collection_Immediate($table);
break;
case Doctrine::FETCH_LAZY_OFFSET:
$coll = new Doctrine_Collection_LazyOffset($table);
break;
endswitch;
$coll->populate($this);
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->tables);
$query = $this->getQuery();
$stmt = $this->tables[$keys[0]]->getSession()->select($query,$this->parts["limit"],$this->offset);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if(count($data) == 1) {
return current($data);
} else {
return $data;
}
} else {
return $this->execute($params);
}
}
/**
* DQL PARSER
*
* @param string $query DQL query
* @return void
*/
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(strtoupper($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->parts["limit"] = trim($part);
break;
case "OFFSET":
$this->offset = trim($part);
break;
endswitch;
}
}
/**
* 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, false);
$tname = $this->tables[$name]->getTableName();
$r = $tname.".".$field;
if(isset($e[1]))
$r .= " ".$e[1];
}
$this->parts["orderby"][] = $r;
}
}
/**
* 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->parts["columns"][] = $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);
$table = $this->load($reference);
}
}
/**
* returns Doctrine::FETCH_* constant
*
* @param string $mode
* @return integer
*/
private function parseFetchMode($mode) {
switch(strtolower($mode)):
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;
case "o":
case "offset":
$fetchmode = Doctrine::FETCH_OFFSET;
break;
case "lo":
case "lazyoffset":
$fetchmode = Doctrine::FETCH_LAZYOFFSET;
default:
throw new DQLException("Unknown fetchmode '$mode'. The availible fetchmodes are 'i', 'b' and 'l'.");
endswitch;
return $fetchmode;
}
/**
* 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(" AND ",$ret);
} else {
$parts = self::bracketExplode($str," || ","(",")");
if(count($parts) > 1) {
$ret = array();
foreach($parts as $part) {
$ret[] = $this->parseWhere($part);
}
$r = implode(" OR ",$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 AND age > 18) AND email LIKE 'John@example.com'
* now exploding $str with parameters $d = ' AND ', $e1 = '(' and $e2 = ')'
* would return an array:
* array("(age < 20 AND 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
*
* @param string $where
*/
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);
if(count($a) > 1)
$objTable = $this->tables[$a[0]]->getForeignKey(end($a))->getTable();
else
$objTable = $this->session->getTable(end($a));
$where = $objTable->getTableName().".".$field." ".$operator." ".$value;
if(count($a) > 1 && isset($a[1])) {
$root = $a[0];
$fk = $this->tables[$root]->getForeignKey($a[1]);
if($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
switch($fk->getType()):
case Doctrine_Relation::ONE_AGGREGATE:
case Doctrine_Relation::ONE_COMPOSITE:
break;
case Doctrine_Relation::MANY_AGGREGATE:
case Doctrine_Relation::MANY_COMPOSITE:
// subquery needed
$where = $objTable->getComponentName().".".$field." ".$operator." ".$value;
$b = $fk->getTable()->getComponentName();
$graph = new Doctrine_Query($this->session);
$graph->parseQuery("FROM $b-l WHERE $where");
$where = $this->tables[$root]->getTableName().".".$this->tables[$root]->getIdentifier()." IN (SELECT ".$fk->getLocal()." FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." IN (".$graph->getQuery()."))";
break;
endswitch;
} else
$this->load($reference, false);
} else
$this->load($reference, false);
}
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, $loadFields = true) {
$e = preg_split("/[.:]/",$path);
$index = 0;
foreach($e as $key => $fullname) {
try {
$e2 = preg_split("/[-(]/",$fullname);
$name = $e2[0];
if($key == 0) {
$table = $this->session->getTable($name);
$tname = $table->getTableName();
$this->parts["from"][$tname] = true;
} else {
$index += strlen($e[($key - 1)]) + 1;
// the mark here is either '.' or ':'
$mark = substr($path,($index - 1),1);
$fk = $table->getForeignKey($name);
$name = $fk->getTable()->getComponentName();
$tname = $table->getTableName();
$tname2 = $fk->getTable()->getTableName();
$this->connectors[$name] = $fk;
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($mark):
case ":":
$this->parts["join"][$tname][$tname2] = "INNER JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
break;
case ".":
$this->parts["join"][$tname][$tname2] = "LEFT JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
break;
endswitch;
$c = $table->getComponentName();
$this->joins[$name] = $c;
} elseif($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
switch($fk->getType()):
case Doctrine_Relation::ONE_AGGREGATE:
case Doctrine_Relation::ONE_COMPOSITE:
break;
case Doctrine_Relation::MANY_AGGREGATE:
case Doctrine_Relation::MANY_COMPOSITE:
//$this->addWhere("SELECT ".$fk->getLocal()." FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." IN (SELECT ".$fk->getTable()->getComponentName().")");
$this->parts["from"][$tname] = true;
break;
endswitch;
}
$table = $fk->getTable();
}
if( ! isset($this->tables[$name])) {
$this->tables[$name] = $table;
if($loadFields && ! $this->aggregate) {
$fields = array();
if(strpos($fullname, "-") === false) {
$fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE);
if(isset($e2[1]))
$fields = explode(",",substr($e2[1],0,-1));
} else {
if(isset($e2[1])) {
$fetchmode = $this->parseFetchMode($e2[1]);
} else
$fetchmode = $table->getAttribute(Doctrine::ATTR_FETCHMODE);
if(isset($e2[2]))
$fields = explode(",",substr($e2[2],0,-1));
}
$this->loadFields($table, $fetchmode, $fields);
}
}
} catch(Exception $e) {
throw new DQLException($e->getMessage(),$e->getCode());
}
}
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.php");
class Doctrine_Query_Exception extends Doctrine_Exception { }
?>
<?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 record 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 record
* @see STATE_* constants
*/
private $state;
/**
* @var array $collections the collections this record 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 Doctrine_Null $nullObject a Doctrine_Null object used for extremely fast
* SQL null value testing
*/
private static $null;
/**
* @var integer $oid object identifier
*/
private $oid;
/**
* 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++;
$keys = $this->table->getPrimaryKeys();
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();
// get the column count
$count = count($this->data);
// clean data array
$cols = $this->cleanData();
$this->prepareIdentifiers($exists);
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($count < $this->table->getColumnCount()) {
$this->state = Doctrine_Record::STATE_PROXY;
}
// listen the onLoad event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onLoad($this);
}
$this->table->getRepository()->add($this);
}
}
/**
* initNullObject
*/
public static function initNullObject(Doctrine_Null $null) {
self::$null = $null;
}
/**
* setUp
* implemented by child classes
*/
public function setUp() { }
/**
* return the object identifier
*
* @return integer
*/
public function getOID() {
return $this->oid;
}
/**
* 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] = self::$null;
} else {
$cols++;
$this->data[$name] = $tmp[$name];
}
}
return $cols;
}
/**
* prepares identifiers
*
* @return void
*/
private function prepareIdentifiers($exists = true) {
switch($this->table->getIdentifierType()):
case Doctrine_Identifier::AUTO_INCREMENT:
case Doctrine_Identifier::SEQUENCE:
if($exists) {
$name = $this->table->getIdentifier();
if(isset($this->data[$name]))
$this->id = $this->data[$name];
unset($this->data[$name]);
}
break;
case Doctrine_Identifier::COMPOSITE:
$names = $this->table->getIdentifier();
$this->id = array();
foreach($names as $name) {
if($this->data[$name] === self::$null)
$this->id[$name] = null;
else
$this->id[$name] = $this->data[$name];
}
break;
endswitch;
}
/**
* this method is automatically called when this Doctrine_Record is serialized
*
* @return array
*/
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);
foreach($this->data as $k=>$v) {
if($v instanceof Doctrine_Record)
$this->data[$k] = array();
}
return array_keys(get_object_vars($this));
}
/**
* unseralize
* this method is automatically called everytime a Doctrine_Record object is unserialized
*
* @return void
*/
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->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
* whether or not this record is part of a collection
*
* @return boolean
*/
final public function hasCollections() {
return (! empty($this->collections));
}
/**
* getState
* returns the current state of the object
*
* @see Doctrine_Record::STATE_* constants
* @return integer
*/
final public function getState() {
return $this->state;
}
/**
* refresh
* refresh internal data from the database
*
* @return boolean
*/
final public function refresh() {
$id = $this->getID();
if( ! is_array($id))
$id = array($id);
if(empty($id))
return false;
$id = array_values($id);
$query = $this->table->getQuery()." WHERE ".implode(" = ? && ",$this->table->getPrimaryKeys())." = ?";
$this->data = $this->table->getSession()->execute($query,$id)->fetch(PDO::FETCH_ASSOC);
$this->modified = array();
$this->cleanData();
$this->prepareIdentifiers();
$this->state = Doctrine_Record::STATE_CLEAN;
return true;
}
/**
* factoryRefresh
* @throws Doctrine_Exception
* @return void
*/
final public function factoryRefresh() {
$data = $this->table->getData();
$id = $this->id;
$this->prepareIdentifiers();
if($this->id != $id)
throw new Doctrine_Refresh_Exception();
$this->data = $data;
$this->cleanData();
$this->state = Doctrine_Record::STATE_CLEAN;
$this->modified = array();
}
/**
* 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 a 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 null (= it is the Doctrine_Null object located in self::$null)
if($this->data[$name] === self::$null) {
// no use trying to load the data from database if the Doctrine_Record is not a proxy
if($this->state == Doctrine_Record::STATE_PROXY) {
if( ! empty($this->collections)) {
foreach($this->collections as $collection) {
$collection->load($this);
}
} else {
$this->refresh();
}
$this->state = Doctrine_Record::STATE_CLEAN;
}
if($this->data[$name] === self::$null)
return null;
}
return $this->data[$name];
}
if($name == $this->table->getIdentifier())
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;
if(isset($this->data[$name])) {
if($this->data[$name] === self::$null) {
if($this->data[$name] !== $value) {
switch($this->state):
case Doctrine_Record::STATE_CLEAN:
$this->state = Doctrine_Record::STATE_DIRTY;
break;
case Doctrine_Record::STATE_TCLEAN:
$this->state = Doctrine_Record::STATE_TDIRTY;
endswitch;
}
}
if($this->state == Doctrine_Record::STATE_TCLEAN)
$this->state = Doctrine_Record::STATE_TDIRTY;
$this->data[$name] = $value;
$this->modified[] = $name;
}
}
/**
* 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])) {
if($value instanceof Doctrine_Record) {
$id = $value->getID();
if( ! empty($id))
$value = $value->getID();
}
$old = $this->get($name);
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);
// one-to-many or one-to-one relation
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($fk->getType()):
case Doctrine_Relation::MANY_COMPOSITE:
case Doctrine_Relation::MANY_AGGREGATE:
// one-to-many relation found
if( ! ($value instanceof Doctrine_Collection))
throw new Doctrine_Exception("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_Relation::ONE_COMPOSITE:
case Doctrine_Relation::ONE_AGGREGATE:
// one-to-one relation found
if( ! ($value instanceof Doctrine_Record))
throw new Doctrine_Exception("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Record when setting one-to-one references.");
if($fk->getLocal() == $this->table->getIdentifier()) {
$this->references[$name]->set($fk->getForeign(),$this);
} else {
$this->set($fk->getLocal(),$value);
}
break;
endswitch;
} elseif($fk instanceof Doctrine_Association) {
// join table relation found
if( ! ($value instanceof Doctrine_Collection))
throw new Doctrine_Exception("Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Collection when setting one-to-many references.");
}
$this->references[$name] = $value;
}
}
/**
* __isset
*
* @param string $name
* @return boolean
*/
public function __isset($name) {
if(isset($this->data[$name]))
return true;
if(isset($this->references[$name]))
return true;
return false;
}
/**
* @param string $name
* @return void
*/
public function __unset($name) {
if(isset($this->data[$name]))
$this->data[$name] = array();
// todo: what to do with references ?
}
/**
* 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();
$alias = $this->table->getAlias($table->getComponentName());
if(isset($this->references[$alias])) {
$obj = $this->references[$alias];
$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;
}
/**
* returns an array of modified fields and values with data preparation
* adds column aggregation inheritance and converts Records into primary key values
*
* @return array
*/
final public function getPrepared() {
$a = array();
foreach($this->table->getInheritanceMap() as $k => $v) {
$this->set($k,$v);
}
foreach($this->modified as $k => $v) {
if($this->data[$v] instanceof Doctrine_Record) {
$this->data[$v] = $this->data[$v]->getID();
}
$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();
$alias = $this->table->getAlias($name);
if($fk instanceof Doctrine_Association) {
switch($fk->getType()):
case Doctrine_Relation::MANY_COMPOSITE:
break;
case Doctrine_Relation::MANY_AGGREGATE:
$asf = $fk->getAssociationFactory();
if(isset($this->references[$alias])) {
$new = $this->references[$alias];
if( ! isset($this->originals[$alias])) {
$this->loadReference($alias);
}
$r = $this->getRelationOperations($alias,$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[$alias] = clone $this->references[$alias];
}
break;
endswitch;
} elseif($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
if(isset($this->originals[$alias]) && $this->originals[$alias]->getID() != $this->references[$alias]->getID())
$this->originals[$alias]->delete();
break;
case Doctrine_Relation::MANY_COMPOSITE:
if(isset($this->references[$alias])) {
$new = $this->references[$alias];
if( ! isset($this->originals[$alias]))
$this->loadReference($alias);
$r = $this->getRelationOperations($alias,$new);
foreach($r["delete"] as $record) {
$record->delete();
}
$this->originals[$alias] = clone $this->references[$alias];
}
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(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
*/
public function delete() {
$this->table->getSession()->delete($this);
}
/**
* returns a copy of this object
* @return DAO
*/
public function copy() {
return $this->table->create($this->data);
}
/**
* @param integer $id
* @return void
*/
final public function setID($id = false) {
if($id === false) {
$this->id = false;
$this->cleanData();
$this->state = Doctrine_Record::STATE_TCLEAN;
$this->modified = array();
} elseif($id === true) {
$this->prepareIdentifiers(false);
$this->state = Doctrine_Record::STATE_CLEAN;
$this->modified = array();
} else {
$this->id = $id;
$this->state = Doctrine_Record::STATE_CLEAN;
$this->modified = array();
}
}
/**
* return the primary key(s) this object is pointing at
* @return mixed id
*/
final public function getID() {
return $this->id;
}
/**
* getLast
* this method is used internally be Doctrine_Query
* it is needed to provide compatibility between
* records and collections
*
* @return Doctrine_Record
*/
public function getLast() {
return $this;
}
/**
* hasRefence
* @param string $name
* @return boolean
*/
public function hasReference($name) {
return isset($this->references[$name]);
}
/**
* initalizes a one-to-one relation
*
* @param Doctrine_Record $record
* @param Doctrine_Relation $connector
* @return void
*/
public function initSingleReference(Doctrine_Record $record) {
$name = $this->table->getAlias($record->getTable()->getComponentName());
$this->references[$name] = $record;
}
/**
* initalizes a one-to-many / many-to-many relation
*
* @param Doctrine_Collection $coll
* @param Doctrine_Relation $connector
* @return void
*/
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
$name = $this->table->getAlias($coll->getTable()->getComponentName());
$coll->setReference($this, $connector);
$this->references[$name] = $coll;
$this->originals[$name] = clone $coll;
}
/**
* addReference
* @param Doctrine_Record $record
* @param mixed $key
* @return void
*/
public function addReference(Doctrine_Record $record, $key = null) {
$name = $this->table->getAlias($record->getTable()->getComponentName());
$this->references[$name]->add($record, $key);
$this->originals[$name]->add($record, $key);
}
/**
* 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();
$local = $fk->getLocal();
$foreign = $fk->getForeign();
$graph = $table->getQueryObject();
$type = $fk->getType();
switch($this->getState()):
case Doctrine_Record::STATE_TDIRTY:
case Doctrine_Record::STATE_TCLEAN:
if($type == Doctrine_Relation::ONE_COMPOSITE ||
$type == Doctrine_Relation::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:
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::ONE_AGGREGATE:
// ONE-TO-ONE
$id = $this->get($local);
if($fk instanceof Doctrine_LocalKey) {
if(empty($id)) {
$this->references[$name] = $table->create();
$this->set($fk->getLocal(),$this->references[$name]);
} else {
try {
$this->references[$name] = $table->find($id);
} catch(Doctrine_Find_Exception $e) {
}
}
} elseif ($fk instanceof Doctrine_ForeignKey) {
if(empty($id)) {
$this->references[$name] = $table->create();
$this->references[$name]->set($fk->getForeign(), $this);
} else {
$dql = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$fk->getForeign()." = ?";
$coll = $graph->query($dql, array($id));
$this->references[$name] = $coll[0];
$this->references[$name]->set($fk->getForeign(), $this);
}
}
break;
default:
// ONE-TO-MANY
if($fk instanceof Doctrine_ForeignKey) {
$id = $this->get($local);
$query = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$fk->getForeign()." = ?";
$coll = $graph->query($query,array($id));
$this->references[$name] = $coll;
$this->references[$name]->setReference($this, $fk);
$this->originals[$name] = clone $coll;
} elseif($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
$query = "SELECT ".$foreign." FROM ".$asf->getTableName()." WHERE ".$local." = ?";
$graph = new Doctrine_Query($table->getSession());
$query = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$table->getIdentifier()." IN ($query)";
$coll = $graph->query($query, array($this->getID()));
$this->references[$name] = $coll;
$this->originals[$name] = clone $coll;
}
endswitch;
break;
endswitch;
}
/**
* binds One-to-One composite relation
*
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function ownsOne($componentName,$foreignKey, $localKey = null) {
$this->table->bind($componentName,$foreignKey,Doctrine_Relation::ONE_COMPOSITE, $localKey);
}
/**
* binds One-to-Many composite relation
*
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function ownsMany($componentName,$foreignKey, $localKey = null) {
$this->table->bind($componentName,$foreignKey,Doctrine_Relation::MANY_COMPOSITE, $localKey);
}
/**
* binds One-to-One aggregate relation
*
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function hasOne($componentName,$foreignKey, $localKey = null) {
$this->table->bind($componentName,$foreignKey,Doctrine_Relation::ONE_AGGREGATE, $localKey);
}
/**
* binds One-to-Many aggregate relation
*
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function hasMany($componentName,$foreignKey, $localKey = null) {
$this->table->bind($componentName,$foreignKey,Doctrine_Relation::MANY_AGGREGATE, $localKey);
}
/**
* setInheritanceMap
* @param array $inheritanceMap
* @return void
*/
final public function setInheritanceMap(array $inheritanceMap) {
$this->table->setInheritanceMap($inheritanceMap);
}
/**
* setPrimaryKey
* @param mixed $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
* sets a column definition
*
* @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->setColumn($name, $type, $length, $options);
}
/**
* returns a string representation of this object
*/
public function __toString() {
return Doctrine_Lib::getRecordAsString($this);
}
}
?>
<?php
/**
* Doctrine_Relation
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
class Doctrine_Relation {
/**
* RELATION CONSTANTS
*/
/**
* 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 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;
}
/**
* @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);
}
}
?>
<?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();
}
}
?>
<?php
class Sensei_Group extends Doctrine_Record { }
class Sensei_Company extends Sensei_Group { }
class Sensei_User extends Doctrine_Record { }
class Sensei_Customer extends Sensei_User { }
class Sensei_Entity extends Doctrine_Record {
/**
* setTableDefinition
* initializes column definitions
*
* @return void
*/
public function setTableDefinition() {
$this->hasColumn("loginname","string",32,"unique");
$this->hasColumn("password","string",32);
}
}
class Sensei_Variable extends Doctrine_Record {
/**
* setUp
* initializes relations and options
*
* @return void
*/
public function setUp() {
//$this->setAttribute(Doctrine::ATTR_COLL_KEY, "name");
}
/**
* setTableDefinition
* initializes column definitions
*
* @return void
*/
public function setTableDefinition() {
$this->hasColumn("name","string",50,"unique");
$this->hasColumn("value","string",10000);
$this->hasColumn("session_id","integer");
}
}
class Sensei_Session extends Doctrine_Record {
/**
* setUp
* initializes relations and options
*
* @return void
*/
public function setUp() {
$this->ownsMany("Sensei_Variable","Sensei_Variable.session_id");
$this->hasOne("Sensei_Entity","Sensei_Session.entity_id");
}
/**
* setTableDefinition
* initializes column definitions
*
* @return void
*/
public function setTableDefinition() {
$this->hasColumn("session_id","string",32);
$this->hasColumn("logged_in","integer",1);
$this->hasColumn("entity_id","integer");
$this->hasColumn("user_agent","string",200);
$this->hasColumn("updated","integer");
$this->hasColumn("created","integer");
}
}
class Sensei_Exception extends Exception { }
class Sensei extends Doctrine_Access {
const ATTR_LIFESPAN = 0;
/**
* @var Sensei_Session $record
*/
private $record;
/**
* @var Doctrine_Session $session
*/
private $session;
/**
* @var Doctrine_Table $table
*/
private $table;
/**
* @var array $attributes
*/
private $attributes = array();
/**
* @var Doctrine_Collection $vars
*/
private $vars;
public function __construct() {
if(headers_sent())
throw new Sensei_Exception("Headers already sent. Couldn't initialize session.");
$this->session = Doctrine_Manager::getInstance()->getCurrentSession();
$this->table = $this->session->getTable("Sensei_session");
$this->init();
$this->gc(1);
if( ! isset($_SESSION))
session_start();
}
/**
* getRecord
*/
public function getRecord() {
return $this->record;
}
/**
* init
*/
private function init() {
session_set_save_handler(
array($this,"open"),
array($this,"close"),
array($this,"read"),
array($this,"write"),
array($this,"destroy"),
array($this,"gc")
);
}
/**
* @param string $username
* @param string $password
* @return boolean
*/
public function login($username,$password) {
$coll = $this->session->query("FROM Sensei_Entity WHERE Sensei_Entity.loginname = ? && Sensei_Entity.password = ?",array($username,$password));
if(count($coll) > 0) {
$this->record->logged_in = 1;
$this->record->entity_id = $coll[0]->getID();
$this->record->save();
return true;
}
return false;
}
/**
* logout
* @return boolean
*/
public function logout() {
if( $this->record->logged_in == true) {
$this->record->logged_in = 0;
$this->record->entity_id = 0;
return true;
} else {
return false;
}
}
/**
* returns a session variable
*
* @param mixed $name
* @return mixed
*/
public function get($name) {
foreach($this->vars as $var) {
if($var->name == $name) {
return $var->value;
}
}
}
/**
* sets a session variable
* returns true on success, false on failure
*
* @param mixed $name
* @param mixed $value
* @return boolean
*/
public function set($name,$value) {
foreach($this->vars as $var) {
if($var->name == $name) {
$var->value = $value;
return true;
}
}
return false;
}
/**
* @param integer $attr
* @param mixed $value
*/
public function setAttribute($attr, $value) {
switch($attr):
case Sensei::ATTR_LIFESPAN:
break;
default:
throw new Sensei_Exception("Unknown attribute");
endswitch;
$this->attributes[$attr] = $value;
}
/**
* @return boolean
*/
private function open($save_path,$session_name) {
return true;
}
/**
* @return boolean
*/
public function close() {
return true;
}
/**
* always returns an empty string
*
* @param string $id php session identifier
* @return string
*/
private function read($id) {
$coll = $this->session->query("FROM Sensei_Session, Sensei_Session.Sensei_Variable WHERE Sensei_Session.session_id = ?",array($id));
$this->record = $coll[0];
$this->record->user_agent = $_SERVER['HTTP_USER_AGENT'];
$this->record->updated = time();
$this->record->session_id = $id;
$this->vars = $this->record->Sensei_Variable;
if($this->record->getState() == Doctrine_Record::STATE_TDIRTY) {
$this->record->created = time();
$this->record->save();
}
return "";
}
/**
* @return boolean
*/
public function write($id,$sess_data) {
return true;
}
/**
* @param string $id php session identifier
* @return Doctrine_Record
*/
private function destroy($id) {
$this->record->delete();
return $this->record;
}
/**
* @param integer $maxlifetime
*/
private function gc($maxlifetime) {
return true;
}
/**
* flush
* makes all changes persistent
*/
public function flush() {
$this->record->save();
}
/**
* destructor
*/
public function __destruct() {
$this->flush();
}
}
?>
<?php
require_once("Configurable.class.php");
require_once("Record.class.php");
/**
* Doctrine_Session
*
* @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;
/**
* @see Doctrine_Session::STATE_* constants
* @var boolean $state the current state of the session
*/
private $state = 0;
/**
* @var integer $transaction_level the nesting level of transactions, used by transaction methods
*/
private $transaction_level = 0;
/**
* @var PDO $cacheHandler cache handler
*/
private $cacheHandler;
/**
* @var array $tables an array containing all the initialized Doctrine_Table objects
* keys representing Doctrine_Table component names and values as Doctrine_Table objects
*/
protected $tables = array();
/**
* @var Doctrine_Validator $validator transaction validator
*/
protected $validator;
/**
* @var array $update two dimensional pending update list, the records in
* this list will be updated when transaction is committed
*/
protected $update = array();
/**
* @var array $insert two dimensional pending insert list, the records in
* this list will be inserted when transaction is committed
*/
protected $insert = array();
/**
* @var array $delete two dimensional pending delete list, the records in
* this list will be deleted when transaction is committed
*/
protected $delete = array();
/**
* 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);
switch($this->getAttribute(Doctrine::ATTR_CACHE)):
case Doctrine::CACHE_SQLITE:
$dir = $this->getAttribute(Doctrine::ATTR_CACHE_DIR).DIRECTORY_SEPARATOR;
$dsn = "sqlite:".$dir."data.cache";
$this->cacheHandler = Doctrine_DB::getConn($dsn);
$this->cacheHandler->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->cacheHandler->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
break;
endswitch;
$this->getAttribute(Doctrine::ATTR_LISTENER)->onOpen($this);
}
public function getCacheHandler() {
return $this->cacheHandler;
}
/**
* returns the state of this session
*
* @see Doctrine_Session::STATE_* constants
* @return integer the session state
*/
public function getState() {
return $this->state;
}
/**
* returns the manager that created this session
*
* @return Doctrine_Manager
*/
public function getManager() {
return $this->getParent();
}
/**
* returns the database handler of which this session uses
*
* @return object PDO the database handler
*/
public function getDBH() {
return $this->dbh;
}
/**
* query
* queries the database with Doctrine Query Language
*
* @param string $query DQL query
* @param array $params query parameters
*/
final public function query($query,array $params = array()) {
$parser = new Doctrine_Query($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);
}
/**
* @param string $query sql query
* @param array $params query parameters
*
* @return PDOStatement
*/
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);
}
}
/**
* whether or not this session has table $name initialized
*
* @param $mixed $name
* @return boolean
*/
public function hasTable($name) {
return isset($this->tables[$name]);
}
/**
* returns a table object for given component name
*
* @param string $name component name
* @return object Doctrine_Table
*/
public function getTable($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);
}
}
/**
* returns an array of all initialized tables
*
* @return array
*/
public function getTables() {
return $this->tables;
}
/**
* returns an iterator that iterators through all
* initialized table objects
*
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->tables);
}
/**
* returns the count of initialized table objects
*
* @return integer
*/
public function count() {
return count($this->tables);
}
/**
* @param $objTable a Doctrine_Table object to be added into 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;
}
/**
* creates a record
*
* 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
* builds a flush tree that is used in transactions
*
* @return array
*/
public function buildFlushTree(array $tables) {
$tree = array();
foreach($tables as $k => $table) {
$k = $k.$table;
if( ! ($table instanceof Doctrine_Table))
$table = $this->getTable($table);
$nm = $table->getComponentName();
$index = array_search($nm,$tree);
if($index === false) {
$tree[] = $nm;
$index = max(array_keys($tree));
//print "$k -- adding <b>$nm</b>...<br \>";
}
$rels = $table->getForeignKeys();
// group relations
foreach($rels as $key => $rel) {
if($rel instanceof Doctrine_ForeignKey) {
unset($rels[$key]);
array_unshift($rels, $rel);
}
}
foreach($rels as $rel) {
$name = $rel->getTable()->getComponentName();
$index2 = array_search($name,$tree);
$type = $rel->getType();
// skip self-referenced relations
if($name === $nm)
continue;
if($rel instanceof Doctrine_ForeignKey) {
if($index2 !== false) {
if($index2 >= $index)
continue;
unset($tree[$index]);
array_splice($tree,$index2,0,$nm);
$index = $index2;
//print "$k -- pushing $nm into $index2...<br \>";
} else {
$tree[] = $name;
//print "$k -- adding $nm :$name...<br>";
}
} elseif($rel instanceof Doctrine_LocalKey) {
if($index2 !== false) {
if($index2 <= $index)
continue;
unset($tree[$index2]);
array_splice($tree,$index,0,$name);
//print "$k -- pushing $name into <b>$index</b>...<br \>";
} else {
//array_splice($tree, $index, 0, $name);
array_unshift($tree,$name);
$index++;
//print "$k -- pushing <b>$name</b> into 0...<br \>";
}
} elseif($rel instanceof Doctrine_Association) {
$t = $rel->getAssociationFactory();
$n = $t->getComponentName();
if($index2 !== false)
unset($tree[$index2]);
array_splice($tree,$index, 0,$name);
$index++;
$index3 = array_search($n,$tree);
if($index3 !== false) {
if($index3 >= $index)
continue;
unset($tree[$index]);
array_splice($tree,$index3,0,$n);
$index = $index2;
//print "$k -- pushing $nm into $index3...<br \>";
} else {
$tree[] = $n;
//print "$k -- adding $nm :$name...<br>";
}
}
//print_r($tree);
}
//print_r($tree);
}
return array_values($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
* saves all the records from all tables
*
* @return void
*/
private function saveAll() {
$tree = $this->buildFlushTree($this->tables);
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 all repositories
*
* @return void
*/
public function clear() {
foreach($this->tables as $k => $table) {
$table->getRepository()->evictAll();
$table->clear();
}
$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
*/
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();
try {
$this->bulkInsert();
$this->bulkUpdate();
$this->bulkDelete();
if($this->getAttribute(Doctrine::ATTR_VLD)) {
if($this->validator->hasErrors()) {
$this->rollback();
throw new Doctrine_Validator_Exception($this->validator);
}
}
} catch(PDOException $e) {
$this->rollback();
throw new Doctrine_Exception($e->getMessage());
}
$this->dbh->commit();
$this->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionCommit($this);
$this->delete = 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 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() {
if(empty($this->insert))
return false;
foreach($this->insert as $name => $inserts) {
if( ! isset($inserts[0]))
continue;
$record = $inserts[0];
$table = $record->getTable();
$seq = $table->getSequenceName();
$increment = false;
$keys = $table->getPrimaryKeys();
$id = null;
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
$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);
$this->insert($record);
if($increment) {
if($k == 0) {
// record uses auto_increment column
$id = $table->getMaxIdentifier();
}
$record->setID($id);
$id++;
} else
$record->setID(true);
// listen the onInsert event
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onInsert($record);
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
}
}
$this->insert = array();
return true;
}
/**
* returns maximum identifier values
*
* @param array $names an array of component names
* @return array
*/
public function getMaximumValues(array $names) {
$values = array();
foreach($names as $name) {
$table = $this->tables[$name];
$keys = $table->getPrimaryKeys();
$tablename = $table->getTableName();
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
// record uses auto_increment column
$sql = "SELECT MAX(".$table->getIdentifier().") FROM ".$tablename;
$stmt = $this->dbh->query($sql);
$data = $stmt->fetch(PDO::FETCH_NUM);
$values[$tablename] = $data[0];
$stmt->closeCursor();
}
}
return $values;
}
/**
* bulkUpdate
* updates all objects in the pending update list
*
* @return void
*/
public function bulkUpdate() {
foreach($this->update as $name => $updates) {
$ids = array();
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);
$ids[] = $record->getID();
}
if(isset($record))
$record->getTable()->getCache()->deleteMultiple($ids);
}
$this->update = array();
}
/**
* bulkDelete
* deletes all records from the pending delete list
*
* @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(false);
}
if($record instanceof Doctrine_Record) {
$table = $record->getTable();
$params = substr(str_repeat("?, ",count($ids)),0,-2);
$query = "DELETE FROM ".$record->getTable()->getTableName()." WHERE ".$table->getIdentifier()." IN(".$params.")";
$this->execute($query,$ids);
$record->getTable()->getCache()->deleteMultiple($ids);
}
}
$this->delete = array();
}
/**
* saves a collection
*
* @param Doctrine_Collection $coll
* @return void
*/
public function saveCollection(Doctrine_Collection $coll) {
$this->beginTransaction();
foreach($coll as $key=>$record):
$record->save();
endforeach;
$this->commit();
}
/**
* deletes all records from collection
*
* @param Doctrine_Collection $coll
* @return void
*/
public function deleteCollection(Doctrine_Collection $coll) {
$this->beginTransaction();
foreach($coll as $k=>$record) {
$record->delete();
}
$this->commit();
}
/**
* saves the given record
*
* @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;
}
/**
* saves all related records to $record
*
* @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_Relation::ONE_COMPOSITE:
case Doctrine_Relation::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;
}
/**
* updates the given record
*
* @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) {
switch($value->getState()):
case Doctrine_Record::STATE_TCLEAN:
case Doctrine_Record::STATE_TDIRTY:
$record->save();
default:
$array[$name] = $value->getID();
$record->set($name, $value->getID());
endswitch;
}
endforeach;
if(isset($this->validator)) {
if( ! $this->validator->validateRecord($record)) {
return false;
}
}
$params = array_values($array);
$id = $record->getID();
if( ! is_array($id))
$id = array($id);
$id = array_values($id);
$params = array_merge($params, $id);
$sql = "UPDATE ".$record->getTable()->getTableName()." SET ".implode(", ",$set)." WHERE ".implode(" = ? && ",$record->getTable()->getPrimaryKeys())." = ?";
$stmt = $this->dbh->prepare($sql);
$stmt->execute($params);
$record->setID(true);
return true;
}
/**
* inserts a record into database
*
* @param Doctrine_Record $record
* @return boolean
*/
private function insert(Doctrine_Record $record) {
$array = $record->getPrepared();
if(empty($array))
return false;
$seq = $record->getTable()->getSequenceName();
if( ! empty($seq)) {
$id = $this->getNextID($seq);
$name = $record->getTable()->getIdentifier();
$array[$name] = $id;
}
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));
return true;
}
/**
* deletes all related composites
* this method is always called internally when a record is deleted
*
* @return void
*/
final public function deleteComposites(Doctrine_Record $record) {
foreach($record->getTable()->getForeignKeys() as $fk) {
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::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 record into pending insert list
* @param Doctrine_Record $record
*/
public function addInsert(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->insert[$name][] = $record;
}
/**
* adds record into penging update list
* @param Doctrine_Record $record
*/
public function addUpdate(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->update[$name][] = $record;
}
/**
* adds record into pending delete list
* @param Doctrine_Record $record
*/
public function addDelete(Doctrine_Record $record) {
$name = $record->getTable()->getComponentName();
$this->delete[$name][] = $record;
}
/**
* returns the pending insert list
*
* @return array
*/
public function getInserts() {
return $this->insert;
}
/**
* returns the pending update list
*
* @return array
*/
public function getUpdates() {
return $this->update;
}
/**
* returns the pending delete list
*
* @return array
*/
public function getDeletes() {
return $this->delete;
}
/**
* returns a string representation of this object
* @return string
*/
public function __toString() {
return Doctrine_Lib::getSessionAsString($this);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Session.class.php");
/**
* standard session, the parent of pgsql, mysql and sqlite
*/
class Doctrine_Session_Common extends Doctrine_Session {
public function modifyLimitQuery($query,$limit = false,$offset = false) {
if($limit && $offset) {
$query .= " LIMIT ".$limit." OFFSET ".$offset;
} elseif($limit && ! $offset) {
$query .= " LIMIT ".$limit;
} elseif( ! $limit && $offset) {
$query .= " LIMIT 999999999999 OFFSET ".$offset;
}
return $query;
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Exception.class.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);
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Session.class.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];
}
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Session.class.php");
/**
* informix database driver
*/
class Doctrine_Session_Informix extends Doctrine_Session { }
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Session.class.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];
}
}
?>
<?php
require_once("Common.class.php");
/**
* mysql driver
*/
class Doctrine_Session_Mysql extends Doctrine_Session_Common {
/**
* the constructor
* @param PDO $pdo -- database handle
*/
public function __construct(Doctrine_Manager $manager,PDO $pdo) {
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
parent::__construct($manager,$pdo);
}
/**
* 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;
}
*/
/**
* returns maximum identifier values
*
* @param array $names an array of component names
* @return array
*/
public function getMaximumValues2(array $names) {
$values = array();
foreach($names as $name) {
$table = $this->tables[$name];
$keys = $table->getPrimaryKeys();
$tablename = $table->getTableName();
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
// record uses auto_increment column
$sql[] = "SELECT MAX(".$tablename.".".$table->getIdentifier().") as $tablename FROM ".$tablename;
$values[$tablename] = 0;
$array[] = $tablename;
}
}
$sql = implode(" UNION ",$sql);
$stmt = $this->getDBH()->query($sql);
$data = $stmt->fetchAll(PDO::FETCH_NUM);
foreach($data as $k => $v) {
$values[$array[$k]] = $v[0];
}
return $values;
}
/**
* bulkInsert
* inserts all the objects in the pending insert list into database
* TODO: THIS IS NOT WORKING YET AS THERE ARE BUGS IN COMPONENTS USING SELF-REFERENCENCING
*
* @return boolean
*/
/**
public function bulkInsert() {
if(empty($this->insert))
return false;
foreach($this->insert as $name => $inserts) {
if( ! isset($inserts[0]))
continue;
$record = $inserts[0];
$table = $record->getTable();
$seq = $table->getSequenceName();
$keys = $table->getPrimaryKeys();
$marks = array();
$params = array();
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);
$array = $record->getPrepared();
if(isset($this->validator)) {
if( ! $this->validator->validateRecord($record)) {
continue;
}
}
$key = implode(", ",array_keys($array));
if( ! isset($params[$key]))
$params[$key] = array();
$marks[$key][] = "(".substr(str_repeat("?, ",count($array)),0,-2).")";
$params[$key] = array_merge($params[$key], array_values($array));
// listen the onInsert event
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onInsert($record);
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
}
if( ! empty($marks)) {
foreach($marks as $key => $list) {
$query = "INSERT INTO ".$table->getTableName()." (".$key.") VALUES ".implode(", ", $list);
$stmt = $this->getDBH()->prepare($query);
$stmt->execute($params[$key]);
}
}
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
// record uses auto_increment column
$sql = "SELECT MAX(".$table->getIdentifier().") FROM ".$record->getTable()->getTableName();
$stmt = $this->getDBH()->query($sql);
$data = $stmt->fetch(PDO::FETCH_NUM);
$id = $data[0];
$stmt->closeCursor();
foreach(array_reverse($inserts) as $record) {
$record->setID((int) $id);
$id--;
}
}
}
$this->insert = array();
return true;
}
*/
}
?>
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Session.class.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];
}
}
?>
<?php
require_once("Common.class.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];
}
}
?>
<?php
require_once("Common.class.php");
/**
* sqlite driver
*/
class Doctrine_Session_Sqlite extends Doctrine_Session_Common { }
?>
<?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 {
/**
* @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 $relations an array containing all the Doctrine_Relation objects for this table
*/
private $relations = array();
/**
* @var array $primaryKeys an array containing all primary key column names
*/
private $primaryKeys = array();
/**
* @var mixed $identifier
*/
private $identifier;
/**
* @var integer $identifierType
*/
private $identifierType;
/**
* @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 array $identityMap first level cache
*/
private $identityMap = array();
private $repository;
/**
* @var Doctrine_Cache $cache second level cache
*/
private $cache;
/**
* @var array $columns an array of column definitions
*/
private $columns;
/**
* @var array $bound bound relations
*/
private $bound = array();
/**
* @var array $boundAliases bound relation aliases
*/
private $boundAliases = array();
/**
* @var integer $columnCount cached column count
*/
private $columnCount;
/**
* @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);
$this->name = $name;
if( ! class_exists($name) || empty($name))
throw new Doctrine_Exception("Couldn't find class $name");
$record = new $name($this);
$names = array();
$class = $name;
// get parent classes
do {
if($class == "Doctrine_Record") break;
$name = $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();
$this->columnCount = count($this->columns);
if(isset($this->columns)) {
$method = new ReflectionMethod($this->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";
$this->identifier = "id";
$this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
break;
default:
if(count($this->primaryKeys) > 1) {
$this->identifier = $this->primaryKeys;
$this->identifierType = Doctrine_Identifier::COMPOSITE;
} else {
foreach($this->primaryKeys as $pk) {
$o = $this->columns[$pk][2];
$e = explode("|",$o);
$found = false;
foreach($e as $option) {
if($found)
break;
$e2 = explode(":",$option);
switch(strtolower($e2[0])):
case "unique":
$this->identifierType = Doctrine_Identifier::UNIQUE;
$found = true;
break;
case "autoincrement":
$this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
$found = true;
break;
case "seq":
$this->identifierType = Doctrine_Identifier::SEQUENCE;
$found = true;
break;
endswitch;
}
if( ! isset($this->identifierType))
$this->identifierType = Doctrine_Identifier::NORMAL;
$this->identifier = $pk;
}
}
endswitch;
if($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
$dict = new Doctrine_DataDict($this->getSession()->getDBH());
$dict->createTable($this->tableName, $this->columns);
}
}
} else {
throw new Doctrine_Exception("Class '$name' has no table definition.");
}
$record->setUp();
// 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_SQLITE:
$this->cache = new Doctrine_Cache_Sqlite($this);
break;
case Doctrine::CACHE_NONE:
$this->cache = new Doctrine_Cache($this);
break;
endswitch;
}
/**
* @return Doctrine_Repository
*/
public function getRepository() {
return $this->repository;
}
/**
* setColumn
* @param string $name
* @param string $type
* @param integer $length
* @param mixed $options
* @return void
*/
final public function setColumn($name, $type, $length, $options = "") {
$this->columns[$name] = array($type,$length,$options);
$e = explode("|",$options);
if(in_array("primary",$e)) {
$this->primaryKeys[] = $name;
}
}
/**
* @return mixed
*/
final public function getIdentifier() {
return $this->identifier;
}
/**
* @return integer
*/
final public function getIdentifierType() {
return $this->identifierType;
}
/**
* hasColumn
* @return boolean
*/
final public function hasColumn($name) {
return isset($this->columns[$name]);
}
/**
* @param mixed $key
* @return void
*/
final public function setPrimaryKey($key) {
switch(gettype($key)):
case "array":
$this->primaryKeys = array_values($key);
break;
case "string":
$this->primaryKeys[] = $key;
break;
endswitch;
}
/**
* 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_Relation::ONE_COMPOSITE:
case Doctrine_Relation::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;
}
/**
* returns all bound relations
*
* @return array
*/
final public function getBounds() {
return $this->bound;
}
/**
* returns a bound relation array
*
* @param string $name
* @return array
*/
final public function getBound($name) {
if( ! isset($this->bound[$name]))
throw new InvalidKeyException();
return $this->bound[$name];
}
/**
* returns a bound relation array
*
* @param string $name
* @return array
*/
final public function getBoundForName($name) {
foreach($this->bound as $k => $bound) {
if($bound[3] == $name) {
return $this->bound[$k];
}
}
throw new InvalidKeyException();
}
/**
* returns the alias for given component name
*
* @param string $name
* @return string
*/
final public function getAlias($name) {
if(isset($this->boundAliases[$name]))
return $this->boundAliases[$name];
return $name;
}
/**
* returns component name for given alias
*
* @param string $alias
* @return string
*/
final public function getAliasName($alias) {
if($name = array_search($this->boundAliases,$alias))
return $name;
throw new InvalidKeyException();
}
/**
* unbinds all relations
*
* @return void
*/
final public function unbindAll() {
$this->bound = array();
$this->relations = array();
$this->boundAliases = array();
}
/**
* unbinds a relation
* returns true on success, false on failure
*
* @param $name
* @return boolean
*/
final public function unbind() {
if( ! isset($this->bound[$name]))
return false;
unset($this->bound[$name]);
if(isset($this->relations[$name]))
unset($this->relations[$name]);
if(isset($this->boundAliases[$name]))
unset($this->boundAliases[$name]);
return true;
}
/**
* binds a relation
*
* @param string $name
* @param string $field
* @return void
*/
final public function bind($name,$field,$type,$localKey) {
if(isset($this->relations[$name]))
throw new InvalidKeyException();
$e = explode(" as ",$name);
$name = $e[0];
if(isset($e[1])) {
$alias = $e[1];
$this->boundAliases[$name] = $alias;
} else
$alias = $name;
$this->bound[$alias] = array($field,$type,$localKey,$name);
}
/**
* 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;
}
/**
* @param string $name component name of which a foreign key object is bound
* @return Doctrine_Relation
*/
final public function getForeignKey($name) {
if(isset($this->relations[$name]))
return $this->relations[$name];
if(isset($this->bound[$name])) {
$type = $this->bound[$name][1];
$local = $this->bound[$name][2];
list($component, $foreign) = explode(".",$this->bound[$name][0]);
$alias = $name;
$name = $this->bound[$alias][3];
$table = $this->session->getTable($name);
if($component == $this->name || in_array($component, $this->parents)) {
// ONE-TO-ONE
if($type == Doctrine_Relation::ONE_COMPOSITE ||
$type == Doctrine_Relation::ONE_AGGREGATE) {
if( ! isset($local))
$local = $table->getIdentifier();
$relation = new Doctrine_LocalKey($table,$foreign,$local,$type);
} else
throw new Doctrine_Mapping_Exception("Only one-to-one relations are possible when local reference key is used.");
} elseif($component == $name || ($component == $alias && $name == $this->name)) {
if( ! isset($local))
$local = $this->identifier;
// ONE-TO-MANY or ONE-TO-ONE
$relation = new Doctrine_ForeignKey($table,$local,$foreign,$type);
} else {
// MANY-TO-MANY
// only aggregate relations allowed
if($type != Doctrine_Relation::MANY_AGGREGATE)
throw new Doctrine_Mapping_Exception("Only aggregate relations are allowed for many-to-many relations");
$classes = array_merge($this->parents, array($this->name));
foreach(array_reverse($classes) as $class) {
try {
$bound = $table->getBoundForName($class);
break;
} catch(InvalidKeyException $exc) { }
}
if( ! isset($local))
$local = $this->identifier;
$e2 = explode(".",$bound[0]);
$fields = explode("-",$e2[1]);
if($e2[0] != $component)
throw new Doctrine_Mapping_Exception($e2[0]." doesn't match ".$component);
$associationTable = $this->session->getTable($e2[0]);
if(count($fields) > 1) {
// SELF-REFERENCING THROUGH JOIN TABLE
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$fields[0],Doctrine_Relation::MANY_COMPOSITE);
$relation = new Doctrine_Association($table,$associationTable,$fields[0],$fields[1],$type);
} else {
// NORMAL MANY-TO-MANY RELATIONSHIP
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE);
$relation = new Doctrine_Association($table,$associationTable,$e2[1],$foreign,$type);
}
}
$this->relations[$alias] = $relation;
return $this->relations[$alias];
}
throw new InvalidKeyException();
}
/**
* returns an array containing all foreign key objects
*
* @return array
*/
final public function getForeignKeys() {
$a = array();
foreach($this->bound as $k=>$v) {
$this->getForeignKey($k);
}
return $this->relations;
}
/**
* sets the database table name
*
* @param string $name database table name
* @return void
*/
final public function setTableName($name) {
$this->tableName = $name;
}
/**
* returns the database table name
*
* @return string
*/
final public function getTableName() {
return $this->tableName;
}
/**
* create
* creates a new record
*
* @param $array an array where keys are field names and values representing field values
* @return Doctrine_Record
*/
public function create(array $array = array()) {
$this->data = $array;
$this->isNewEntry = true;
$record = new $this->name($this);
$this->isNewEntry = false;
$this->data = array();
return $record;
}
/**
* finds a record by its identifier
*
* @param $id database row id
* @throws Doctrine_Find_Exception
* @return Doctrine_Record a record for given database identifier
*/
public function find($id) {
if($id !== null) {
if( ! is_array($id))
$id = array($id);
else
$id = array_values($id);
$query = $this->query." WHERE ".implode(" = ? AND ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
$params = array_merge($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 string 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(" AND ",$a);
$where .= " AND $i";
}
return $where;
}
/**
* findAll
* returns a collection of records
*
* @return Doctrine_Collection
*/
public function findAll() {
$graph = new Doctrine_Query($this->session);
$users = $graph->query("FROM ".$this->name);
return $users;
}
/**
* findBySql
* finds records with given sql where clause
* returns a collection of records
*
* @param string $sql SQL after WHERE clause
* @param array $params query parameters
* @return Doctrine_Collection
*/
public function findBySql($sql, array $params = array()) {
$q = new Doctrine_Query($this->session);
$users = $q->query("FROM ".$this->name." WHERE ".$sql, $params);
return $users;
}
/**
* clear
* clears the first level cache (identityMap)
*
* @return void
*/
public function clear() {
$this->identityMap = array();
}
/**
* getRecord
* first checks if record exists in identityMap, if not
* returns a new record
*
* @return Doctrine_Record
*/
public function getRecord() {
$key = $this->getIdentifier();
if( ! is_array($key))
$key = array($key);
foreach($key as $k) {
if( ! isset($this->data[$k]))
throw new Doctrine_Exception("No primary key found");
$id[] = $this->data[$k];
}
$id = implode(' ', $id);
if(isset($this->identityMap[$id]))
$record = $this->identityMap[$id];
else {
$record = new $this->name($this);
$this->identityMap[$id] = $record;
}
$this->data = array();
return $record;
}
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
* @return DAOProxy a proxy for given identifier
*/
final public function getProxy($id = null) {
if($id !== null) {
$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
*/
final public function getTableDescription() {
return $this->columns;
}
/**
* @return Doctrine_Query a Doctrine_Query object
*/
public function getQueryObject() {
$graph = new Doctrine_Query($this->getSession());
$graph->load($this->getComponentName());
return $graph;
}
/**
* execute
* @param string $query
* @param array $array
* @param integer $limit
* @param integer $offset
*/
public function execute($query, array $array = array(), $limit = null, $offset = null) {
$coll = new Doctrine_Collection($this);
$query = $this->session->modifyLimitQuery($query,$limit,$offset);
if( ! empty($array)) {
$stmt = $this->session->getDBH()->prepare($query);
$stmt->execute($array);
} else {
$stmt = $this->session->getDBH()->query($query);
}
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach($data as $row) {
$this->data = $row;
$record = $this->getRecord();
$coll->add($record);
}
return $coll;
}
/**
* @return integer
*/
final public function getColumnCount() {
return $this->columnCount;
}
/**
* returns all columns and their definitions
*
* @return array
*/
final public function getColumns() {
return $this->columns;
}
/**
* returns an array containing all the column names
*
* @return array
*/
public function getColumnNames() {
return array_keys($this->columns);
}
/**
* setData
* doctrine uses this function internally
* users are strongly discouraged to use this function
*
* @param array $data internal data
* @return void
*/
public function setData(array $data) {
$this->data = $data;
}
/**
* returns the maximum primary key value
*
* @return integer
*/
final public function getMaxIdentifier() {
$sql = "SELECT MAX(".$this->getIdentifier().") FROM ".$this->getTableName();
$stmt = $this->session->getDBH()->query($sql);
$data = $stmt->fetch(PDO::FETCH_NUM);
return isset($data[0])?$data[0]:1;
}
/**
* return whether or not a newly created object is new or not
*
* @return boolean
*/
final public function isNewEntry() {
return $this->isNewEntry;
}
/**
* returns simple cached query
*
* @return string
*/
final public function getQuery() {
return $this->query;
}
/**
* returns internal data, used by Doctrine_Record instances
* when retrieving data from database
*
* @return array
*/
final public function getData() {
return $this->data;
}
/**
* returns a string representation of this object
*
* @return string
*/
public function __toString() {
return Doctrine_Lib::getTableAsString($this);
}
}
?>
<?php
/**
* Doctrine_Validator
* Doctrine_Session uses this class for transaction validation
*
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
class Doctrine_Validator {
/**
* ERROR CONSTANTS
*/
/**
* constant for length validation error
*/
const ERR_LENGTH = 0;
/**
* constant for type validation error
*/
const ERR_TYPE = 1;
/**
* constant for general validation error
*/
const ERR_VALID = 2;
/**
* constant for unique validation error
*/
const ERR_UNIQUE = 3;
/**
* constant for blank validation error
*/
const ERR_BLANK = 4;
/**
* constant for date validation error
*/
const ERR_DATE = 5;
/**
* constant for null validation error
*/
const ERR_NULL = 6;
/**
* constant for enum validation error
*/
const ERR_ENUM = 7;
/**
* constant for range validation error
*/
const ERR_RANGE = 8;
/**
* @var array $stack error stack
*/
private $stack = array();
/**
* @var array $validators an array of validator objects
*/
private static $validators = array();
/**
* returns a validator object
*
* @param string $name
* @return Doctrine_Validator_Interface
*/
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];
}
/**
* validates a given record and saves possible errors
* in Doctrine_Validator::$stack
*
* @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" || $arg == "protected" || $arg == "autoincrement")
continue;
$args = explode(":",$arg);
if( ! isset($args[1]))
$args[1] = '';
$validator = self::getValidator($args[0]);
if( ! $validator->validate($record, $key, $value, $args[1])) {
switch(strtolower($args[0])):
case "unique":
$err[$key] = Doctrine_Validator::ERR_UNIQUE;
break;
case "notnull":
$err[$key] = Doctrine_Validator::ERR_NULL;
break;
case "notblank":
$err[$key] = Doctrine_Validator::ERR_BLANK;
break;
case "enum":
$err[$key] = Doctrine_Validator::ERR_VALID;
break;
default:
$err[$key] = Doctrine_Validator::ERR_VALID;
break;
endswitch;
}
// errors found quit validation looping for this column
if(isset($err[$key]))
break;
}
}
if( ! empty($err)) {
$this->stack[$name][] = $err;
return false;
}
return true;
}
/**
* whether or not this validator has errors
*
* @return boolean
*/
public function hasErrors() {
return (count($this->stack) > 0);
}
/**
* returns the error stack
*
* @return array
*/
public function getErrorStack() {
return $this->stack;
}
/**
* returns the type of loosely typed variable
*
* @param mixed $var
* @return string
*/
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;
}
}
?>
<?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
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
return isset(self::$countries[$value]);
}
}
?>
<?php
class Doctrine_Validator_Date {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
return checkdate($value);
}
}
?>
<?php
class Doctrine_Validator_Email {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
$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;
}
}
?>
<?php
class Doctrine_Validator_Enum {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
$max = substr_count($args, "-");
$int = (int) $value;
if($int != $value)
return false;
if($int < 0 || $int > $max)
return false;
return true;
}
}
?>
<?php
class Doctrine_Validator_HtmlColor {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
if( ! preg_match("/^#{0,1}[0-9]{6}$/",$color)) {
return false;
}
return true;
}
}
?>
<?php
class Doctrine_Validator_Ip {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
$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;
}
}
?>
<?php
class Doctrine_Validator_NoSpace {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
if(trim($value) === '')
return false;
return true;
}
}
?>
<?php
class Doctrine_Validator_Notblank {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
$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 false;
return true;
}
}
?>
<?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) {
if ($value === null || $value === '')
return false;
return true;
}
}
?>
<?php
class Doctrine_Validator_Range {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
$e = explode("-",$args);
if($value < $e[0])
return false;
if(isset($e[1]) && $value > $e[1])
return false;
return true;
}
}
?>
<?php
class Doctrine_Validator_Regexp {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
if(preg_match("/$args/", $value))
return true;
return false;
}
}
?>
<?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);
}
}
?>
<?php
class Doctrine_Validator_Unique {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
$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()));
}
}
?>
<?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
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
return isset(self::$states[$value]);
}
}
?>
<?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.
DOCUMENTATION:
See adodb/tests/test-datadict.php for docs and examples.
Modified 3 October, 2005 for use with ADOdb Lite by Mark Dickenson
*/
/*
Test script for parser
*/
// security - hide paths
if (!defined('ADODB_DIR')) die();
if (!function_exists('ctype_alnum')) {
function ctype_alnum($text) {
return preg_match('/^[a-z0-9]*$/i', $text);
}
}
function _array_change_key_case($an_array)
{
if (is_array($an_array)) {
$new_array = array();
foreach($an_array as $key=>$value)
$new_array[strtoupper($key)] = $value;
return $new_array;
}
return $an_array;
}
/**
Parse arguments, treat "text" (text) and 'text' as quotation marks.
To escape, use "" or '' or ))
Will read in "abc def" sans quotes, as: abc def
Same with 'abc def'.
However if `abc def`, then will read in as `abc def`
@param endstmtchar Character that indicates end of statement
@param tokenchars Include the following characters in tokens apart from A-Z and 0-9
@returns 2 dimensional array containing parsed tokens.
*/
function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
{
$pos = 0;
$intoken = false;
$stmtno = 0;
$endquote = false;
$tokens = array();
$tokens[$stmtno] = array();
$max = strlen($args);
$quoted = false;
while ($pos < $max) {
$ch = substr($args,$pos,1);
switch($ch) {
case ' ':
case "\t":
case "\n":
case "\r":
if (!$quoted) {
if ($intoken) {
$intoken = false;
$tokens[$stmtno][] = implode('',$tokarr);
}
break;
}
$tokarr[] = $ch;
break;
case '`':
if ($intoken) $tokarr[] = $ch;
case '(':
case ')':
case '"':
case "'":
if ($intoken) {
if (empty($endquote)) {
$tokens[$stmtno][] = implode('',$tokarr);
if ($ch == '(') $endquote = ')';
else $endquote = $ch;
$quoted = true;
$intoken = true;
$tokarr = array();
} else if ($endquote == $ch) {
$ch2 = substr($args,$pos+1,1);
if ($ch2 == $endquote) {
$pos += 1;
$tokarr[] = $ch2;
} else {
$quoted = false;
$intoken = false;
$tokens[$stmtno][] = implode('',$tokarr);
$endquote = '';
}
} else
$tokarr[] = $ch;
}else {
if ($ch == '(') $endquote = ')';
else $endquote = $ch;
$quoted = true;
$intoken = true;
$tokarr = array();
if ($ch == '`') $tokarr[] = '`';
}
break;
default:
if (!$intoken) {
if ($ch == $endstmtchar) {
$stmtno += 1;
$tokens[$stmtno] = array();
break;
}
$intoken = true;
$quoted = false;
$endquote = false;
$tokarr = array();
}
if ($quoted) $tokarr[] = $ch;
else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
else {
if ($ch == $endstmtchar) {
$tokens[$stmtno][] = implode('',$tokarr);
$stmtno += 1;
$tokens[$stmtno] = array();
$intoken = false;
$tokarr = array();
break;
}
$tokens[$stmtno][] = implode('',$tokarr);
$tokens[$stmtno][] = $ch;
$intoken = false;
}
}
$pos += 1;
}
if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
return $tokens;
}
class ADODB_DataDict {
var $connection;
var $debug = false;
var $dropTable = 'DROP TABLE %s';
var $renameTable = 'RENAME TABLE %s TO %s';
var $dropIndex = 'DROP INDEX %s';
var $addCol = ' ADD';
var $alterCol = ' ALTER COLUMN';
var $dropCol = ' DROP COLUMN';
var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s'; // table, old-column, new-column, column-definitions (not used by default)
var $nameRegex = '\w';
var $nameRegexBrackets = 'a-zA-Z0-9_\(\)';
var $schema = false;
var $serverInfo = array();
var $autoIncrement = false;
var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql
var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
/// in other words, we use a text area for editting.
var $metaTablesSQL;
var $metaColumnsSQL;
var $debug_echo = true;
var $fetchMode;
var $raiseErrorFn;
function SetFetchMode($mode)
{
GLOBAL $ADODB_FETCH_MODE;
$old = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = $mode;
return $old;
}
function outp($text)
{
$this->debug_output = "<br>\n(" . $this->dbtype . "): ".htmlspecialchars($text)."<br>\n";
if($this->debug_echo)
echo $this->debug_output;
}
function GetCommentSQL($table,$col)
{
return false;
}
function SetCommentSQL($table,$col,$cmt)
{
return false;
}
/**
* @param ttype can either be 'VIEW' or 'TABLE' or false.
* If false, both views and tables are returned.
* "VIEW" returns only views
* "TABLE" returns only tables
* @param showSchema returns the schema/user with the table name, eg. USER.TABLE
* @param mask is the input mask - only supported by oci8 and postgresql
*
* @return array of tables for current database.
*/
function MetaTables()
{
global $ADODB_FETCH_MODE;
$false = false;
if ($mask) {
return $false;
}
if ($this->metaTablesSQL) {
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
$rs = $this->Execute($this->metaTablesSQL);
if (isset($savem)) $this->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if ($rs === false) return $false;
$arr =& $rs->GetArray();
$arr2 = array();
if ($hast = ($ttype && isset($arr[0][1]))) {
$showt = strncmp($ttype,'T',1);
}
for ($i=0; $i < sizeof($arr); $i++) {
if ($hast) {
if ($showt == 0) {
if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
} else {
if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
}
} else
$arr2[] = trim($arr[$i][0]);
}
$rs->Close();
return $arr2;
}
return $false;
}
/**
* List columns in a database as an array of ADOFieldObjects.
* See top of file for definition of object.
*
* @param table table name to query
* @param upper uppercase table name (required by some databases)
* @schema is optional database schema to use - not supported by all databases.
*
* @return array of ADOFieldObjects for current table.
*/
function MetaColumns($table, $upper=true, $schema=false)
{
global $ADODB_FETCH_MODE;
$false = false;
if (!empty($this->metaColumnsSQL)) {
$schema = false;
$this->_findschema($table,$schema);
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
$stmt = $this->connection->query(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
if (isset($savem)) $this->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if ($stmt === false)
return $false;
$retarr = array();
while ($rs = $stmt->fetch(PDO::FETCH_NUM)) {
$fld = new ADOFieldObject();
$fld->name = $rs[0];
$fld->type = $rs[1];
if (isset($rs[3]) && $rs[3]) {
if ($rs[3]>0) $fld->max_length = $rs[3];
$fld->scale = $rs[4];
if ($fld->scale>0) $fld->max_length += 1;
} else
$fld->max_length = $rs[2];
if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
else $retarr[strtoupper($fld->name)] = $fld;
}
$stmt->closeCursor();
return $retarr;
}
return $false;
}
function _findschema(&$table,&$schema)
{
if (!$schema && ($at = strpos($table,'.')) !== false) {
$schema = substr($table,0,$at);
$table = substr($table,$at+1);
}
}
/**
* @returns an array with the primary key columns in it.
*/
function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
{
// owner not used in base class - see oci8
$p = array();
$objs =& $this->MetaColumns($table);
if ($objs) {
foreach($objs as $v) {
if (!empty($v->primary_key))
$p[] = $v->name;
}
}
if (sizeof($p)) return $p;
if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
return false;
}
/**
* List indexes on a table as an array.
* @param table table name to query
* @param primary true to only show primary keys. Not actually used for most databases
*
* @return array of indexes on current table. Each element represents an index, and is itself an associative array.
Array (
[name_of_index] => Array
(
[unique] => true or false
[columns] => Array
(
[0] => firstname
[1] => lastname
)
)
*/
function MetaIndexes($table, $primary = false, $owner = false)
{
$false = false;
return $false;
}
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
// changed in 2.32 to hashing instead of switch stmt for speed...
static $typeMap = array(
'VARCHAR' => 'C',
'VARCHAR2' => 'C',
'CHAR' => 'C',
'C' => 'C',
'STRING' => 'C',
'NCHAR' => 'C',
'NVARCHAR' => 'C',
'VARYING' => 'C',
'BPCHAR' => 'C',
'CHARACTER' => 'C',
'INTERVAL' => 'C', # Postgres
##
'LONGCHAR' => 'X',
'TEXT' => 'X',
'NTEXT' => 'X',
'M' => 'X',
'X' => 'X',
'CLOB' => 'X',
'NCLOB' => 'X',
'LVARCHAR' => 'X',
##
'BLOB' => 'B',
'IMAGE' => 'B',
'BINARY' => 'B',
'VARBINARY' => 'B',
'LONGBINARY' => 'B',
'B' => 'B',
##
'YEAR' => 'D', // mysql
'DATE' => 'D',
'D' => 'D',
##
'TIME' => 'T',
'TIMESTAMP' => 'T',
'DATETIME' => 'T',
'TIMESTAMPTZ' => 'T',
'T' => 'T',
##
'BOOL' => 'L',
'BOOLEAN' => 'L',
'BIT' => 'L',
'L' => 'L',
##
'COUNTER' => 'R',
'R' => 'R',
'SERIAL' => 'R', // ifx
'INT IDENTITY' => 'R',
##
'INT' => 'I',
'INT2' => 'I',
'INT4' => 'I',
'INT8' => 'I',
'INTEGER' => 'I',
'INTEGER UNSIGNED' => 'I',
'SHORT' => 'I',
'TINYINT' => 'I',
'SMALLINT' => 'I',
'I' => 'I',
##
'LONG' => 'N', // interbase is numeric, oci8 is blob
'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
'DECIMAL' => 'N',
'DEC' => 'N',
'REAL' => 'N',
'DOUBLE' => 'N',
'DOUBLE PRECISION' => 'N',
'SMALLFLOAT' => 'N',
'FLOAT' => 'N',
'NUMBER' => 'N',
'NUM' => 'N',
'NUMERIC' => 'N',
'MONEY' => 'N',
## informix 9.2
'SQLINT' => 'I',
'SQLSERIAL' => 'I',
'SQLSMINT' => 'I',
'SQLSMFLOAT' => 'N',
'SQLFLOAT' => 'N',
'SQLMONEY' => 'N',
'SQLDECIMAL' => 'N',
'SQLDATE' => 'D',
'SQLVCHAR' => 'C',
'SQLCHAR' => 'C',
'SQLDTIME' => 'T',
'SQLINTERVAL' => 'N',
'SQLBYTES' => 'B',
'SQLTEXT' => 'X'
);
$tmap = false;
$t = strtoupper($t);
$tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
switch ($tmap) {
case 'C':
// is the char field is too long, return as text field...
if ($this->blobSize >= 0) {
if ($len > $this->blobSize) return 'X';
} else if ($len > 250) {
return 'X';
}
return 'C';
case 'I':
if (!empty($fieldobj->primary_key)) return 'R';
return 'I';
case false:
return 'N';
case 'B':
if (isset($fieldobj->binary))
return ($fieldobj->binary) ? 'B' : 'X';
return 'B';
case 'D':
if (!empty($this->datetime)) return 'T';
return 'D';
default:
if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
return $tmap;
}
}
function NameQuote($name = NULL,$allowBrackets=false)
{
if (!is_string($name)) {
return FALSE;
}
$name = trim($name);
if ( !is_object($this->connection) ) {
return $name;
}
$quote = "'";
// 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
$regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
return $quote . $name . $quote;
}
return $name;
}
function TableName($name)
{
if ( $this->schema ) {
return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
}
return $this->NameQuote($name);
}
// Executes the sql array returned by GetTableSQL and GetIndexSQL
function ExecuteSQLArray($sql, $continueOnError = true)
{
$rez = 2;
$conn = &$this->connection;
$saved = $conn->debug;
foreach($sql as $line) {
if ($this->debug) $conn->debug = true;
$ok = $conn->Execute($line);
$conn->debug = $saved;
if (!$ok) {
if ($this->debug) $this->outp($conn->ErrorMsg());
if (!$continueOnError) return 0;
$rez = 1;
}
}
return $rez;
}
/*
Returns the actual type given a character code.
C: varchar
X: CLOB (character large object) or largest varchar size if CLOB is not supported
C2: Multibyte varchar
X2: Multibyte CLOB
B: BLOB (binary large object)
D: Date
T: Date-time
L: Integer field suitable for storing booleans (0 or 1)
I: Integer
F: Floating point number
N: Numeric or decimal number
*/
function ActualType($meta)
{
return $meta;
}
function CreateDatabase($dbname,$options=false)
{
$options = $this->_Options($options);
$sql = array();
$s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
if (isset($options[$this->upperName]))
$s .= ' '.$options[$this->upperName];
$sql[] = $s;
return $sql;
}
/*
Generates the SQL to create index. Returns an array of sql strings.
*/
function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
{
if (!is_array($flds)) {
$flds = explode(',',$flds);
}
foreach($flds as $key => $fld) {
# some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
$flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
}
return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
}
function DropIndexSQL ($idxname, $tabname = NULL)
{
return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
}
function SetSchema($schema)
{
$this->schema = $schema;
}
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) {
$sql[] = $alter . $v;
}
return $sql;
}
/**
* Change the definition of one column
*
* As some DBM's can't do that on there 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/string $tableoptions='' options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
foreach($lines as $v) {
$sql[] = $alter . $v;
}
return $sql;
}
/**
* Rename one column
*
* Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
* @param string $tabname table-name
* @param string $oldcolumn column-name to be renamed
* @param string $newcolumn new column-name
* @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
* @return array with SQL strings
*/
function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
{
$tabname = $this->TableName ($tabname);
if ($flds) {
list($lines,$pkey) = $this->_GenFields($flds);
list(,$first) = each($lines);
list(,$column_def) = split("[\t ]+",$first,2);
}
return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
}
/**
* Drop one column
*
* Some DBM's can't do that on there 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/string $tableoptions='' options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->TableName ($tabname);
if (!is_array($flds)) $flds = explode(',',$flds);
$sql = array();
$alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
foreach($flds as $v) {
$sql[] = $alter . $this->NameQuote($v);
}
return $sql;
}
function DropTableSQL($tabname)
{
return array (sprintf($this->dropTable, $this->TableName($tabname)));
}
function RenameTableSQL($tabname,$newname)
{
return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
}
/*
Generate the SQL to create table. Returns an array of sql strings.
*/
function CreateTableSQL($tabname, $flds, $tableoptions=false)
{
if (!$tableoptions) $tableoptions = array();
list($lines,$pkey) = $this->_GenFields($flds, true);
$taboptions = $this->_Options($tableoptions);
$tabname = $this->TableName ($tabname);
$sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
$tsql = $this->_Triggers($tabname,$taboptions);
foreach($tsql as $s) $sql[] = $s;
return $sql;
}
function _GenFields($flds,$widespacing=false)
{
if (is_string($flds)) {
$padding = ' ';
$txt = $flds.$padding;
$flds = array();
$flds0 = Lens_ParseArgs($txt,',');
$hasparam = false;
foreach($flds0 as $f0) {
$f1 = array();
foreach($f0 as $token) {
switch (strtoupper($token)) {
case 'CONSTRAINT':
case 'DEFAULT':
$hasparam = $token;
break;
default:
if ($hasparam) $f1[$hasparam] = $token;
else $f1[] = $token;
$hasparam = false;
break;
}
}
$flds[] = $f1;
}
}
$this->autoIncrement = false;
$lines = array();
$pkey = array();
foreach($flds as $fld) {
$fld = _array_change_key_case($fld);
$fname = false;
$fdefault = false;
$fautoinc = false;
$ftype = false;
$fsize = false;
$fprec = false;
$fprimary = false;
$fnoquote = false;
$fdefts = false;
$fdefdate = false;
$fconstraint = false;
$fnotnull = false;
$funsigned = false;
//-----------------
// Parse attributes
foreach($fld as $attr => $v) {
if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
switch($attr) {
case '0':
case 'NAME':
$fname = $v;
break;
case '1':
case 'TYPE':
$ty = $v; $ftype = $this->ActualType(strtoupper($v));
break;
case 'SIZE':
$dotat = strpos($v,'.');
if ($dotat === false) $dotat = strpos($v,',');
if ($dotat === false) $fsize = $v;
else {
$fsize = substr($v,0,$dotat);
$fprec = substr($v,$dotat+1);
}
break;
case 'UNSIGNED':
$funsigned = true;
break;
case 'AUTOINCREMENT':
case 'AUTO':
$fautoinc = true;
$fnotnull = true;
break;
case 'KEY':
case 'PRIMARY':
$fprimary = $v;
$fnotnull = true;
break;
case 'DEF':
case 'DEFAULT':
$fdefault = $v;
break;
case 'NOTNULL':
$fnotnull = $v;
break;
case 'NOQUOTE':
$fnoquote = $v;
break;
case 'DEFDATE':
$fdefdate = $v;
break;
case 'DEFTIMESTAMP':
$fdefts = $v;
break;
case 'CONSTRAINT':
$fconstraint = $v;
break;
}
}
//--------------------
// VALIDATE FIELD INFO
if (!strlen($fname)) {
if ($this->debug) $this->outp("Undefined NAME");
return false;
}
$fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
$fname = $this->NameQuote($fname);
if (!strlen($ftype)) {
if ($this->debug) $this->outp("Undefined TYPE for field '$fname'");
return false;
} else {
$ftype = strtoupper($ftype);
}
$ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
if ($fprimary) $pkey[] = $fname;
// some databases do not allow blobs to have defaults
if ($ty == 'X') $fdefault = false;
//--------------------
// CONSTRUCT FIELD SQL
if ($fdefts) {
if (substr($this->dbtype,0,5) == 'mysql') {
$ftype = 'TIMESTAMP';
} else {
$fdefault = $this->connection->sysTimeStamp;
}
} else if ($fdefdate) {
if (substr($this->dbtype,0,5) == 'mysql') {
$ftype = 'TIMESTAMP';
} else {
$fdefault = $this->connection->sysDate;
}
} else if ($fdefault !== false && !$fnoquote)
if ($ty == 'C' or $ty == 'X' or
( substr($fdefault,0,1) != "'" && !is_numeric($fdefault)))
if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
$fdefault = trim($fdefault);
else if (strtolower($fdefault) != 'null')
$fdefault = $this->connection->qstr($fdefault);
$suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
if ($widespacing) $fname = str_pad($fname,24);
$lines[$fid] = $fname.' '.$ftype.$suffix;
if ($fautoinc) $this->autoIncrement = true;
} // foreach $flds
return array($lines,$pkey);
}
/*
GENERATE THE SIZE PART OF THE DATATYPE
$ftype is the actual type
$ty is the type defined originally in the DDL
*/
function _GetSize($ftype, $ty, $fsize, $fprec)
{
if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
$ftype .= "(".$fsize;
if (strlen($fprec)) $ftype .= ",".$fprec;
$ftype .= ')';
}
return $ftype;
}
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
{
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname);
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[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s .= '(' . $flds . ')';
$sql[] = $s;
return $sql;
}
function _DropAutoIncrement($tabname)
{
return false;
}
function _TableSQL($tabname,$lines,$pkey,$tableoptions)
{
$sql = array();
if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
$sql[] = sprintf($this->dropTable,$tabname);
if ($this->autoIncrement) {
$sInc = $this->_DropAutoIncrement($tabname);
if ($sInc) $sql[] = $sInc;
}
if ( isset ($tableoptions['DROP']) ) {
return $sql;
}
}
$s = "CREATE TABLE $tabname (\n";
$s .= implode(",\n", $lines);
if (sizeof($pkey)>0) {
$s .= ",\n PRIMARY KEY (";
$s .= implode(", ",$pkey).")";
}
if (isset($tableoptions['CONSTRAINTS']))
$s .= "\n".$tableoptions['CONSTRAINTS'];
if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
$s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
$s .= "\n)";
if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
/*
GENERATE TRIGGERS IF NEEDED
used when table has auto-incrementing field that is emulated using triggers
*/
function _Triggers($tabname,$taboptions)
{
return array();
}
/*
Sanitize options, so that array elements with no keys are promoted to keys
*/
function _Options($opts)
{
if (!is_array($opts)) return array();
$newopts = array();
foreach($opts as $k => $v) {
if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
else $newopts[strtoupper($k)] = $v;
}
return $newopts;
}
/*
"Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
This function changes/adds new fields to your table. You don't
have to know if the col is new or not. It will check on its own.
*/
function ChangeTableSQL($tablename, $flds, $tableoptions = false)
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
// check table exists
$save_handler = $this->raiseErrorFn;
$this->raiseErrorFn = '';
$cols = $this->MetaColumns($tablename);
$this->raiseErrorFn = $save_handler;
if (isset($savem)) $this->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if ( empty($cols)) {
return $this->CreateTableSQL($tablename, $flds, $tableoptions);
}
if (is_array($flds)) {
// Cycle through the update fields, comparing
// existing fields to fields to update.
// if the Metatype and size is exactly the
// same, ignore - by Mark Newham
$holdflds = array();
foreach($flds as $k=>$v) {
if ( isset($cols[$k]) && is_object($cols[$k]) ) {
$c = $cols[$k];
$ml = $c->max_length;
$mt = &$this->MetaType($c->type,$ml);
if ($ml == -1) $ml = '';
if ($mt == 'X') $ml = $v['SIZE'];
if (($mt != $v['TYPE']) || $ml != $v['SIZE']) {
$holdflds[$k] = $v;
}
} else {
$holdflds[$k] = $v;
}
}
$flds = $holdflds;
}
// 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]) ) {
$flds = Lens_ParseArgs($v,',');
// We are trying to change the size of the field, if not allowed, simply ignore the request.
if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) continue;
$sql[] = $alter . $this->alterCol . ' ' . $v;
} else {
$sql[] = $alter . $this->addCol . ' ' . $v;
}
}
return $sql;
}
}
?>
<?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="";
}
?>
<?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();
}
}
?>
\ No newline at end of file
<?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;
}
}
?>
\ No newline at end of file
<?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;
}
}
?>
\ No newline at end of file
<?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;
}
}
*/
?>
\ No newline at end of file
<?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();
}
}
?>
\ No newline at end of file
<?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;
}
}
?>
\ No newline at end of file
<?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);
}
}
?>
\ No newline at end of file
<?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;
}
}
?>
<?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";
}
}
?>
\ No newline at end of file
<?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;
}
}
?>
<?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) . ')' );
}
}
?>
\ No newline at end of file
<?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)
// {
// }
}
?>
\ No newline at end of file
<?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;
}
}
?>
\ No newline at end of file
<?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)
// {
// }
}
?>
\ No newline at end of file
<?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)
// {
// }
}
?>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment