D.J. - 2008-01-15

Moved from
http://sourceforge.net/forum/message.php?msg_id=4712093

======================================================
RE: XOOPS 2.30 kick-off and task distribution (New)
Delete By: Garrath (garrath_fr) - 2008-01-13 05:40
sorry for my bad english

I mean that we can read a parametre table for class. This parameters may be in php array, db table or xml (like Spring for Java)

With this, after you can change class by an other with no work, you can store class where you want (folder for put in the same folder class and interface)

I put here what i do for xoops_gethandler, it's on work and i'm looking for jointure between table (i see you have a solution but i don't look completely but i'm interesting in ;-) )

I play with db table like this :
CREATE TABLE xoops_handlerconfig (
Name varchar(30) collate latin1_general_ci NOT NULL,
Active tinyint(1) NOT NULL default '0',
Class_Name varchar(50) collate latin1_general_ci default NULL,
Handler_Class_Name varchar(50) collate latin1_general_ci NOT NULL,
Path_Handler_Class varchar(100) collate latin1_general_ci NOT NULL,
Path_Class varchar(100) collate latin1_general_ci default NULL,
Table_Name varchar(30) collate latin1_general_ci default NULL,
Key_Name varchar(255) collate latin1_general_ci default NULL,
Identifier_Name varchar(255) collate latin1_general_ci default NULL,
prefix_table_name varchar(5) collate latin1_general_ci default NULL,
link_table_name varchar(30) collate latin1_general_ci default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

And after xoops_gethandler:
function xoops_gethandler($name, $optional = false )
{
//echo $name.'<br />';
if (!$name) return false;
static $handlers = array();
static $configs = array(); // chargement de la table handlerconfig pour la lire qu'une seule fois, cela evite de charger toutes les classes handlers et cela evite le pb de recursivite, en effet certain handler font appel a gethandler

$name = strtolower(trim($name));

if (!isset($handlers[$name])) {
if ($name == 'confighandler'){
if ( file_exists( $hnd_file = XOOPS_ROOT_PATH.'/kernel/object.php' ) ) {
require_once $hnd_file;
}

if ( file_exists( $hnd_file = XOOPS_ROOT_PATH.'/class/xoopshandlerconfig.php' ) ) {
require_once $hnd_file;
}
$handlers[$name] = new XoopsPersistableObjectHandler($GLOBALS['xoopsDB'], 'handlerconfig', 'XoopsHandlerConfig', null, false);
}
else{

if (!$configs){
$confighandler = xoops_gethandler('confighandler', false);
$criteria = new Criteria('active', 1, '=');
$configsTupples = $confighandler->getObjects($criteria, false, false);

foreach ($configsTupples as $config){
$configs[$config['name']] = $config;
}
}

if (isset($configs[$name])){
$config = $configs[$name];
if ( file_exists( $hnd_file = XOOPS_ROOT_PATH.$config['path_handler_class'] ) ) {
require_once $hnd_file;
}
$class = $config['handler_class_name'];
if (class_exists($class)) {
if ($config['path_class']){
if ( file_exists( $hnd_file = XOOPS_ROOT_PATH.$config['path_class'] ) ) {
require_once $hnd_file;
}
}
$handlers[$name] =& new $class($GLOBALS['xoopsDB'], $config['table_name'], $config['class_name'], $config['key_name'], $config['identifier_name'], $config['prefix_table_name'], $config['link_table_name']);
}
}
}
}

if (!isset($handlers[$name]) && !$optional ) {
trigger_error('Class <b>'.$class.'</b> does not exist<br />Handler Name: '.$name, E_USER_ERROR);
}
if ( isset($handlers[$name]) ) {
return $handlers[$name];
}
return false;
}

Here i read just one time the table for any page. I get all rows with colunmn active = 1, i put it in a array, and after i can get with parameter the filename, the handler class name etc...


For example : I take configcategory again in example

for use the 2.0.17 file i put this on my table:
INSERT INTO xoops_handlerconfig (Name, Active, Class_Name, Handler_Class_Name, Path_Handler_Class, Path_Class, Table_Name, Key_Name, Identifier_Name, prefix_table_name, link_table_name) VALUES
('configcategory', 1, NULL, 'XoopsConfigCategoryHandler', '/kernel/configcategory.php', NULL, NULL, NULL, NULL, NULL, NULL);

For use a new class I put 0 in this first row and i put this row:
INSERT INTO xoops_handlerconfig (Name, Active, Class_Name, Handler_Class_Name, Path_Handler_Class, Path_Class, Table_Name, Key_Name, Identifier_Name, prefix_table_name, link_table_name) VALUES
('configcategory', 1, 'XoopsConfigCategory', 'XoopsPersistableObjectHandler', '/kernel/object.php', '/kernel/configcategory.class.php', 'configcategory', 'confcat_id', NULL, NULL, NULL);

You can see i just use XoopsPersistableObjectHandler for this, i put in my table all parameters for the XoopsPersistableObjectHandler constructor
$table
$className
$keyName
$identifierName

then with simple object with just standard method you don't need a specific handler, i just use XoopsPersistableObjectHandler with good parameters => less code for same result.

This feature i think is good (the work it's not finalyze), you can change easily the class you use then you can have a new class with new table for user with some adding column, for developement and test it's easily to change implementation you want, tomorrow if you want to rename class file or to put in folder, you don't have to modify code, just parameter etc...

I think XoopsObjectHandler is an abstract, but XoopsPersistableObjectHandler is not an abstract.
I put here in example my actual xoopsObject.php with xoopsObject, XoopsObjectHandler and XoopsPersistableObjectHandler, i take XoopsPersistableObjectHandler from 2.2 and i make just optimization with the use of cleanvars, and one or two correction on insert (the flag isNew ...), i'm working on allways (for joint table) then there is adding parameter
<?php
// $Id: object.php 762 2006-09-24 21:59:34Z phppp $
// ------------------------------------------------------------------------ //
// XOOPS - PHP Content Management System //
// Copyright (c) 2000 XOOPS.org //
// <http://www.xoops.org/> //
// ------------------------------------------------------------------------ //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// You may not change or alter any portion of this comment or credits //
// of supporting developers from this source code or any supporting //
// source code which is considered copyrighted (c) material of the //
// original comment or credit authors. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program; if not, write to the Free Software //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //
// ------------------------------------------------------------------------ //
// Author: Kazumi Ono (AKA onokazu) //
// URL: http://www.myweb.ne.jp/, http://www.xoops.org/, http://jp.xoops.org/ //
// Project: The XOOPS Project //
// ------------------------------------------------------------------------- //

/
@package kernel
@copyright copyright &copy; 2000 XOOPS.org
*/

/#@+
Xoops object datatype
/
define('XOBJ_DTYPE_TXTBOX', 1);
define('XOBJ_DTYPE_TXTAREA', 2);
define('XOBJ_DTYPE_INT', 3);
define('XOBJ_DTYPE_URL', 4);
define('XOBJ_DTYPE_EMAIL', 5);
define('XOBJ_DTYPE_ARRAY', 6);
define('XOBJ_DTYPE_OTHER', 7);
define('XOBJ_DTYPE_SOURCE', 8);
define('XOBJ_DTYPE_STIME', 9);
define('XOBJ_DTYPE_MTIME', 10);
define('XOBJ_DTYPE_LTIME', 11);
/*#@-/

/
Base class for all objects in the Xoops kernel (and beyond)

@author <p>Kazumi Ono (AKA onokazu)</p><p>Lionel FORTE aka Garrath, Garrath_fr for optimisation and translate to php5</p>
@copyright copyright &copy; 2000 XOOPS.org
* @package kernel
/
class XoopsObject
{

/
holds all variables(properties) of an object

@var array
@access protected
/
protected $vars = array();

/
variables cleaned for store in DB

@var array
@access protected
*/
//TODO a repasser en protected quand toutes les classes auront evolué
public $cleanVars = array();

/
is it a newly created object?

@var bool
@access private
*/
protected $_isNew = false;

/
has any of the values been modified?

@var bool
@access private
*/
private $_isDirty = false;

/
errors

@var array
@access private
*/
private $_errors = array();

/
additional filters registered dynamically by a child class object

@access private
/
private $_filters = array();

/
constructor

normally, this is called from child classes only
@access public
*/
public function __construct()
{
}

/#@+
used for new/clone objects

@access public
/
public function setNew()
{
$this->_isNew = true;
}
public function unsetNew()
{
$this->_isNew = false;
}
public function isNew()
{
return $this->_isNew;
}
/
#@-*/

/#@+
mark modified objects as dirty

used for modified objects only
@access public
*/
public function setDirty()
{
$this->_isDirty = true;
}
public function unsetDirty()
{
$this->_isDirty = false;
}
public function isDirty()
{
return $this->_isDirty;
}
/
#@-*/

/
initialize variables for the object

@access public
@param string $key
@param int $data_type set to one of XOBJ_DTYPE_XXX constants (set to XOBJ_DTYPE_OTHER if no data type ckecking nor text sanitizing is required)
@param mixed
@param bool $required require html form input?
@param int $maxlength for XOBJ_DTYPE_TXTBOX type only
@param string $option does this data have any select options?
/
public function initVar($key, $data_type, $value = null, $required = false, $maxlength = null, $options = '')
{
$this->vars[$key] = array('value' => $value, 'required' => $required, 'data_type' => $data_type, 'maxlength' => $maxlength, 'changed' => false, 'options' => $options);
}

/
assign a value to a variable

@access public
@param string $key name of the variable to assign
@param mixed $value value to assign
/
public function assignVar($key, $value)
{
$key = strtolower($key);
if (isset($value) && isset($this->vars[$key])) {
$this->vars[$key]['value'] =& $value;
}
}

/
assign values to multiple variables in a batch

@access private
@param array $var_array associative array of values to assign
*/
public function assignVars($var_arr)
{
foreach ($var_arr as $key => $value) {
$this->assignVar($key, $value);
}
}

/
assign a value to a variable

@access public
@param string $key name of the variable to assign
@param mixed $value value to assign
@param bool $not_gpc
*/
public function setVar($key, $value, $not_gpc = false)
{
$key = strtolower($key);
if (!empty($key) && isset($value) && isset($this->vars[$key]) && !($this->vars[$key]['value'] == $value)) {
$this->vars[$key]['value'] =& $value;
$this->vars[$key]['not_gpc'] = $not_gpc;
$this->vars[$key]['changed'] = true;
$this->setDirty();
}
}

/
assign values to multiple variables in a batch

@access private
@param array $var_arr associative array of values to assign
@param bool $not_gpc
/
public function setVars($var_arr, $not_gpc = false)
{
foreach ($var_arr as $key => $value) {
$this->setVar($key, $value, $not_gpc);
}
}

/
Assign values to multiple variables in a batch

Meant for a CGI contenxt:
- prefixed CGI args are considered save
- avoids polluting of namespace with CGI args

@access private
@param array $var_arr associative array of values to assign
@param string $pref prefix (only keys starting with the prefix will be set)
/
public function setFormVars($var_arr=null, $pref='xo_', $not_gpc=false) {
$len = strlen($pref);
foreach ($var_arr as $key => $value) {
if ($pref == substr($key,0,$len)) {
$this->setVar(substr($key,$len), $value, $not_gpc);
}
}
}

/
returns all variables for the object

@access public
@return array associative array of key->value pairs
*/
public function getVars()
{
return $this->vars;
}
/

Returns the values of the specified variables

@param mixed $keys An array containing the names of the keys to retrieve, or null to get all of them
@param string $format Format to use (see getVar)
@param int $maxDepth Maximum level of recursion to use if some vars are objects themselves
@return array associative array of key->value pairs
/
public function getValues( $keys = null, $format = 's', $maxDepth = 1 ) {
if ( !isset( $keys ) ) {
$keys = array_keys( $this->vars );
}
$vars = array();
foreach ( $keys as $key ) {
if ( isset( $this->vars[$key] ) ) {
if ( is_object( $this->vars[$key] ) && is_a( $this->vars[$key], 'XoopsObject' ) ) {
if ( $maxDepth ) {
$vars[$key] = $this->vars[$key]->getValues( null, $format, $maxDepth - 1 );
}
} else {
$vars[$key] = $this->getVar( $key, $format );
}
}
}
return $vars;
}
/

returns a specific variable for the object in a proper format

@access public
@param string $key key of the object's variable to be returned
@param string $format format to use for the output
@return mixed formatted value of the variable
/
public function getVar($key, $format = 's')
{
$ret = $this->vars[$key]['value'];
switch ($this->vars[$key]['data_type']) {

case XOBJ_DTYPE_TXTBOX:
switch (strtolower($format)) {
case 's':
case 'show':
case 'e':
case 'edit':
$ts =& MyTextSanitizer::getInstance();
return $ts->htmlSpecialChars($ret);
break 1;
case 'p':
case 'preview':
case 'f':
case 'formpreview':
$ts =& MyTextSanitizer::getInstance();
return $ts->htmlSpecialChars($ts->stripSlashesGPC($ret));
break 1;
case 'n':
case 'none':
default:
break 1;
}
break;
case XOBJ_DTYPE_TXTAREA:
switch (strtolower($format)) {
case 's':
case 'show':
$ts =& MyTextSanitizer::getInstance();
$html = !empty($this->vars['dohtml']['value']) ? 1 : 0;
$xcode = (!isset($this->vars['doxcode']['value']) || $this->vars['doxcode']['value'] == 1) ? 1 : 0;
$smiley = (!isset($this->vars['dosmiley']['value']) || $this->vars['dosmiley']['value'] == 1) ? 1 : 0;
$image = (!isset($this->vars['doimage']['value']) || $this->vars['doimage']['value'] == 1) ? 1 : 0;
$br = (!isset($this->vars['dobr']['value']) || $this->vars['dobr']['value'] == 1) ? 1 : 0;
return $ts->displayTarea($ret, $html, $smiley, $xcode, $image, $br);
break 1;
case 'e':
case 'edit':
return htmlspecialchars($ret, ENT_QUOTES);
break 1;
case 'p':
case 'preview':
$ts =& MyTextSanitizer::getInstance();
$html = !empty($this->vars['dohtml']['value']) ? 1 : 0;
$xcode = (!isset($this->vars['doxcode']['value']) || $this->vars['doxcode']['value'] == 1) ? 1 : 0;
$smiley = (!isset($this->vars['dosmiley']['value']) || $this->vars['dosmiley']['value'] == 1) ? 1 : 0;
$image = (!isset($this->vars['doimage']['value']) || $this->vars['doimage']['value'] == 1) ? 1 : 0;
$br = (!isset($this->vars['dobr']['value']) || $this->vars['dobr']['value'] == 1) ? 1 : 0;
return $ts->previewTarea($ret, $html, $smiley, $xcode, $image, $br);
break 1;
case 'f':
case 'formpreview':
$ts =& MyTextSanitizer::getInstance();
return htmlspecialchars($ts->stripSlashesGPC($ret), ENT_QUOTES);
break 1;
case 'n':
case 'none':
default:
break 1;
}
break;
case XOBJ_DTYPE_ARRAY:
$ret =& unserialize($ret);
break;
case XOBJ_DTYPE_SOURCE:
switch (strtolower($format)) {
case 's':
case 'show':
break 1;
case 'e':
case 'edit':
return htmlspecialchars($ret, ENT_QUOTES);
break 1;
case 'p':
case 'preview':
$ts =& MyTextSanitizer::getInstance();
return $ts->stripSlashesGPC($ret);
break 1;
case 'f':
case 'formpreview':
$ts =& MyTextSanitizer::getInstance();
return htmlspecialchars($ts->stripSlashesGPC($ret), ENT_QUOTES);
break 1;
case 'n':
case 'none':
default:
break 1;
}
break;
default:
if ($this->vars[$key]['options'] != '' && $ret != '') {
switch (strtolower($format)) {
case 's':
case 'show':
$selected = explode('|', $ret);
$options = explode('|', $this->vars[$key]['options']);
$i = 1;
$ret = array();
foreach ($options as $op) {
if (in_array($i, $selected)) {
$ret[] = $op;
}
$i++;
}
return implode(', ', $ret);
case 'e':
case 'edit':
$ret = explode('|', $ret);
break 1;
default:
break 1;
}

}
break;
}
return $ret;
}

public function resetCleanVars(){
$this->cleanVars = array();
}

/
clean values of all variables of the object for storage.
also add slashes whereever needed and put quote if it's necessary


@return null if there is errors, or cleanVars table<p>cleanVars contains just modified var.</p>
@access public
@deprecated version - 4 nov. 07
/
public function cleanVars()
{
$ts =& MyTextSanitizer::getInstance();
$existing_errors = $this->getErrors();
$this->_errors = array();
foreach ($this->vars as $k => $v) {
$cleanv = $v['value'];
if (!$v['changed']) {
} else {
$cleanv = is_string($cleanv) ? trim($cleanv) : $cleanv;
switch ($v['data_type']) {
case XOBJ_DTYPE_TXTBOX:
if ($v['required'] && $cleanv != '0' && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if (isset($v['maxlength']) && strlen($cleanv) > intval($v['maxlength'])) {
$this->setErrors( sprintf( _XOBJ_ERR_SHORTERTHAN, $k, intval( $v['maxlength'] ) ) );
continue;
}
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
} else {
$cleanv = $ts->censorString($cleanv);
}
break;
case XOBJ_DTYPE_TXTAREA:
if ($v['required'] && $cleanv != '0' && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
} else {
$cleanv = $ts->censorString($cleanv);
}
break;
case XOBJ_DTYPE_SOURCE:
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($cleanv);
} else {
$cleanv = $cleanv;
}
break;
case XOBJ_DTYPE_INT:
$cleanv = intval($cleanv);
break;
case XOBJ_DTYPE_EMAIL:
if ($v['required'] && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if ($cleanv != '' && !preg_match("/^[_a-z0-9-]+(.[_a-z0-9-]+)@[a-z0-9-]+([.][a-z0-9-]+)+$/i",$cleanv)) {
$this->setErrors("Invalid Email");
continue;
}
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($cleanv);
}
break;
case XOBJ_DTYPE_URL:
if ($v['required'] && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if ($cleanv != '' && !preg_match("/^http[s]
:\/\//i", $cleanv)) {
$cleanv = 'http://' . $cleanv;
}
if (!$v['not_gpc']) {
$cleanv =& $ts->stripSlashesGPC($cleanv);
}
break;
case XOBJ_DTYPE_ARRAY:
$cleanv = serialize($cleanv);
break;
case XOBJ_DTYPE_STIME:
case XOBJ_DTYPE_MTIME:
case XOBJ_DTYPE_LTIME:
$cleanv = !is_string($cleanv) ? intval($cleanv) : strtotime($cleanv);
break;
default:
break;
}
}
$this->cleanVars[$k] =& $cleanv;
unset($cleanv);
}
if (count($this->_errors) > 0) {
$this->_errors = array_merge($existing_errors, $this->_errors);
return false;
}
$this->_errors = array_merge($existing_errors, $this->_errors);
$this->unsetDirty();
return true;
}

/
clean values of all modified variables of the object for storage.
also add slashes whereever needed and put quote if it's necessary


@return null if there is errors, or cleanVars table<p>cleanVars contains just modified var.</p>
@access public
/
public function getCleanVars()
{
$ts =& MyTextSanitizer::getInstance();
$existing_errors = $this->getErrors();
$this->_errors = array();
foreach ($this->vars as $k => $v) {
$cleanv = $v['value'];
if (!$v['changed']) {
} else {
$cleanv = is_string($cleanv) ? trim($cleanv) : $cleanv;
switch ($v['data_type']) {
case XOBJ_DTYPE_TXTBOX:
if ($v['required'] && $cleanv != '0' && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if (isset($v['maxlength']) && strlen($cleanv) > intval($v['maxlength'])) {
$this->setErrors( sprintf( _XOBJ_ERR_SHORTERTHAN, $k, intval( $v['maxlength'] ) ) );
continue;
}
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
} else {
$cleanv = $ts->censorString($cleanv);
}
break;
case XOBJ_DTYPE_TXTAREA:
if ($v['required'] && $cleanv != '0' && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
} else {
$cleanv = $ts->censorString($cleanv);
}
break;
case XOBJ_DTYPE_SOURCE:
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($cleanv);
} else {
$cleanv = $cleanv;
}
break;
case XOBJ_DTYPE_INT:
$cleanv = intval($cleanv);
break;
case XOBJ_DTYPE_EMAIL:
if ($v['required'] && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if ($cleanv != '' && !preg_match("/^[_a-z0-9-]+(.[_a-z0-9-]+)
@[a-z0-9-]+([.][a-z0-9-]+)+$/i",$cleanv)) {
$this->setErrors("Invalid Email");
continue;
}
if (!$v['not_gpc']) {
$cleanv = $ts->stripSlashesGPC($cleanv);
}
break;
case XOBJ_DTYPE_URL:
if ($v['required'] && $cleanv == '') {
$this->setErrors( sprintf( _XOBJ_ERR_REQUIRED, $k ) );
continue;
}
if ($cleanv != '' && !preg_match("/^http[s]*:\/\//i", $cleanv)) {
$cleanv = 'http://' . $cleanv;
}
if (!$v['not_gpc']) {
$cleanv =& $ts->stripSlashesGPC($cleanv);
}
break;
case XOBJ_DTYPE_ARRAY:
$cleanv = serialize($cleanv);
break;
case XOBJ_DTYPE_STIME:
case XOBJ_DTYPE_MTIME:
case XOBJ_DTYPE_LTIME:
$cleanv = !is_string($cleanv) ? intval($cleanv) : strtotime($cleanv);
break;
default:
break;
}
//TODO voir cette histoire de $GLOBALS['xoopsDB']
if ($v['data_type'] == XOBJ_DTYPE_INT) {
$cleanv = intval($cleanv);
} elseif ( is_array( $cleanv ) ) {
$cleanv = $GLOBALS['xoopsDB']->quoteString( implode( ',', $cleanv ) );
} else {
$cleanv= $GLOBALS['xoopsDB']->quoteString($cleanv);
}
$this->cleanVars[$k] =& $cleanv;
}
unset($cleanv);
}
if (count($this->_errors) > 0) {
$this->_errors = array_merge($existing_errors, $this->_errors);
return null;
}
$this->_errors = array_merge($existing_errors, $this->_errors);
$this->unsetDirty();
if (count($this->cleanVars))
return $this->cleanVars;
return null;
}

/
dynamically register additional filter for the object

@param string $filtername name of the filter
@access public
*/
public function registerFilter($filtername)
{
$this->_filters[] = $filtername;
}

/
load all additional filters that have been registered to the object

@access private
/
public function _loadFilters()
{
//include_once XOOPS_ROOT_PATH.'/class/filters/filter.php';
//foreach ($this->_filters as $f) {
// include_once XOOPS_ROOT_PATH.'/class/filters/'.strtolower($f).'php';
//}
}

/
create a clone(copy) of the current object

@access public
@return object clone
*/
public function xoopsClone()
{
$class = get_class($this);
$clone = new $class();
foreach ($this->vars as $k => $v) {
$clone->assignVar($k, $v['value']);
}
// need this to notify the handler class that this is a newly created object
$clone->setNew();
return $clone;
}

/
add an error

@param string $value error to add
@access public
*/
public function setErrors($err_str)
{
$this->_errors[] = trim($err_str);
}

/
return the errors for this object as an array

@return array an array of errors
@access public
*/
public function getErrors()
{
return $this->_errors;
}

/
return the errors for this object as html

@return string html listing the errors
@access public
*/
public function getHtmlErrors()
{
$ret = '<h4>Errors</h4>';
if (!empty($this->_errors)) {
foreach ($this->_errors as $error) {
$ret .= $error.'<br />';
}
} else {
$ret .= 'None<br />';
}
return $ret;
}
}

/
XOOPS object handler class.
This class is an abstract class of handler classes that are responsible for providing
data access mechanisms to the data source of its corresponsing data objects
@package kernel
@abstract

@author <p>Kazumi Ono <onokazu@xoops.org></p><p>Lionel FORTE aka Garrath, Garrath_fr for translation to php5</p>
@copyright copyright &copy; 2000 The XOOPS Project
*/
abstract class XoopsObjectHandler
{

/
holds referenced to {@link XoopsDatabase} class object

@var object
@see XoopsDatabase
@access protected
/
protected $db;

//
/
called from child classes only

@param object $db reference to the {@link XoopsDatabase} object
@access protected
*/
public function __construct($db)
{
$this->db = $db;
}

/
creates a new object

@abstract
/
public function create()
{
}

/
gets a value object

@param int $int_id
@abstract
*/
public function get($int_id)
{
}

/
insert/update object

@param object $object
@abstract
*/
public function insert($object)
{
}

/
delete obejct from database

@param object $object
@abstract
*/
public function delete($object)
{
}

}

/
Persistable Object Handler class.
This class is responsible for providing data access mechanisms to the data source
of derived class objects.

@author <p>Jan Keller Pedersen <mithrandir@xoops.org> - IDG Danmark A/S <www.idg.dk></p><p>Lionel FORTE aka Garrath, Garrath_fr for optimisation and translation to php5</p>
@copyright copyright (c) 2000-2004 XOOPS.org
@package Kernel
/
class XoopsPersistableObjectHandler extends XoopsObjectHandler {

/#@+
Information about the class, the handler is managing

@var string
/
protected $table;
protected $keyName;
protected $prefixSql;
protected $linkHandler;
protected $linkId;
private $className;
private $identifierName;

/
Constructor - called from child classes
@param object $db {@link XoopsDatabase} object
@param string $tablename Name of database table
@param string $classname Name of Class, this handler is managing
@param string $keyname Name of the property, holding the key

@return void
/
public function construct($db, $tablename, $classname, $keyname, $identifierName = false, $prefix = null, $linkTableName = null) {
parent::
construct($db);
$this->table = $db->prefix($tablename);
$this->keyName = $keyname;
$this->linkId = $keyname;
$this->className = $classname;
$this->prefixSql = $prefix;
if ($identifierName != false) {
$this->identifierName = $identifierName;
}

if (isset($linkTableName) and $linkTableName){
echo '<b>construction de '.$classname.': appel de creation lien '.$linkTableName.'</b><br />';
$this->linkHandler = xoops_gethandler($linkTableName);
}
}

/

@param $obj to test if is an instance of $this->className
@return bool
/
protected function isIntanceOf($obj){
return (class_exists($this->className) && $obj instanceof $this->className);
}

/
create a new user

@param bool $isNew Flag the new objects as "new"?

@return object
/
public function create($isNew = true) {
$classname = $this->className;
//$isNew = true;
//echo 'create '.$isNew.'<br/>';
$obj = new $classname ();
if ($isNew == true) {
$obj->setNew();
}
else {
$obj->unsetNew();
}
return $obj;
}

/
retrieve an object

@param mixed $id ID of the object - or array of ids for joint keys. Joint keys MUST be given in the same order as in the constructor
@param bool $as_object whether to return an object or an array
@return mixed reference to the object, FALSE if failed
/
public function get($id, $as_object = true) {
if (is_array($this->keyName)) {
$criteria = new CriteriaCompo();
for ($i = 0; $i < count($this->keyName); $i++) {
$criteria->add(new Criteria($this->keyName[$i], intval($id[$i]), '=', $this->prefixSql));
}
}
else {
$criteria = new Criteria($this->keyName, intval($id), '=', $this->prefixSql);
}
$criteria->setLimit(1);
$obj_array = $this->getObjects($criteria, false, $as_object);
//echo count($obj_array).'<br/>';
if (count($obj_array) != 1) {
return $this->create();
}
return $obj_array[0];
}

/
retrieve objects from the database

@param object $criteria {@link CriteriaElement} conditions to be met
@param bool $id_as_key use the ID as key for the array?
@param bool $as_object return an array of objects?

@return array
/
public function getObjects($criteria = null, $id_as_key = false, $as_object = true)
{
$ret = array();
$limit = $start = 0;
$sql = 'SELECT * FROM '.$this->table;
if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
$sql .= ' '.$criteria->renderWhere();
if ($criteria->getSort() != '') {
$sql .= ' ORDER BY '.$criteria->getSort().' '.$criteria->getOrder();
}
$limit = $criteria->getLimit();
$start = $criteria->getStart();
}
$result = $this->db->query($sql, $limit, $start);
if ($result) {
$ret = $this->convertResultSet($result, $id_as_key, $as_object);
}
return $ret;
}

/
Convert a database resultset to a returnable array

@param object $result database resultset
@param bool $id_as_key - should NOT be used with joint keys
@param bool $as_object

@return array
/
protected function convertResultSet($result, $id_as_key = false, $as_object = true) {
$ret = array();

while ($myrow = $this->db->fetchArray($result)) {
$obj = $this->create(false);
$obj->assignVars($myrow);

if (!$id_as_key) {
if ($as_object) {
$ret[] = $obj;
}
else {
$row = array();
$vars = $obj->getVars();
foreach (array_keys($vars) as $i) {
$row[$i] = $obj->getVar($i);
}
$ret[] = $row;
}
} else {
if ($as_object) {
$ret[$myrow[$this->keyName]] = $obj;
}
else {
$row = array();
$vars = $obj->getVars();
foreach (array_keys($vars) as $i) {
$row[$i] = $obj->getVar($i);
}
$ret[$myrow[$this->keyName]] = $row;
}
}
unset($obj);
}

return $ret;
}

/
Retrieve a list of objects as arrays - DON'T USE WITH JOINT KEYS

@param object $criteria {@link CriteriaElement} conditions to be met
@param int $limit Max number of objects to fetch
@param int $start Which record to start at

@return array
/
public function getList($criteria = null, $limit = 0, $start = 0) {
$ret = array();
if ($criteria == null) {
$criteria = new CriteriaCompo();
}

if ($criteria->getSort() == '') {
$criteria->setSort($this->identifierName);
}

$sql = 'SELECT '.$this->keyName;
if(!empty($this->identifierName)){
$sql .= ', '.$this->identifierName;
}
$sql .= ' FROM '.$this->table;
if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
$sql .= ' '.$criteria->renderWhere();
if ($criteria->getSort() != '') {
$sql .= ' ORDER BY '.$criteria->getSort().' '.$criteria->getOrder();
}
$limit = $criteria->getLimit();
$start = $criteria->getStart();
}
$result = $this->db->query($sql, $limit, $start);
if ($result) {
$myts =& MyTextSanitizer::getInstance();
while ($myrow = $this->db->fetchArray($result)) {
//identifiers should be textboxes, so sanitize them like that
$ret[$myrow[$this->keyName]] = empty($this->identifierName)?1:$myts->htmlSpecialChars($myrow[$this->identifierName]);
}
}

return $ret;
}

/**

  • count objects matching a condition
  • @param object $criteria {@link CriteriaElement} to match
  • @return int count of objects
    /
    public function getCount($criteria = null)
    {
    $field = '';
    $groupby = false;
    if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
    if ($criteria->groupby != '') {
    $groupby = true;
    $field = $criteria->groupby.', '; //Not entirely secure unless you KNOW that no criteria's groupby clause is going to be mis-used
    }
    }
    $sql = 'SELECT '.$field.'COUNT(
    ) FROM '.$this->table;
    if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
    $sql .= ' '.$criteria->renderWhere();
    if ($criteria->groupby != '') {
    $sql .= $criteria->getGroupby();
    }
    }
    $result = $this->db->query($sql);
    if (!$result) {
    return 0;
    }
    if ($groupby == false) {
    list($count) = $this->db->fetchRow($result);
    return $count;
    }
    else {
    $ret = array();
    while (list($id, $count) = $this->db->fetchRow($result)) {
    $ret[$id] = $count;
    }
    return $ret;
    }
    }

/
delete an object from the database

@param object $obj reference to the object to delete
@param bool $force
@return bool FALSE if failed.
/
public function delete($obj, $force = false)
{
if (!$this->isIntanceOf($obj)){
$obj->setErrors(get_class($obj).' Differs from '.$this->className);
return false;
}

if (is_array($this->keyName)) {
$clause = array();
for ($i = 0; $i < count($this->keyName); $i++) {
$clause[] = $this->keyName[$i].' = '.$obj->getVar($this->keyName[$i]);
}
$whereclause = implode(' AND ', $clause);
}
else {
$whereclause = $this->keyName.' = '.$obj->getVar($this->keyName);
}
$sql = 'DELETE FROM '.$this->table.' WHERE '.$whereclause;
if (false != $force) {
$result = $this->db->queryF($sql);
} else {
$result = $this->db->query($sql);
}

return $result;
}

/
insert a new object in the database

@param object $obj reference to the object
@param bool $force whether to force the query execution despite security settings
@param bool $checkObject check if the object is dirty and clean the attributes
@return bool FALSE if failed, TRUE if already present and unchanged or successful
*/
public function insert($obj, $force = false, $checkObject = true)
{
if ($checkObject != false) {
if (!is_object($obj)) {
return false;
}

if (!$this->isIntanceOf($obj)){
$obj->setErrors(get_class($obj).' Differs from '.$this->className);
return false;
}
if (!$obj->isDirty()) {
$obj->setErrors('Not dirty'); //will usually not be outputted as errors are not displayed when the method returns true, but it can be helpful when troubleshooting code - Mith
return true;
}
}

if (!($cleanvars=$obj->getCleanVars())) {
$obj->setErrors('clean vars failed');
return false;
}

if ($obj->isNew()) {
// Cela sert a rien sur MySQL le Id sequentiel est automatiquement genere ca sert a rien d'aller le chercher avant l'insert
// if (!is_array($this->keyName)) {
// if ($cleanvars[$this->keyName] < 1) {
// $cleanvars[$this->keyName] = $this->db->genId($this->table.'_'.$this->keyName.'_seq');
// }
// }
$sql = 'INSERT INTO '.$this->table.' ('.implode(',', array_keys($cleanvars)).') VALUES ('.implode(',', array_values($cleanvars)) .')';
} else {
$sql = 'UPDATE '.$this->table.' SET';
foreach ($cleanvars as $key => $value) {
if ((!is_array($this->keyName) && $key == $this->keyName) || (is_array($this->keyName) && in_array($key, $this->keyName))) {
continue;
}
if (isset($notfirst) ) {
$sql .= ',';
}
$sql .= ' '.$key.' = '.$value;
$notfirst = true;
}
if (is_array($this->keyName)) {
$whereclause = '';
for ($i = 0; $i < count($this->keyName); $i++) {
if ($i > 0) {
$whereclause .= ' AND ';
}
$whereclause .= $this->keyName[$i].' = '.$obj->getVar($this->keyName[$i]);
}
}
else {
$whereclause = $this->keyName.' = '.$obj->getVar($this->keyName);
}
$sql .= ' WHERE '.$whereclause;
}

$queryFunc = empty($force)?'query':'queryF';
if (!$this->db->{$queryFunc}($sql)) {
$obj->setErrors('insert failed: '.$sql);
return false;
}

$obj->resetCleanVars();
if ($obj->isNew()){
if ( !is_array($this->keyName)) {
$obj->assignVar($this->keyName, $this->db->getInsertId());
}
$obj->unsetNew(); //correction
}
return true;
}

/
Change a value for objects with a certain criteria

@param string $fieldname Name of the field
@param string $fieldvalue Value to write
@param object $criteria {@link CriteriaElement}

* @return bool
/
public function updateAll($fieldname, $fieldvalue, $criteria = null, $force = false)
{
$set_clause = $fieldname . ' = ';
if ( is_numeric( $fieldvalue ) ) {
$set_clause .= $fieldvalue;
} elseif ( is_array( $fieldvalue ) ) {
$set_clause .= $this->db->quoteString( implode( ',', $fieldvalue ) );
} else {
$set_clause .= $this->db->quoteString( $fieldvalue );
}
$sql = 'UPDATE '.$this->table.' SET '.$set_clause;
if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
$sql .= ' '.$criteria->renderWhere();
}

$queryFunc = empty($force)?'query':'queryF';
return $this->db->{$queryFunc}($sql);
}

/
delete all objects meeting the conditions

@param object $criteria {@link CriteriaElement} with conditions to meet
@return bool
*/
public function deleteAll($criteria = null)
{
$sql = 'DELETE FROM '.$this->table;
if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
$sql .= ' '.$criteria->renderWhere();
}
if (!$this->db->query($sql)) {
return false;
}
$rows = $this->db->getAffectedRows();
return $rows > 0 ? $rows : true;
}
}
?>