File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/api/class.engine.php
<?php
/**
* This file contains the iwp_engine class
*
* @version $Id$
*
*
* @package IWP
* @subpackage IWP_API
*/
/**
* IWP Engine Class
* This is the base class from which most other content classes extend from.
* It has the base functions used by different classes; save, load,
* db setup plus getters and setters
*
* @package IWP
* @subpackage IWP_API
*/
abstract class iwp_engine extends iwp_base {
/**
* TableName
* This is the full name of the current working database table.
* This is set in the SetTableName function by combining the $baseTableName
* and $tablePrefix functions.
*
* @var String $TableName
*
* @see GetTableName
* @see SetTableName
*/
protected $TableName = null;
/**
* baseTableName
* This is the name of the current working database table without its prefix.
* This is set in the child class declaration.
*
* @var String $baseTableName
*
* @see SetTableName
*/
protected $baseTableName = '';
/**
* primaryKey
* This is the primary key field name for the current working db table.
*
* @var String $primaryKey
*
* @see Load
* @see Save
* @see LoadByField
* @see LoadMulti
* @see ValidColumn
*/
protected $primaryKey = null;
/**
* id
* This is the id number of the current db row held in the class.
* This number is the value of the primary key field of the current db table.
* This is a protected member variable and can only be changed from within
* the class to ensure its kept a valid integer
*
* @var integer $id
*
* @see SetId
* @see GetId
*/
protected $id = 0;
/**
* data
* This is an array of the current table's columns. This also contains the
* current working data.
* Most sub-classes will not hold the primary key in here, but those using
* the 'multi' option (i.e. using LoadMulti() instead of Load()) will as they
* need the primary key for each row.
* This is a duplicate of the final variable $_columns (or an arrayed version if its a 'multi' class)
*
* @var array $data
*
* @see Save
* @see Load
* @see ValidColumn
*/
protected $data = array();
/**
* _columns
* This is an array of the current table's columns. This array stays blank and is used
* as a table structure reference.
* In the sub-classes it is declared as a final private variable with the table column names
*
* @var array _columns
*
* @see ResetColumns
* @see ValidColumn
*/
protected $_columns = array();
/**
* Public read-only accessor for the _columns protected member.
*
* @return array
*
* @see _columns
*/
public function GetColumns ()
{
return $this->_columns;
}
/**
* validation
* This is an array of validation functions to perform on the fields in $data before the values are saved to the database
* Each element of the array has the fieldname for the key and an array of function names from the iwp_validation class as the value
*
* @var array validation
*
**/
protected $validation = array();
/**
* ErrorHistory
* An array of all the error messages that have occurred in this instantiation, useful for debugging.
*
* @var array ErrorHistory
*
* @see SetError
* @see GetErrorHistory
*/
protected $ErrorHistory = array();
/**
* Error
* The last error message recorded by this instantiation
*
* @var string Error
*
* @see SetError
* @see GetError
*/
public $Error = '';
/**
* tablePrefix
* This is the table prefix and is set in the constructor. It should be set automatically if the GetConfig('tablePrefix') function exists
*
* @var string tablePrefix
*
* @see SetTablePrefix
**/
protected static $tablePrefix = '';
/**
* __construct
* This is the constructor function of the class. This must be called by the sub-classes to set up the database table names
*
* @return void Doesn't return anything
*
* @see SetTableName
* @see SetTablePrefix
**/
public function __construct(){
if(function_exists('GetConfig')){
$this->SetTablePrefix(GetConfig('tablePrefix'));
}
$this->SetTableName();
}
/**
* __call
* This is the capture function for any functions that don't actually exist.
* This allows us to do some neat and flexible things.
* This function should not be called directly.
*
* Usage Examples:
*
* Universal setters and getters for variables
* SetMyVar('blah') - This sets $MyVar class variable to have a value of 'blah'
* GetMyVar() - This returns the value of the class variable MyVar
*
* Dynamic data loading:
* LoadByName('Jordie') - This loads the class's data from the database where the
* field is 'Name' and its value is 'Jordie'.
*
* @param $method string The function name being called
* @param $args array The array of arguements that were passed to the function
*
* @return mixed The result depends on the inputs and what other methods are called
**/
public function __call($method, $args){
if(iwp_strtolower(substr($method,0,3)) == 'set'){
if (IWP::$DebugMode) {
// TODO: This might actually be a security problem... lets look into what uses this, and change it to be for specific variables only
$log = "----------------------------------------------------------------------\n";
$log .= date('c') . "\t" . $_SERVER['REQUEST_URI'] . "\n";
$log .= "Set method:\t" . $method . "\n";
$log .= "----------------------------------------------------------------------\n";
$backtraces = debug_backtrace();
foreach ($backtraces as $backtrace) {
$log .= (@$backtrace['line'] ? $backtrace['line'] : '?') . "\t";
$log .= (@$backtrace['file'] ? $backtrace['file'] : '?') . "\t";
$log .= @$backtrace['class'] . "\t";
$log .= @$backtrace['function'] . "\n";
}
$log .= "----------------------------------------------------------------------\n";
$log .= "\n";
@file_put_contents('tmp/set_members.txt', $log, FILE_APPEND);
}
$var = substr($method,3);
$this->$var = $args[0];
}elseif(iwp_strtolower(substr($method,0,3)) == 'get'){
if (IWP::$DebugMode) {
$log = "----------------------------------------------------------------------\n";
$log .= date('c') . "\t" . $_SERVER['REQUEST_URI'] . "\n";
$log .= "Get method:\t" . $method . "\n";
$log .= "----------------------------------------------------------------------\n";
$backtraces = debug_backtrace();
foreach ($backtraces as $backtrace) {
$log .= (@$backtrace['line'] ? $backtrace['line'] : '?') . "\t";
$log .= (@$backtrace['file'] ? $backtrace['file'] : '?') . "\t";
$log .= @$backtrace['class'] . "\t";
$log .= @$backtrace['function'] . "\n";
}
$log .= "----------------------------------------------------------------------\n";
$log .= "\n";
@file_put_contents('tmp/get_members.txt', $log, FILE_APPEND);
}
$var = substr($method,3);
if(in_string('by', $var)){
$bits = explode('by', $var);
if($this->ValidColumn(iwp_strtolower($bits[0])) && $this->ValidColumn(iwp_strtolower($bits[1]))){
return $this->db->FirstResult('select `'.iwp_strtolower($bits[0]).'` from where `'.iwp_strtolower($bits[1]).'`="'.$args[0].'"');
}
}
return $this->$var;
}elseif(iwp_strtolower(substr($method,0,6)) == 'loadby'){
$field = iwp_strtolower(substr($method,6));
if(in_array($field, $this->data)){
$this->LoadByField($field, $args[0]);
}
}
if (IWP::$DebugMode) {
$log = "----------------------------------------------------------------------\n";
$log .= date('c') . "\t" . $_SERVER['REQUEST_URI'] . "\n";
$log .= "Unhandled method:\t" . $method . "\n";
$log .= "----------------------------------------------------------------------\n";
$backtraces = debug_backtrace();
foreach ($backtraces as $backtrace) {
$log .= (@$backtrace['line'] ? $backtrace['line'] : '?') . "\t";
$log .= (@$backtrace['file'] ? $backtrace['file'] : '?') . "\t";
$log .= @$backtrace['class'] . "\t";
$log .= @$backtrace['function'] . "\n";
}
$log .= "----------------------------------------------------------------------\n";
$log .= "\n";
@file_put_contents('tmp/undefined_members.txt', $log, FILE_APPEND);
}
return false;
}
/**
* SetTablePrefix
* Sets the tablePrefix variable
*
* @param prefix string The prefix all the tables in the application use, e.g. 'iwp_'
*
* @return void
*
* @see tablePrefix
**/
public function SetTablePrefix($prefix){
$this->tablePrefix = $prefix;
}
/**
* SetTableName
* Sets the tableName variable by combining the tablePrefix and baseTableName variables
*
* @return void
*
* @see tablePrefix
* @see TableName
* @see baseTableName
**/
public function SetTableName(){
$this->TableName = $this->tablePrefix . $this->baseTableName;
}
/**
* Exists
* Checks whether a field and its value exists in the current database table
*
* @param $field string The name of the field to be checked
* @param $value string The value of the field to check if it exists
*
* @return boolean Returns true if it does exist, false otherwise.
**/
public function Exists($field, $value){
if(!is_array($field)){
$field = array($field);
}
if(!is_array($value)){
$value = array($value);
}
foreach($field as $k=>$thisField){
$thisField = $this->valid->FilterAlphaNumeric($thisField);
$where[] = ' `'.$thisField.'`="'.$this->db->Quote($value[$k]).'" ';
}
$count = $this->db->FetchOne('select count(*) from ' . $this->GetTableName() . ' where '.implode('and', $where));
if($count > 0){
return true;
}else{
return false;
}
}
/**
* ResetColumns
* Resets the columns variable to the _columns variable clearing out all data
*
* @return void
**/
function ResetColumns(){
$this->data = $this->_columns;
}
/**
* ResetColumnsMulti
* Resets the columns variable in a manner suitable for LoadMulti to the _columns variable clearing out all data
*
* @return void
*/
function ResetColumnsMulti(){
$this->data = array($this->_columns);
}
/**
* SetError
* Sets the Error class variable to the string passed in as $error. It also adds it to the ErrorHistory array
*
* @param $error string The error string to be set
*
* @return void
**/
function SetError($error){
$this->ErrorHistory[] = $error;
$this->ErrorHistory = CleanArray($this->ErrorHistory);
$this->Error = $error;
}
/**
* GetError
* This returns the Error class variable
*
* @return string The value of Error is returned
**/
function GetError(){
return $this->Error;
}
/**
* GetErrorHistory
* Returns the array variable ErrorHistory that contains all messages that have been set to Error in the current
* instantiation of the class.
*
* @return array The list of error messages
**/
function GetErrorHistory(){
return $this->ErrorHistory;
}
/**
* LoadByField
* This is a function that loads the class's current $data from the database table base on a field value combination
* These values can only be strings.
*
* @param $fieldname string The name of the field to load the data by
* @param $fieldvalue string The value of the field to load the data by
*
* @return void
**/
public function LoadByField($fieldname, $fieldvalue, $multi=false){
if($multi === false){
$result = $this->db->FetchQuery('select * from '.$this->GetTableName() .' where `'.$fieldname.'`="'.$this->db->Quote($fieldvalue).'"');
if(is_array($result) && sizeof($result) > 0){
foreach($result as $field=>$value) {
if(isset($this->data[$field]) && $field != $this->primaryKey){
$this->data[$field] = $value;
}
}
$this->SetId($result[$this->primaryKey]);
}
}else{
$result = $this->db->Query('select * from '.$this->GetTableName() .' where `'.$fieldname.'`="'.$this->db->Quote($fieldvalue).'"');
$this->data = array();
while(($row = $this->db->Fetch($result))){
$this->data[] = $row;
} // end while
}
}
/**
* GetId
* This returns the integer current primary key value.
*
* @return integer The id number or primary key value of the data currently stored
**/
public function GetId(){
return (int)$this->id;
}
/**
* ValidId
* This checks to see if the current Id is value. If its not a positive integer above zero, return false.
*
* @return boolean Whether or not the id number is a positive integer above zero
**/
public function ValidId(){
$id = (int)$this->GetId();
if($id > 0){
return true;
}else{
return false;
}
}
/**
* SetId
* Sets the id or primary key value for the current class.
* This value must be a positive integer so it is checked before being set.
*
* @param $id integer The number value to set the ID to
*
* @return void
**/
public function SetId($id){
$id = (int)$id;
if($id > 0){
$this->id = (int)$id;
return true;
}
return false;
}
/**
* Set
* This sets the current data value of $name to be $value only if $name is a value column of this the current table. Also accepts an associative array of column/value pairs as the $name parameter.
*
* @param string|array $name The name of the field to set/change the value of
* @param string $value The value of the field to set/change (optional but required if $name is string, do not supply a value for this if $name is an array).
*
* @return void
**/
public function Set($name, $value=''){
if (is_string($name)) {
// simple, single-value setter
if ($this->ValidColumn($name)) {
$this->data[$name] = $value;
}
} elseif (is_array($name) || is_object($name)) {
// multi-value set
foreach ($name as $key => $value) {
$this->Set($key, $value);
}
}
}
/**
* Get
* Returns the value from $data of the requested field ($name).
* Whether or not $name is a valid field is also checked first.
*
* @param $name string The name of the field to get the data value for
*
* @return mixed The value of the field requested.
**/
public function Get($name) {
if($this->ValidColumn($name) && isset($this->data[$name])){
return $this->data[$name];
}
return false;
}
/**
* ValidColumn
* Takes a string value and checks it again the final class variable _columns that defines the table structure used
* and returns true if the column exists and false if it doesn't
*
* @param $col string The name of the column/field to check
*
* @return boolean True if it does exist, otherwise false
**/
public function ValidColumn($col) {
return true; // hack for now, should not be this
return in_array($col, $this->_columns); // should be this
}
/**
* Load
* Loads the data from the database table based upon the current primary key name and value
*
* @param $id integer This is optional if the class has an ID set already, or if you want to override it use this.
*
* @return boolean
**/
public function Load($id = null) {
if ($id === null) {
if ($this->ValidId()) {
$id = $this->GetId();
} else {
return false;
}
}
$query = $this->db->Query('SELECT * FROM `' . $this->TableName . '` WHERE ' . $this->primaryKey . ' = ' . (int) $id);
$data = $this->db->Fetch($query);
if (is_array($data)) {
$this->SetId($id);
$this->Set($data);
return true;
} else {
return false;
}
}
/**
* Load multiple instances of a child of iwp_engine in one query. This uses a simple clone() call in PHP so please refer to for notes about using this: http://php.net/clone
*
* Example:
* $events = iwp_module_calendar_event::getInstance()->LoadInstancesByField('content', 0);
* foreach ($events as $event) {
* // $event is an instance of iwp_module_calendar_event
* }
*
* @param string $fieldName
* @param string $value
* @param string|array $columns Optional. Can be used to limit the selected columns from the db. Default is * (to issue a SELECT *). This function can be provided with a delimited list of columns, or an array which will be implode()'d anyway.
* @param string $operator Optional. Can be used to specify an operator for WHERE SQL comparison. Default is =
* @return array
*/
public function LoadInstancesByField ($fieldName, $value, $columns = '*', $operator = '=') {
if (is_array($columns)) {
$columns = implode($columns, ', ');
}
return $this->LoadInstancesBySQL(sprintf("SELECT %s FROM %s WHERE `%s` %s '%s'", $columns, $this->GetTableName(), $fieldName, $operator, $this->db->Quote($value)));
}
/**
* Load all records (and columns) from the model's table as instances. Only intended for use in testing and development and should be replaced by a more specific select at some point.
*
* @return array
*/
public function LoadInstances () {
return $this->LoadInstancesBySQL(sprintf("SELECT * FROM %s", $this->GetTableName()));
}
/**
* See LoadInstancesByField. This does the same thing except by direct SQL query, useful if you want to do custom joins, etc.
*
* Used internally by LoadInstancesByField.
*
* @param string $sql
* @return array
*/
public function LoadInstancesBySQL ($sql) {
$query = $this->db->Query($sql);
return $this->LoadInstancesByQuery($query);
}
/**
* See LoadInstancesByFIeld. This does the same thing except by an already existing query result. Useful if the data has already been selected and you wish to build a list of instances based on that result.
*
* @param resource $query
* @return array
*/
public function LoadInstancesByQuery ($query) {
$results = array();
while ($row = $this->db->Fetch($query)) {
$clone = clone($this);
$clone->Set($row);
$clone->SetId($row[$clone->primaryKey]);
$results[] = $clone;
}
return $results;
}
/**
* LoadMulti
* This is used when the object need to hold multiple sets of data rows from the database. This might be the case
* when its used as a object variable in another class with a one to many relationship. In those circumstances it is
* recommended to override the Load() function in the subclass with this function. This assumes $data is an array of
* dataset arrays rather than a single dataset array.
*
* @param $fieldname string The name of the field to load the data by. In the case of the multiple datasets, this usually will not be the primary key of the table, but rather a foreign key.
* @param $value string The value of the field that is used to load the data.
*
* @return void
**/
public function LoadMulti($fieldname, $value, $skipReset=false){
if($skipReset === false){
$this->ResetColumnsMulti();
}
$query = $this->db->Query('select * from ' . $this->GetTableName() . ' where `'.$fieldname.'`="'.$this->db->Quote($value).'"');
while(($row = $this->db->Fetch($query))) {
foreach($row as $field=>$value){
if($this->ValidColumn($field)){
if($skipReset === false || !isset($this->data[$row[$this->primaryKey]][$field])){
$this->data[$row[$this->primaryKey]][$field] = $value;
}else{
$this->data[$row[$this->primaryKey]][$field] = ($value || $this->data[$row[$this->primaryKey]][$field]);
}
}
}
}
}
/**
* This function deletes an item from the database based on an ID number passed in
*
* @param integer $id The ID number to use to delete an item in the database. Uses the primaryKey to delete.
*
* @return boolean True if the item was deleted, false otherwise.
*
* @see $primaryKey
* @see $TableName
* @see ValidId()
* @see SetId()
* @see GetId()
*/
public function Delete($id=null){
if($id === null){
if($this->ValidId()){
$id = $this->GetId();
}else{
return false;
}
}
$result = $this->db->Query('delete from `'.$this->TableName.'` where '.$this->primaryKey.'='.(int)$id);
if($result == true){
$this->SetId(0);
return true;
} else {
return false;
}
}
public function AddTemporaryColumn($colName, $default=''){
$this->_columns[$colName] = $default;
}
public function RemoveTemporaryColumn($colName){
unset($this->_columns[$colName]);
}
/**
* Save
* This is the generic save function that can be used for most standard sub classes. It takes all of $data and
* saves it to the database using the primary key to update, or inserting a new row if the primary key is
* currently blank.
*
* @return boolean True if the data was saved, false if it wasn't and there was an error
**/
public function Save(){
/*$cleanInsert = array();
foreach($this->data as $key=>$value){
if(isset($this->validation[$key]) && $this->validation[$key] !== null){
// this column requires validation before input!
$validList = $this->validation[$key];
if(!is_array($validList)){
$validList = (array)$validList;
}
foreach($validList as $key2=>$value2){
$result = call_user_func(array(&$this->valid, $value2), $this->data[$key]);
if($result === false){
$this->SetError('The column "'.$key.'" did not pass through the "'.$value2.'" function successfully.');
return false;
}else{
$cleanInsert[$key] = $result;
}
}
}else{
$cleanInsert[$key] = $value;
}
}*/
if($this->ValidId() && $this->GetId() > 0){
// already exists, so update!
$result = $this->db->UpdateQuery($this->TableName, $this->data, '`'.$this->primaryKey.'`=' . $this->GetId());
if($result !== false){
return $this->GetId();
}else{
$this->SetError('A problem occurred trying to update this entry. MySQL Said: ' . $this->db->GetErrorMsg());
return false;
}
}else{
// since it isn't a valid id, strip it from the list of columns to save
if (isset($this->data[$this->primaryKey]) && !is_numeric($this->data[$this->primaryKey])) {
unset($this->data[$this->primaryKey]);
}
$this->SetTableName();
$result = $this->db->InsertQuery($this->TableName, $this->data);
if($result !== false){
$this->SetId($this->db->LastId());
return $this->GetId();
}else{
$this->SetError('A problem occurred trying to insert this entry. MySQL Said: ' . $this->db->GetErrorMsg() . ' Query was: '.htmlspecialchars($this->db->LastQuery));
return false;
}
}
}
public function GetData(){
return $this->data;
}
public function GetDataById($id){
if(!iwp_IsId($id)){
return array();
}
$self = new self();
$self->Load($id);
return $self->GetData();
}
/**
* Removes all rows that have a primary key in the passed primary key(s).
*
* @return Boolean
* @param Mixed $primaryKeys A primary key or array of primary keys
*/
public function deleteIn($primaryKeys)
{
if (!$primaryKeys || !count($primaryKeys)) {
return false;
}
if (!is_array($primaryKeys)) {
$primaryKeys = array($primaryKeys);
}
return $this->db->Query('
DELETE FROM ' . $this->TableName . '
WHERE `' . $this->primaryKey . '`
IN (' . implode(', ', $primaryKeys) . ')
');
}
/**
* Removes all rows that DO NOT have a primary key in the passed primary key(s).
*
* @return Boolean
* @param Mixed $primaryKeys A primary key or array of primary keys
*/
public function deleteNotIn($primaryKeys)
{
if (!$primaryKeys || !count($primaryKeys)) {
return false;
}
if (!is_array($primaryKeys)) {
$primaryKeys = array($primaryKeys);
}
return $this->db->Query('
DELETE FROM ' . $this->TableName . '
WHERE `' . $this->primaryKey . '`
NOT IN (' . implode(', ', $primaryKeys) . ')
');
}
/**
* Provides a single method to normalize request parameters. $_GET overrides $_POST. This
* also allows us to wrap any calls to $_GET and $_POST and fascilitates a way to add
* request paramter filtering in the future.
*
* @return String|Array Request parameters are either strings or arrays.
* @param String $paramName The parameter you want to get.
*/
static public function getParam($paramName)
{
if (isset($_GET[$paramName])) {
return $_GET[$paramName];
}
if (isset($_POST[$paramName])) {
return $_POST[$paramName];
}
return null;
}
}