Enabled result caching

This commit is contained in:
Deon George 2013-07-13 22:42:02 +10:00
parent a82edbf64c
commit 2997f6ada0
6 changed files with 237 additions and 10 deletions

View File

@ -0,0 +1,4 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
class Database_LDAP_Result_Cached extends Kohana_Database_LDAP_Result_Cached {}
?>

View File

@ -27,7 +27,37 @@ class Kohana_Database_LDAP_Result extends Database_Result {
ldap_free_result($this->_result['r']);
}
public function as_array($key=NULL,$value=NULL) {
$result = array();
if ($key === NULL AND $value === NULL) {
// Indexed rows
foreach ($this as $dn => $row)
$result[$dn] = $row;
} elseif ($key === NULL) {
throw HTTP_Exception::factory(501,'Not implemented');
// Indexed columns
} elseif ($value === NULL) {
throw HTTP_Exception::factory(501,'Not implemented');
// Associative rows
} else {
throw HTTP_Exception::factory(501,'Not implemented');
// Associative columns
}
return $result;
}
public function current() {
if (! $this->_current_entry)
return array();
if ($this->_as_object === TRUE) {
// Return an stdClass
throw HTTP_Exception::factory(501,'Not implemented');
@ -67,6 +97,28 @@ class Kohana_Database_LDAP_Result extends Database_Result {
return ldap_get_dn($this->_result['l'],$this->_current_entry);
}
/**
* Implements [Iterator::next], moves to the next row.
*
* next($result);
*
* @return $this
*/
public function next() {
$this->_current_entry = ldap_next_entry($this->_result['l'],$this->_current_entry);
++$this->_current_row;
return $this;
}
public function offsetExists($offset) {
return $this->valid();
}
public function prev() {
throw new Kohana_Exception('Cant go backwards');
}
public function seek($dn) {
$this->_current_entry = ldap_first_entry($this->_result['l'],$this->_result['r']);
@ -82,4 +134,23 @@ class Kohana_Database_LDAP_Result extends Database_Result {
// We didnt find it
return FALSE;
}
public function rewind() {
if ($this->_total_rows)
$this->_current_entry = ldap_first_entry($this->_result['l'],$this->_result['r']);
$this->_current_row = 0;
}
/**
* Implements [Iterator::valid], checks if the current row exists.
*
* [!!] This method is only used internally.
*
* @return boolean
*/
public function valid() {
return (boolean)$this->_current_entry;
}
} // End Database_LDAP_Result

View File

@ -0,0 +1,69 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Object used for caching the results of select queries. See [Results](/database/results#select-cached) for usage and examples.
*
* @package Kohana/LDAP
* @category Query/Result
* @author Deon George
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
*/
class Kohana_Database_LDAP_Result_Cached extends Database_Result_Cached {
public function __construct(array $result, $sql, $as_object = NULL)
{
parent::__construct($result, $sql, $as_object);
// Find the number of rows in the result
$this->_total_rows = count($result);
$this->_current_row = key($result);
}
public function __destruct() {
// Cached results do not use resources
}
public function cached() {
return $this;
}
public function current() {
// Return an array of the row
return $this->valid() ? $this->_result[$this->_current_row] : NULL;
}
public function key() {
return $this->_current_row;
}
public function next() {
next($this->_result);
$this->_current_row = key($this->_result);
return $this;
}
public function offsetExists($offset) {
return isset($this->_result[$offset]);
}
public function rewind() {
// We dont index by numbers, so we can just return
reset($this->_result);
$this->_current_row = key($this->_result);
return $this;
}
public function seek($offset) {
if (isset($this->_result[$offset])) {
$this->_current_row = $offset;
return TRUE;
} else {
return FALSE;
}
}
} // End Database_LDAP_Result_Cached

View File

@ -21,6 +21,9 @@ abstract class Kohana_Database_LDAP_Search {
private $_time_limit = '60'; // LDAP Search Time Limit
private $_db_pending = array(); // LDAP Query Filter to compile
// Execute the query during a cache hit
protected $_force_execute = FALSE;
// Cache lifetime
protected $_lifetime = NULL;
@ -126,6 +129,26 @@ abstract class Kohana_Database_LDAP_Search {
return isset($u['']['namingcontexts']) ? $u['']['namingcontexts'] : array();
}
/**
* Enables the query to be cached for a specified amount of time.
*
* @param integer $lifetime number of seconds to cache, 0 deletes it from the cache
* @param boolean whether or not to execute the query during a cache hit
* @return $this
* @uses Kohana::$cache_life
*/
public function cached($lifetime=NULL,$force=FALSE) {
if ($lifetime === NULL) {
// Use the global setting
$lifetime = Kohana::$cache_life;
}
$this->_force_execute = $force;
$this->_lifetime = $lifetime;
return $this;
}
public function deref($val) {
$this->_deref = $val;
@ -147,21 +170,21 @@ abstract class Kohana_Database_LDAP_Search {
$result = array();
foreach ($this->_base as $base) {
$search = NULL;
$result[$base] = NULL;
if ($this->_lifetime !== NULL AND $this->_db->caching()) {
// Set the cache key based on the database instance name and SQL
$cache_key = 'Database::query("'.$this->_db.'","'.$base.'","'.$this->_scope.'","'.$this->_filter.'")';
// Read the cache first to delete a possible hit with lifetime <= 0
if (($result = Kohana::cache($cache_key, NULL, $this->_lifetime)) !== NULL AND ! $this->_force_execute) {
if (($search = Kohana::cache($cache_key, NULL, $this->_lifetime)) !== NULL AND ! $this->_force_execute) {
// Return a cached result
$search = new Database_Result_Cached($result, array('b'=>$base,'s'=>$this->_scope,'f'=>$this->_filter), $as_object, $object_params);
$result[$base] = new Database_LDAP_Result_Cached($search, array('b'=>$base,'s'=>$this->_scope,'f'=>$this->_filter), $as_object, $object_params);
}
}
// Search is not cached, OR caching is disabled, so we'll query
if (! $search) {
if (! $result[$base]) {
switch ($this->_scope) {
case 'base':
$search = ldap_read($this->_db->connection(),$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
@ -178,6 +201,10 @@ abstract class Kohana_Database_LDAP_Search {
}
$result[$base] = new Database_LDAP_Result(array('l'=>$this->_db->connection(),'r'=>$search),array('b'=>$base,'s'=>$this->_scope,'f'=>$this->_filter),$as_object,$object_params);
// Cache the result array
if (isset($cache_key) AND $this->_lifetime > 0)
Kohana::cache($cache_key,$result[$base]->as_array(),$this->_lifetime);
}
}

View File

@ -0,0 +1,58 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This should test all LDAP server caching configuration
*
* @package Kohana/LDAP
* @category Test
* @author Deon George
* @copyright (c) 2013 phpLDAPadmin Development Team
* @license http://dev.phpldapadmin.org/license.html
* @group ldap
* @group ldap.server
*/
Class LDAPCaching extends Unittest_TestCase {
function hosts() {
return array(
array(FALSE,TRUE,FALSE,60),
array(TRUE,TRUE,FALSE,0),
array(TRUE,FALSE,FALSE,60),
array(TRUE,FALSE,FALSE,0),
array(TRUE,FALSE,TRUE,60),
array(TRUE,FALSE,TRUE,0),
array(TRUE,TRUE,TRUE,60),
array(TRUE,TRUE,TRUE,0),
);
}
/**
* Test that we can connect to an LDAP server
* @dataProvider hosts
*/
function testCache($expect,$caching,$force,$cached) {
$connection = Arr::merge(Kohana::$config->load('database.default'),array(
'caching'=>$caching,
));
$x = LDAP::factory('user',NULL,$connection);
$x->connect();
// We'll do a query first.
$u = $x->search(array(''))
->scope('base')
->cached($cached,$force)
->run();
$u = $x->search(array(''))
->scope('base')
->cached($cached,$force)
->run();
if ($expect)
$this->assertInstanceOf('Database_LDAP_Result',$u['']);
else
$this->assertInstanceOf('Database_LDAP_Result_Cached',$u['']);
$x->disconnect();
}
}

View File

@ -27,10 +27,9 @@ Class LDAPConnection extends Unittest_TestCase {
* @dataProvider hosts
*/
function testConnect($host,$port,$instance,$expect) {
$connection = array(
'type'=>'LDAP',
$connection = Arr::merge(Kohana::$config->load('database.default'),array(
'connection'=>array('hostname'=>$host,'port'=>$port),
);
));
$x = LDAP::factory($instance,NULL,$connection);
$x->connect();
@ -79,8 +78,7 @@ Class LDAPConnection extends Unittest_TestCase {
* @depends testConnect
*/
function testAuthConfiguration($user,$password,$expect) {
$connection = array(
'type'=>'LDAP',
$connection = Arr::merge(Kohana::$config->load('database.default'),array(
'login_attr'=>'uid',
'connection'=>array(
'hostname'=>'localhost',
@ -88,7 +86,7 @@ Class LDAPConnection extends Unittest_TestCase {
'username'=>$user,
'password'=>$password
),
);
));
// Ensure we start with a clean auth connection.
LDAP::factory('auth')->disconnect();