Commit 2d4db7b0 authored by doctrine's avatar doctrine

--no commit message

--no commit message
parent 87fa5b24
<?php <?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Cache.class.php"); require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."iCache.class.php");
/** /**
* Doctrine_CacheFile * Doctrine_CacheFile
* @author Konsta Vesterinen * @author Konsta Vesterinen
...@@ -8,7 +8,7 @@ require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Cache.class.php"); ...@@ -8,7 +8,7 @@ require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Cache.class.php");
* @license LGPL * @license LGPL
* @version 1.0 alpha * @version 1.0 alpha
*/ */
class Doctrine_Cache_File extends Doctrine_Cache implements Countable { class Doctrine_Cache_File implements Countable {
const STATS_FILE = "stats.cache"; const STATS_FILE = "stats.cache";
/** /**
* @var string $path path for the cache files * @var string $path path for the cache files
......
<?php
require_once(Doctrine::getPath().DIRECTORY_SEPARATOR."Cache.class.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 = "INSERT 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 = new PDO("sqlite:".$this->path."data.cache");
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
try {
$this->dbh->query("CREATE TABLE ".$this->table->getTableName()." (id INTEGER, 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 integer $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);
$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();
}
/**
* @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;
$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;
}
/**
* 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();
}
}
?>
...@@ -91,7 +91,7 @@ abstract class Doctrine_Configurable { ...@@ -91,7 +91,7 @@ abstract class Doctrine_Configurable {
break; break;
case Doctrine::ATTR_CACHE: case Doctrine::ATTR_CACHE:
if($value != Doctrine::CACHE_FILE && $value != Doctrine::CACHE_NONE) if($value != Doctrine::CACHE_SQLITE && $value != Doctrine::CACHE_NONE)
throw new Doctrine_Exception("Unknown cache container. See Doctrine::CACHE_* constants for availible containers."); throw new Doctrine_Exception("Unknown cache container. See Doctrine::CACHE_* constants for availible containers.");
break; break;
default: default:
......
<?php <?php
class Doctrine_DataDict { class Doctrine_DataDict {
private $table; private $dbh;
public function __construct(Doctrine_Table $table) { public function __construct(PDO $dbh) {
$this->table = $table; $manager = Doctrine_Manager::getInstance();
$manager = $this->table->getSession()->getManager();
require_once($manager->getRoot()."/adodb-hack/adodb.inc.php"); require_once($manager->getRoot()."/adodb-hack/adodb.inc.php");
$dbh = $this->table->getSession()->getDBH(); $this->dbh = $dbh;
$this->dict = NewDataDictionary($dbh); $this->dict = NewDataDictionary($dbh);
} }
public function metaColumns() { public function metaColumns(Doctrine_Table $table) {
return $this->dict->metaColumns($this->table->getTableName()); return $this->dict->metaColumns($table->getTableName());
} }
public function createTable() {
foreach($this->table->getColumns() as $name => $args) {
public function createTable($tablename, $columns) {
foreach($columns as $name => $args) {
$r[] = $name." ".$this->getADOType($args[0],$args[1])." ".$args[2]; $r[] = $name." ".$this->getADOType($args[0],$args[1])." ".$args[2];
} }
$dbh = $this->table->getSession()->getDBH();
$r = implode(", ",$r); $r = implode(", ",$r);
$a = $this->dict->createTableSQL($this->table->getTableName(),$r); $a = $this->dict->createTableSQL($tablename,$r);
$return = true; $return = true;
foreach($a as $sql) { foreach($a as $sql) {
try { try {
$dbh->query($sql); $this->dbh->query($sql);
} catch(PDOException $e) { } catch(PDOException $e) {
if($this->dbh->getAttribute(PDO::ATTR_DRIVER_NAME) == "sqlite")
throw $e;
$return = false; $return = false;
} }
} }
......
...@@ -124,9 +124,9 @@ final class Doctrine { ...@@ -124,9 +124,9 @@ final class Doctrine {
*/ */
/** /**
* file cache constant * sqlite cache constant
*/ */
const CACHE_FILE = 0; const CACHE_SQLITE = 0;
/** /**
* constant for disabling the caching * constant for disabling the caching
*/ */
...@@ -217,7 +217,7 @@ final class Doctrine { ...@@ -217,7 +217,7 @@ final class Doctrine {
$a[] = self::$path.DIRECTORY_SEPARATOR.$entry; $a[] = self::$path.DIRECTORY_SEPARATOR.$entry;
break; break;
default: default:
if(is_file(self::$path.DIRECTORY_SEPARATOR.$entry)) { if(is_file(self::$path.DIRECTORY_SEPARATOR.$entry) && substr($entry,-4) == ".php") {
require_once($entry); require_once($entry);
} }
endswitch; endswitch;
...@@ -226,7 +226,7 @@ final class Doctrine { ...@@ -226,7 +226,7 @@ final class Doctrine {
$dir = dir($dirname); $dir = dir($dirname);
$path = $dirname.DIRECTORY_SEPARATOR; $path = $dirname.DIRECTORY_SEPARATOR;
while (false !== ($entry = $dir->read())) { while (false !== ($entry = $dir->read())) {
if(is_file($path.$entry)) { if(is_file($path.$entry) && substr($entry,-4) == ".php") {
require_once($path.$entry); require_once($path.$entry);
} }
} }
......
...@@ -45,7 +45,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera ...@@ -45,7 +45,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
Doctrine::ATTR_FETCHMODE => Doctrine::FETCH_LAZY, Doctrine::ATTR_FETCHMODE => Doctrine::FETCH_LAZY,
Doctrine::ATTR_CACHE_TTL => 100, Doctrine::ATTR_CACHE_TTL => 100,
Doctrine::ATTR_CACHE_SIZE => 100, Doctrine::ATTR_CACHE_SIZE => 100,
Doctrine::ATTR_CACHE => Doctrine::CACHE_FILE, Doctrine::ATTR_CACHE => Doctrine::CACHE_NONE,
Doctrine::ATTR_BATCH_SIZE => 5, Doctrine::ATTR_BATCH_SIZE => 5,
Doctrine::ATTR_LISTENER => new EmptyEventListener(), Doctrine::ATTR_LISTENER => new EmptyEventListener(),
Doctrine::ATTR_PK_COLUMNS => array("id"), Doctrine::ATTR_PK_COLUMNS => array("id"),
......
...@@ -162,8 +162,8 @@ class Doctrine_Table extends Doctrine_Configurable { ...@@ -162,8 +162,8 @@ class Doctrine_Table extends Doctrine_Configurable {
endswitch; endswitch;
if($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) { if($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
$dict = new Doctrine_DataDict($this); $dict = new Doctrine_DataDict($this->getSession()->getDBH());
$dict->createTable($this->columns); $dict->createTable($this->tableName, $this->columns);
} }
} }
...@@ -192,8 +192,8 @@ class Doctrine_Table extends Doctrine_Configurable { ...@@ -192,8 +192,8 @@ class Doctrine_Table extends Doctrine_Configurable {
$this->repository = new Doctrine_Repository($this); $this->repository = new Doctrine_Repository($this);
switch($this->getAttribute(Doctrine::ATTR_CACHE)): switch($this->getAttribute(Doctrine::ATTR_CACHE)):
case Doctrine::CACHE_FILE: case Doctrine::CACHE_SQLITE:
$this->cache = new Doctrine_Cache_File($this); $this->cache = new Doctrine_Cache_Sqlite($this);
break; break;
case Doctrine::CACHE_NONE: case Doctrine::CACHE_NONE:
$this->cache = new Doctrine_Cache($this); $this->cache = new Doctrine_Cache($this);
......
<?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
require_once("UnitTestCase.class.php");
class Doctrine_Cache_SqliteTestCase extends Doctrine_UnitTestCase {
public function setUp() {
parent::setUp();
$this->manager->setAttribute(Doctrine::ATTR_CACHE,Doctrine::CACHE_NONE);
$dir = $this->session->getAttribute(Doctrine::ATTR_CACHE_DIR);
if(file_exists($dir.DIRECTORY_SEPARATOR."stats.cache"))
unlink($dir.DIRECTORY_SEPARATOR."stats.cache");
$this->cache = new Doctrine_Cache_Sqlite($this->objTable);
$this->cache->deleteAll();
}
/**
public function testStore() {
// does not store proxy objects
$this->assertFalse($this->cache->store($this->objTable->getProxy(4)));
$this->assertTrue($this->cache->store($this->objTable->find(4)));
$record = $this->cache->fetch(4);
$this->assertTrue($record instanceof Doctrine_Record);
foreach($this->old as $name => $value) {
$this->assertEqual($record->get($name), $value);
}
$this->assertEqual($record->getID(), $this->old->getID());
}
public function testFetchMultiple() {
$this->assertFalse($this->cache->fetchMultiple(array(5,6)));
$this->cache->store($this->objTable->find(5));
$array = $this->cache->fetchMultiple(array(5,6));
$this->assertEqual(gettype($array), "array");
$this->assertEqual(count($array), 1);
$this->assertTrue($array[0] instanceof Doctrine_Record);
}
public function testDeleteMultiple() {
$this->assertEqual($this->cache->deleteMultiple(array()),0);
$this->cache->store($this->objTable->find(5));
$this->cache->store($this->objTable->find(6));
$count = $this->cache->deleteMultiple(array(5,6));
$this->assertEqual($count,2);
$this->cache->store($this->objTable->find(6));
$count = $this->cache->deleteMultiple(array(5,6));
$this->assertEqual($count,1);
}
public function testDelete() {
$this->cache->store($this->objTable->find(5));
$this->assertTrue($this->cache->fetch(5) instanceof Doctrine_Record);
$this->assertEqual($this->cache->delete(5),true);
$this->assertFalse($this->cache->fetch(5));
$this->assertFalse($this->cache->delete(0));
}
public function testFetch() {
$this->assertFalse($this->cache->fetch(3));
}
public function testCount() {
$this->assertEqual($this->cache->count(), 0);
$this->cache->store($this->objTable->find(5));
$this->assertEqual($this->cache->count(), 1);
}
public function testSaveStats() {
$this->assertFalse($this->cache->saveStats());
$this->cache->store($this->objTable->find(5));
$this->cache->store($this->objTable->find(6));
$this->cache->store($this->objTable->find(7));
$this->cache->fetchMultiple(array(5,6,7));
$this->assertTrue($this->cache->saveStats());
$this->assertTrue(gettype($this->cache->getStats()), "array");
$this->assertEqual($this->cache->getStats(),array(5 => 1, 6 => 1, 7 => 1));
$this->cache->fetchMultiple(array(5,6,7));
$this->cache->fetch(5);
$this->cache->fetch(7);
$this->assertTrue($this->cache->saveStats());
$this->assertEqual($this->cache->getStats(),array(5 => 3, 6 => 2, 7 => 3));
}
public function testClean() {
$this->cache->store($this->objTable->find(4));
$this->cache->store($this->objTable->find(5));
$this->cache->store($this->objTable->find(6));
$this->cache->store($this->objTable->find(7));
$this->cache->store($this->objTable->find(8));
$this->cache->store($this->objTable->find(9));
$this->assertEqual($this->cache->count(), 6);
$this->cache->fetch(5);
$this->cache->fetch(7);
$this->cache->fetchMultiple(array(5,6,7));
$this->cache->fetchMultiple(array(5,6,7));
$this->cache->fetchMultiple(array(5,6,7));
$this->cache->fetchMultiple(array(4,5,6,7,8,9));
$this->assertTrue($this->cache->saveStats());
$this->manager->setAttribute(Doctrine::ATTR_CACHE_SIZE, 3);
$this->assertEqual($this->cache->clean(), 3);
}
*/
}
?>
...@@ -33,9 +33,6 @@ class Doctrine_TableTestCase extends Doctrine_UnitTestCase { ...@@ -33,9 +33,6 @@ class Doctrine_TableTestCase extends Doctrine_UnitTestCase {
public function testGetSession() { public function testGetSession() {
$this->assertTrue($this->objTable->getSession() instanceof Doctrine_Session); $this->assertTrue($this->objTable->getSession() instanceof Doctrine_Session);
} }
public function testGetCache() {
$this->assertTrue($this->objTable->getCache() instanceof Doctrine_Cache);
}
public function testGetData() { public function testGetData() {
$this->assertTrue($this->objTable->getData() == array()); $this->assertTrue($this->objTable->getData() == array());
} }
......
...@@ -61,13 +61,12 @@ class Doctrine_UnitTestCase extends UnitTestCase { ...@@ -61,13 +61,12 @@ class Doctrine_UnitTestCase extends UnitTestCase {
foreach($tables as $name) { foreach($tables as $name) {
$table = $this->session->getTable($name); $table = $this->session->getTable($name);
$table->getCache()->deleteAll();
} }
$this->objTable = $this->session->getTable("User"); $this->objTable = $this->session->getTable("User");
$this->repository = $this->objTable->getRepository(); $this->repository = $this->objTable->getRepository();
$this->cache = $this->objTable->getCache(); //$this->cache = $this->objTable->getCache();
$this->prepareData(); $this->prepareData();
} }
......
<?php <?php
require_once("ConfigurableTestCase.class.php"); require_once("ConfigurableTestCase.class.php");
require_once("ManagerTestCase.class.php"); require_once("ManagerTestCase.class.php");
require_once("SessionTestCase.class.php"); require_once("SessionTestCase.class.php");
...@@ -10,6 +11,10 @@ require_once("RecordTestCase.class.php"); ...@@ -10,6 +11,10 @@ require_once("RecordTestCase.class.php");
require_once("DQLParserTestCase.class.php"); require_once("DQLParserTestCase.class.php");
require_once("AccessTestCase.class.php"); require_once("AccessTestCase.class.php");
require_once("ValidatorTestCase.class.php"); require_once("ValidatorTestCase.class.php");
require_once("CacheSqliteTestCase.class.php");
print "<pre>"; print "<pre>";
error_reporting(E_ALL); error_reporting(E_ALL);
...@@ -30,14 +35,14 @@ $test->addTestCase(new Doctrine_TableTestCase()); ...@@ -30,14 +35,14 @@ $test->addTestCase(new Doctrine_TableTestCase());
$test->addTestCase(new Doctrine_AccessTestCase()); $test->addTestCase(new Doctrine_AccessTestCase());
$test->addTestCase(new Doctrine_ConfigurableTestCase()); $test->addTestCase(new Doctrine_ConfigurableTestCase());
$test->addTestCase(new Doctrine_EventListenerTestCase()); $test->addTestCase(new Doctrine_EventListenerTestCase());
$test->addTestCase(new Doctrine_DQL_ParserTestCase()); $test->addTestCase(new Doctrine_DQL_ParserTestCase());
$test->addTestCase(new Doctrine_BatchIteratorTestCase()); $test->addTestCase(new Doctrine_BatchIteratorTestCase());
//$test->addTestCase(new Doctrine_Cache_FileTestCase()); /**
$test->addTestCase(new Doctrine_Cache_FileTestCase());
$test->addTestCase(new Doctrine_Cache_SqliteTestCase());
*/
...@@ -46,6 +51,7 @@ $test->addTestCase(new Doctrine_BatchIteratorTestCase()); ...@@ -46,6 +51,7 @@ $test->addTestCase(new Doctrine_BatchIteratorTestCase());
$test->run(new HtmlReporter()); $test->run(new HtmlReporter());
$dbh = Doctrine_Manager::getInstance()->getCurrentSession()->getDBH(); $dbh = Doctrine_Manager::getInstance()->getCurrentSession()->getDBH();
$a = $dbh->getQueries(); $a = $dbh->getQueries();
...@@ -55,4 +61,5 @@ foreach($a as $query) { ...@@ -55,4 +61,5 @@ foreach($a as $query) {
$e = explode(" ",$query); $e = explode(" ",$query);
print $query."\n"; print $query."\n";
} }
?> ?>
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