b2evolution

Multilingual multiuser multiblog engine

b2evolution Technical Documentation (CVS HEAD) [ class tree: evocore ] [ index: evocore ] [ all elements ]

Source for file _dataobject.class.php

Documentation is available at _dataobject.class.php

  1. <?php
  2. /**
  3.  * This file implements the abstract DataObject base class.
  4.  *
  5.  * This file is part of the evoCore framework - {@link http://evocore.net/}
  6.  * See also {@link http://sourceforge.net/projects/evocms/}.
  7.  *
  8.  * @copyright (c)2003-2010 by Francois PLANQUE - {@link http://fplanque.net/}
  9.  *  Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10.  *  Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
  11.  *
  12.  *  {@internal License choice
  13.  *  - If you have received this file as part of a package, please find the license.txt file in
  14.  *    the same folder or the closest folder above for complete license terms.
  15.  *  - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  16.  *    then you must choose one of the following licenses before using the file:
  17.  *    - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  18.  *    - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  19.  *  }}}
  20.  *
  21.  *  {@internal Open Source relicensing agreement:
  22.  *  Daniel HAHLER grants Francois PLANQUE the right to license
  23.  *  Daniel HAHLER's contributions to this file and the b2evolution project
  24.  *  under any OSI approved OSS license (http://www.opensource.org/licenses/).
  25.  *
  26.  *  PROGIDISTRI S.A.S. grants Francois PLANQUE the right to license
  27.  *  PROGIDISTRI S.A.S.'s contributions to this file and the b2evolution project
  28.  *  under any OSI approved OSS license (http://www.opensource.org/licenses/).
  29.  *  }}}
  30.  *
  31.  * @package evocore
  32.  *
  33.  *  {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  34.  * @author fplanque: Francois PLANQUE
  35.  * @author blueyed: Daniel HAHLER
  36.  * @author mbruneau: Marc BRUNEAU / PROGIDISTRI
  37.  *
  38.  * @version $Id: _dataobject.class.php,v 1.35 2010/02/08 17:51:50 efy-yury Exp $
  39.  */
  40. if!defined('EVO_MAIN_INIT') ) die'Please, do not access this page directly.' );
  41.  
  42. /**
  43.  * Data Object Base Class
  44.  *
  45.  * This is typically an abstract class, useful only when derived.
  46.  *
  47.  * @package evocore
  48.  * @version beta
  49.  * @abstract
  50.  */
  51. class DataObject
  52. {
  53.     /**
  54.      * Unique ID of object in database
  55.      *
  56.      * Please use get/set functions to read or write this param
  57.      *
  58.      * @var int 
  59.      * @access protected
  60.      */
  61.     var $ID = 0;  // This will be the ID in the DB
  62.  
  63.     var $allow_ID_insert = false;
  64.  
  65.     /**#@+
  66.      * @access private
  67.      */
  68.     var $dbtablename;
  69.     var $dbprefix;
  70.     var $dbIDname;
  71.     var $datecreated_field;
  72.     var $datemodified_field;
  73.     var $creator_field;
  74.     var $lasteditor_field;
  75.     var $dbchanges array();
  76.     /**#@-*/
  77.  
  78.     /**
  79.      * Relations that may restrict deletion.
  80.      */
  81.     var $delete_restrictions = array();
  82.  
  83.     /**
  84.      * Relations that will cascade deletion.
  85.      */
  86.     var $delete_cascades = array();
  87.  
  88.  
  89.     /**
  90.      * Constructor
  91.      *
  92.      * @param string Name of table in database
  93.      * @param string Prefix of fields in the table
  94.      * @param string Name of the ID field (including prefix)
  95.      * @param string datetime field name
  96.      * @param string datetime field name
  97.      * @param string User ID field name
  98.      * @param string User ID field name
  99.      */
  100.     function DataObject$tablename$prefix ''$dbIDname 'ID'$datecreated_field ''$datemodified_field ''$creator_field ''$lasteditor_field '' )
  101.     {
  102.         $this->dbtablename        $tablename;
  103.         $this->dbprefix           $prefix;
  104.         $this->dbIDname           $dbIDname;
  105.         $this->datecreated_field  $datecreated_field;
  106.         $this->datemodified_field $datemodified_field;
  107.         $this->creator_field      $creator_field;
  108.         $this->lasteditor_field   $lasteditor_field;
  109.     }
  110.  
  111.  
  112.     /**
  113.      * Records a change that will need to be updated in the db
  114.      *
  115.      * @access protected
  116.      * @param string Name of parameter
  117.      * @param string DB field type ('string', 'number', 'date', 'dbfield' )
  118.      * @param mixed Pointer to value of parameter - dh> pointer? So it should be a reference? Would make sense IMHO anyway.. fp> I just wonder why it's not already a reference... :@
  119.      */
  120.     function dbchange$dbfieldname$dbfieldtype$valuepointer // TODO: dh> value by reference? see above..
  121.     {
  122.         // echo '<br />DB change on :'.$dbfieldname;
  123.         $this->dbchanges[$dbfieldname]['type'$dbfieldtype;
  124.         $this->dbchanges[$dbfieldname]['value'$valuepointer ;
  125.     }
  126.  
  127.  
  128.     /**
  129.      * Update the DB based on previously recorded changes
  130.      *
  131.      * @param boolean do we want to auto track the mod date?
  132.      * @return boolean true on success, false on failure to update, NULL if no update necessary
  133.      */
  134.     function dbupdate$auto_track_modification true )
  135.     {
  136.         global $DB$localtimenow$current_User;
  137.  
  138.         if$this->ID == debug_die'New object cannot be updated!' )}
  139.  
  140.         ifcount$this->dbchanges == )
  141.         {
  142.             return NULL;    // No changes!
  143.         }
  144.  
  145.         if$auto_track_modification )
  146.         // We wnat to track modification date and author automatically:
  147.             if!empty($this->datemodified_field) )
  148.             {    // We want to track modification date:
  149.                 $this->set_param$this->datemodified_field'date'date('Y-m-d H:i:s',$localtimenow) );
  150.             }
  151.             if!empty($this->lasteditor_field&& is_object($current_User) )
  152.             {    // We want to track last editor:
  153.                 // TODO: the current_User is not necessarily the last editor. Item::dbupdate() gets called after incrementing the view for example!
  154.                 // fplanque: this should be handled by set() deciding wether the setting changes the last editor or not
  155.                 $this->set_param$this->lasteditor_field'number'$current_User->ID );
  156.             }
  157.         }
  158.  
  159.         $sql_changes array();
  160.         foreach$this->dbchanges as $loop_dbfieldname => $loop_dbchange )
  161.         {
  162.             if$loop_dbchange['type'== 'dbfield' )
  163.             {    // Set to dbfield only:
  164.                 $sql_changes["`$loop_dbfieldname` = `".$loop_dbchange['value'].'` ';
  165.                 continue;
  166.             }
  167.  
  168.             // Get changed value (we use eval() to allow constructs like $loop_dbchange['value'] = 'Group->get(\'ID\')'):
  169.             eval'$loop_value = $this->'.$loop_dbchange['value'].';' );
  170.             // Prepare matching statement:
  171.             ifis_null($loop_value) )
  172.             {
  173.                 $sql_changes[$loop_dbfieldname.' = NULL ';
  174.             }
  175.             else
  176.             {
  177.                 switch$loop_dbchange['type')
  178.                 {
  179.                     case 'date':
  180.                     case 'string':
  181.                         $sql_changes[$loop_dbfieldname." = '".$DB->escape$loop_value )."' ";
  182.                         break;
  183.  
  184.                     default:
  185.                         $sql_changes[$loop_dbfieldname." = ".$DB->null($loop_value).' ';
  186.                 }
  187.             }
  188.         }
  189.  
  190.         // Prepare full statement:
  191.         $sql "UPDATE $this->dbtablename SET "implode', '$sql_changes )"
  192.                          WHERE $this->dbIDname = $this->ID";
  193.         //echo $sql;
  194.  
  195.         if$DB->query$sql'DataObject::dbupdate()' ) )
  196.         {
  197.             return false;
  198.         }
  199.  
  200.         // Reset changes in object:
  201.         $this->dbchanges array();
  202.  
  203.         return true;
  204.     }
  205.  
  206.  
  207.     /**
  208.      * Insert object into DB based on previously recorded changes.
  209.      *
  210.      * Note: DataObject does not require a matching *Cache object.
  211.      * Therefore it will not try to update the Cache.
  212.      * If something like that was needed, sth like *Cache->add() should be called.
  213.      * ATTENTION: Any dbinsert should typically be followed by a 303 redirect. Updating the Cache before redirect is generally not needed.
  214.      *
  215.      * @return boolean true on success
  216.      */
  217.     function dbinsert()
  218.     {
  219.         global $DB$localtimenow$current_User;
  220.  
  221.         if$this->ID != && !$this->allow_ID_insert )
  222.         {
  223.             die'Existing object/object with an ID cannot be inserted!' );
  224.         }
  225.  
  226.         if!empty($this->datecreated_field) )
  227.         {    // We want to track creation date:
  228.             $this->set_param$this->datecreated_field'date'date('Y-m-d H:i:s',$localtimenow) );
  229.         }
  230.         if!empty($this->datemodified_field) )
  231.         {    // We want to track modification date:
  232.             $this->set_param$this->datemodified_field'date'date('Y-m-d H:i:s',$localtimenow) );
  233.         }
  234.         if!empty($this->creator_field) )
  235.         {    // We want to track creator:
  236.             ifempty($this->creator_user_ID) )
  237.             {    // No creator assigned yet, use current user:
  238.                 $this->set_param$this->creator_field'number'$current_User->ID );
  239.             }
  240.         }
  241.         if!empty($this->lasteditor_field) )
  242.         {    // We want to track last editor:
  243.             ifempty($this->lastedit_user_ID) )
  244.             {    // No editor assigned yet, use current user:
  245.                 $this->set_param$this->lasteditor_field'number'$current_User->ID );
  246.             }
  247.         }
  248.  
  249.         $sql_fields array();
  250.         $sql_values array();
  251.         foreach$this->dbchanges as $loop_dbfieldname => $loop_dbchange )
  252.         {
  253.             // Get changed value (we use eval() to allow constructs like $loop_dbchange['value'] = 'Group->get(\'ID\')'):
  254.             eval'$loop_value = $this->'$loop_dbchange['value'].';' );
  255.             // Prepare matching statement:
  256.             $sql_fields[$loop_dbfieldname;
  257.             ifis_null($loop_value) )
  258.             {
  259.                 $sql_values['NULL';
  260.             }
  261.             else
  262.             {
  263.                 switch$loop_dbchange['type')
  264.                 {
  265.                     case 'date':
  266.                     case 'string':
  267.                         $sql_values[$DB->quote$loop_value );
  268.                         break;
  269.  
  270.                     default:
  271.                         $sql_values[$DB->null$loop_value );
  272.                 }
  273.             }
  274.         }
  275.  
  276.         // Prepare full statement:
  277.         $sql "INSERT INTO {$this->dbtablename} ("implode( ', ', $sql_fields )") VALUES ("implode( ', ', $sql_values )")";
  278.         // echo $sql;
  279.         if( ! $DB->query$sql'DataObject::dbinsert()' ) )
  280.         {
  281.             return false;
  282.         }
  283.  
  284.  
  285.         if( !( $this->allow_ID_insert && $this->ID ) )
  286.         {// store ID for newly created db record. Do not if allow_ID_insert is true and $this->ID is not 0
  287.             $this->ID = $DB->insert_id;
  288.         }
  289.         // Reset changes in object:
  290.         $this->dbchanges array();
  291.  
  292.         return true;
  293.     }
  294.  
  295.  
  296.     /**
  297.      * Inserts or Updates depending on object state.
  298.      *
  299.      * @uses dbinsert()
  300.      * @uses dbupdate()
  301.      * @return boolean true on success, false on failure
  302.      */
  303.     function dbsave()
  304.     {
  305.         if( $this->ID == )
  306.         {    // Object not serialized yet, let's insert!
  307.             // echo 'INSERT';
  308.             return $this->dbinsert();
  309.         }
  310.         else
  311.         {    // Object already serialized, let's update!
  312.             // echo 'UPDATE';
  313.             return $this->dbupdate();
  314.         }
  315.     }
  316.  
  317.  
  318.     /**
  319.      * Delete object from DB.
  320.      *
  321.      * @return boolean true on success
  322.      */
  323.     function dbdelete()
  324.     {
  325.         global $DB, $Messages, $db_config;
  326.  
  327.         if( $this->ID == { debug_die( 'Non persistant object cannot be deleted!' ); }
  328.  
  329.         if( count($this->delete_cascades) )
  330.         {    // The are cascading deletes to be performed
  331.             // Start transaction:
  332.             $DB->begin();
  333.  
  334.             foreach$this->delete_cascades as $restriction )
  335.             {
  336.                 if( !isset( $db_config['aliases'][$restriction['table']] ) )
  337.                 {    // We have no declaration for this table, we consider we don't deal with this table in this app:
  338.                     continue;
  339.                 }
  340.  
  341.                 $DB->query'
  342.                     DELETE FROM '.$restriction['table'].'
  343.                     WHERE '.$restriction['fk'].' = '.$this->ID,
  344.                     'Cascaded delete' );
  345.             }
  346.         }
  347.  
  348.         // Delete this (main/parent) object:
  349.         $DB->query"
  350.             DELETE FROM $this->dbtablename
  351.             WHERE $this->dbIDname = $this->ID",
  352.             'Main delete' );
  353.  
  354.         ifcount($this->delete_cascades) )
  355.         {    // There were cascading deletes
  356.             // End transaction:
  357.             $DB->commit();
  358.         }
  359.  
  360.         // Just in case... remember this object has been deleted from DB!
  361.         $this->ID = 0;
  362.  
  363.         return true;
  364.     }
  365.  
  366.  
  367.     /**
  368.      * Check existence of specified value in unique field.
  369.      *
  370.      * @param string Name of unique field
  371.      * @param mixed specified value
  372.      * @return int ID if value exists otherwise NULL/false
  373.      */
  374.     function dbexists($unique_field, $value)
  375.     {
  376.         global $DB;
  377.  
  378.         $sql = "SELECT $this->dbIDname
  379.                           FROM $this->dbtablename
  380.                        WHERE $unique_field = ".$DB->quote($value)."
  381.                            AND $this->dbIDname != $this->ID";
  382.  
  383.         return $DB->get_var$sql );
  384.     }
  385.  
  386.  
  387.     /**
  388.      * Check relations for restrictions or cascades.
  389.      * @todo dh> Add link to affected items, e.g. items when trying to delete an attachment, where it gets used.
  390.      */
  391.     function check_relations( $what, $ignore = array() )
  392.     {
  393.         global $DB, $Messages;
  394.  
  395.         foreach( $this->$what as $restriction )
  396.         {
  397.             if( !in_array( $restriction['fk'], $ignore ) )
  398.             {
  399.                 $count = $DB->get_var(
  400.                     'SELECT COUNT(*)
  401.                        FROM '.$restriction['table'].'
  402.                       WHERE '.$restriction['fk'].' = '.$this->ID,
  403.                     00'restriction/cascade check' );
  404.                 if$count )
  405.                 {
  406.                     $Messages->addsprintf$restriction['msg']$count )'restrict' );
  407.                 }
  408.             }
  409.         }
  410.     }
  411.  
  412.  
  413.     /**
  414.      * Check relations for restrictions before deleting
  415.      *
  416.      * @param string
  417.      * @param array list of foreign keys to ignore
  418.      * @return boolean true if no restriction prevents deletion
  419.      */
  420.     function check_delete( $restrict_title, $ignore = array() )
  421.     {
  422.         global $Messages;
  423.  
  424.         // Check restrictions:
  425.         $this->check_relations'delete_restrictions'$ignore );
  426.  
  427.         if$Messages->count('restrict') )
  428.         {    // There are restrictions:
  429.             $Messages->head array(
  430.                     'container' => $restrict_title,
  431.                     'restrict' => T_('The following relations prevent deletion:')
  432.                 );
  433.             $Messages->foot =    T_('Please delete related objects before you proceed.');
  434.             return false;    // Can't delete
  435.         }
  436.  
  437.         return true;    // can delete
  438.     }
  439.  
  440.  
  441.     /**
  442.      * Displays form to confirm deletion of this object
  443.      *
  444.      * @param string Title for confirmation
  445.      * @param string crumb name
  446.      * @param string "action" param value to use (hidden field)
  447.      * @param array Hidden keys (apart from "action")
  448.      */
  449.     function confirm_delete( $confirm_title, $crumb_name, $delete_action, $hiddens )
  450.     {
  451.         global $Messages;
  452.  
  453.         $block_item_Widget = new Widget( 'block_item' );
  454.  
  455.         $block_item_Widget->title $confirm_title;
  456.         $block_item_Widget->disp_template_replaced'block_start' );
  457.  
  458.         $this->check_relations'delete_cascades' );
  459.  
  460.         if$Messages->count('restrict') )
  461.         {    // The will be cascading deletes, issue WARNING:
  462.             echo '<h3>'.T_('WARNING: Deleting this object will also delete:').'</h3>';
  463.             $Messages->display''''true'restrict'NULLNULLNULL );
  464.         }
  465.  
  466.         echo '<p class="warning">'.$confirm_title.'</p>';
  467.         echo '<p class="warning">'.T_('THIS CANNOT BE UNDONE!').'</p>';
  468.  
  469.         $Form = new Form( '', 'form_confirm', 'get', '' );
  470.  
  471.         $Form->begin_form'inline' );
  472.             $Form->add_crumb$crumb_name );
  473.             $Form->hiddens_by_key$hiddens );
  474.             $Form->hidden'action'$delete_action );
  475.             $Form->hidden'confirm');
  476.             $Form->buttonarray'submit'''T_('I am sure!')'DeleteButton' ) );
  477.         $Form->end_form();
  478.  
  479.         $Form new Form'''form_cancel''get''' );
  480.  
  481.         $Form->begin_form'inline' );
  482.             $Form->hiddens_by_key$hiddens );
  483.             $Form->buttonarray'submit'''T_('CANCEL')'CancelButton' ) );
  484.         $Form->end_form();
  485.  
  486.         $block_item_Widget->disp_template_replaced'block_end' );
  487.         return true;
  488.     }
  489.  
  490.  
  491.     /**
  492.      * Get a member param by its name
  493.      *
  494.      * @param mixed Name of parameter
  495.      * @return mixed Value of parameter
  496.      */
  497.     function get( $parname )
  498.     {
  499.         return $this->$parname;
  500.     }
  501.  
  502.  
  503.     /**
  504.      * Get a ready-to-display member param by its name
  505.      *
  506.      * Same as disp but don't echo
  507.      *
  508.      * @param string Name of parameter
  509.      * @param string Output format, see {@link format_to_output()}
  510.      */
  511.     function dget( $parname, $format = 'htmlbody' )
  512.     {
  513.         // Note: we call get again because of derived objects specific handlers !
  514.         return format_to_output( $this->get($parname)$format );
  515.     }
  516.  
  517.  
  518.     /**
  519.      * Display a member param by its name
  520.      *
  521.      * @param string Name of parameter
  522.      * @param string Output format, see {@link format_to_output()}
  523.      */
  524.     function disp( $parname, $format = 'htmlbody' )
  525.     {
  526.         // Note: we call get again because of derived objects specific handlers !
  527.         echo format_to_output( $this->get($parname)$format );
  528.     }
  529.  
  530.  
  531.     /**
  532.      * Set param value
  533.      *
  534.      * By default, all values will be considered strings
  535.      *
  536.      * @param string parameter name
  537.      * @param mixed parameter value
  538.      * @param boolean true to set to NULL if empty value
  539.      * @return boolean true, if a value has been set; false if it has not changed
  540.      */
  541.     function set( $parname, $parvalue, $make_null = false )
  542.     {
  543.         return $this->set_param$parname'string'$parvalue$make_null );
  544.     }
  545.  
  546.  
  547.     /**
  548.      * Set param value.
  549.      *
  550.      * @param string Name of parameter
  551.      * @param string DB field type ('string', 'number', 'date' )
  552.      * @param mixed Value of parameter
  553.      * @param boolean true to set to NULL if empty string value
  554.      * @return boolean true, if value has been set/changed, false if not.
  555.      */
  556.     function set_param( $parname, $fieldtype, $parvalue, $make_null = false )
  557.     {
  558.         global $Debuglog;
  559.  
  560.         $dbfield = $this->dbprefix.$parname;
  561.  
  562.         // Set value:
  563.         // fplanque: Note: I am changing the "make NULL" test to differentiate between 0 and NULL .
  564.         // There might be side effects. In this case it would be better to fix them before coming here.
  565.         // i-e: transform 0 to ''
  566.         $new_value ($make_null && ($parvalue === '')) NULL $parvalue;
  567.  
  568.         /* Tblue> Problem: All class member variables originating from the
  569.          *                 DB are strings (unless they were NULL in the DB,
  570.          *                 then they are set to NULL by the PHP MySQL
  571.          *                 extension).
  572.          *                 If we pass an integer or a double to this function,
  573.          *                 the corresponding member variable gets changed
  574.          *                 on every call, because its type is 'string' and
  575.          *                 we compare using the === operator. Using the
  576.          *                 == operator would be a bad idea, though, because
  577.          *                 somebody could pass a NULL value to this function.
  578.          *                 If the member variable then is set to 0, then
  579.          *                 0 equals NULL and the member variable does not
  580.          *                 get updated at all!
  581.          *                 Thus, using the === operator is correct.
  582.          *       Solution: If $fieldtype is 'number' and the type of the
  583.          *                 passed value is either integer or double, we
  584.          *                 convert it to a string (no data loss). The
  585.          *                 member variable and the passed value can then
  586.          *                 be correctly compared using the === operator.
  587.          *  fp> It would be nicer to convert numeric values to ints & floats at load time in class constructor  x=(int)$y->value  or sth.
  588.          * THIS IS EXPERIMENTAL! Feel free to revert if something does not
  589.          * work as expected.
  590.          */
  591.         if$fieldtype == 'number' && is_int$new_value || is_float$new_value ) ) )
  592.         {
  593.             settype( $new_value, 'string' );
  594.         }
  595.  
  596.         //$Debuglog->add( $this->dbtablename.' object; $fieldtype = '.$fieldtype.'; type of $this->'.$parname.' = '.gettype( @$this->$parname ).'; type of $new_value = '.gettype( $new_value ), 'dataobjects' );
  597. /* >old
  598.         if( !isset($this->$parname) )
  599.         {    // This property has never been set before, set it to NULL now in order for tests to work:
  600.             $this->$parname = NULL;
  601.         }
  602.         /* blueyed>
  603.         TODO: there's a bug here: you cannot use set_param('foo', 'number', 0), if the $parname member
  604.               has not been set before or is null!!
  605.               What about just:
  606.               ( isset($this->$parname) && $this->$parname === $new_value )
  607.               This would also eliminate the isset() check from above.
  608.               IIRC you've once said here that '===' would be too expensive and I would misuse the DataObjects,
  609.               but IMHO what we have now is not much faster and buggy anyway..
  610.             fp> okay let's give it a try...
  611.         if( (!is_null($new_value) && $this->$parname == $new_value)
  612.             || (is_null($this->$parname) && is_null($new_value)) )
  613. <old */
  614.         if( (isset($this->$parname&& $this->$parname === $new_value)
  615.             || isset($this->$parname&& isset($new_value) ) )
  616.         {    // Value has not changed (we need 2 tests, for NULL and for NOT NULL value pairs)
  617.             $Debuglog->add$this->dbtablename.' object, already set to same value: '.$parname.'/'.$dbfield.' = '.var_export@$this->$parnametrue )'dataobjects' );
  618.             // echo '<br />'.$this->dbtablename.' object, already set to same value: '.$parname.'/'.$dbfield.' = '.$this->$parname;
  619.  
  620.             return false;
  621.         }
  622.         else
  623.         {
  624.             // Set the value in the object:
  625.             // echo '<br/>'.$this->dbtablename.' object, setting param '.$parname.'/'.$dbfield.' to '.$new_value.(is_null($new_value)?' NULL':'').' (was:'.$this->$parname.(is_null($this->$parname)?' NULL':'').')';
  626.             $this->$parname $new_value;
  627.             $Debuglog->add$this->dbtablename.' object, setting param '.$parname.'/'.$dbfield.' to '.$this->$parname'dataobjects' );
  628.  
  629.             // Remember change for later db update:
  630.             $this->dbchange$dbfield$fieldtype$parname );
  631.  
  632.             return true;
  633.         }
  634.     }
  635.  
  636.  
  637.     /**
  638.      * Set a parameter from a Request form value.
  639.      *
  640.      * @param string Dataobject parameter name
  641.      * @param string Request parameter name (NULL means to use Dataobject param name with its prefix)
  642.      * @param boolean true to set to NULL if empty string value
  643.      * @return boolean true, if value has been set/changed, false if not.
  644.      */
  645.     function set_from_Request( $parname, $var = NULL, $make_null = false, $cleanup_function = NULL )
  646.     {
  647.         if( empty($var) )
  648.         {
  649.             $var = $this->dbprefix.$parname;
  650.         }
  651.  
  652.         $value = get_param($var);
  653.  
  654.         if( !empty($cleanup_function) )
  655.         {    //We want to apply a cleanup function
  656.             $value = $cleanup_function($value);
  657.             set_param($var, $value);
  658.         }
  659.  
  660.         return $this->set$parname$value$make_null );
  661.     }
  662.  
  663.  
  664.     /**
  665.      * Set a string parameter from a Request form value.
  666.      *
  667.      * @param string Dataobject parameter name
  668.      * @param boolean true to set to NULL if empty string value
  669.      * @param string name of function used to clean up input
  670.      * @param string name of fucntion used to validate input (TODO)
  671.      * @return boolean true, if value is required
  672.      */
  673.     function set_string_from_param( $parname, $required = false, $cleanup_function = NULL, $validation_function = NULL, $error_message = NULL )
  674.     {
  675.         $var = $this->dbprefix.$parname;
  676.  
  677.         $value param$var'string' );
  678.  
  679.         if!empty($cleanup_function) )
  680.         {    // We want to apply a cleanup function:
  681.             $GLOBALS[$var] = $value = $cleanup_function( $value );
  682.         }
  683.  
  684.         if( $required )
  685.         {
  686.             param_check_not_empty( $var );
  687.         }
  688.  
  689.         if( $validation_function != NULL )
  690.         {
  691.             param_validate( $var, $validation_function, $required, $error_message );
  692.         }
  693.  
  694.         return $this->set$parname$value$required );
  695.     }
  696.  
  697.  
  698.     /**
  699.      * Template function: Displays object ID.
  700.      */
  701.     function ID()
  702.     {
  703.         echo $this->ID;
  704.     }
  705.  
  706.  
  707.     /**
  708.      * Generate help title text for action
  709.      *
  710.      * @param string action code: edit, delete, etc.
  711.      * @return string translated help string
  712.      */
  713.     function get_action_title( $action )
  714.     {
  715.         switch( $action )
  716.         {
  717.             case 'edit'return T_('Edit this object...');
  718.             case 'copy'return T_('Duplicate this object...');
  719.             case 'delete'return T_('Delete this object!');
  720.             default:
  721.                 return '';
  722.         }
  723.     }
  724.  
  725.  
  726.     /**
  727.      * Generate requested action icon depending on perm
  728.      */
  729.     function action_icon( $action, $help_texts = array() )
  730.     {
  731.         if( ! $this->check_perm($actionfalse) )
  732.         {    // permission denied:
  733.             return '';
  734.         }
  735.  
  736.         return action_icon( $this->get_action_title($action)$action,
  737.                                   regenerate_url'action'$this->dbIDname.'='.$this->ID.'&amp;action='.$action
  738.                                                                   .'&amp;'.url_crumb(strtolower(get_class($this))) ) );
  739.     }
  740.  
  741.  
  742.     /**
  743.      * Generate requested action link depending on perm
  744.      */
  745.     function action_link( $action, $link_text, $help_texts = array() )
  746.     {
  747.         if( ! $this->check_perm($actionfalse) )
  748.         {    // permission denied:
  749.             return '';
  750.         }
  751.  
  752.         return '<a href="'.regenerate_url( 'action', $this->dbIDname.'='.$this->ID.'&amp;action='.$action )
  753.                         .'" title="'.$this->get_action_title($action).'">'.$link_text.'</a>';
  754.     }
  755.  
  756.  
  757.     /**
  758.      * Create icon with dataobject history
  759.      */
  760.     function history_info_icon()
  761.     {
  762.         $history = array();
  763.  
  764.         $UserCache = & get_UserCache();
  765.  
  766.         // HANDLE CREATOR STUFF
  767.         if( !empty($this->creator_field&& !empty($this->{$this->creator_field}) )
  768.         {    // We have a creator:
  769.             $creator_User = & $UserCache->get_by_ID$this->{$this->creator_field);
  770.  
  771.             if!empty($this->datecreated_field&& !empty($this->{$this->datecreated_field}) )
  772.             {    // We also have a create date:
  773.                 $history[0] = sprintf( T_('Created on %s by %s'), mysql2localedate( $this->{$this->datecreated_field),
  774.                     $creator_User->dget('preferredname') );
  775.             }
  776.             else
  777.             {    // We only have a cretaor:
  778.                 $history[0] = sprintf( T_('Created by %s'), $creator_User->dget('preferredname') );
  779.             }
  780.         }
  781.         elseif( !empty($this->datecreated_field&& !empty($this->{$this->datecreated_field}) )
  782.         {    // We only have a create date:
  783.             $history[0] = sprintf( T_('Created on %s'), mysql2localedate( $this->{$this->datecreated_field) );
  784.         }
  785.  
  786.         // HANDLE LAST UPDATE STUFF
  787.         if( !empty($this->lasteditor_field&& !empty($this->{$this->lasteditor_field}) )
  788.         {    // We have a creator:
  789.             $creator_User = & $UserCache->get_by_ID$this->{$this->lasteditor_field);
  790.  
  791.             if!empty($this->datemodified_field&& !empty($this->{$this->datemodified_field}) )
  792.             {    // We also have a create date:
  793.                 $history[1] = sprintf( T_('Last mod on %s by %s'), mysql2localedate( $this->{$this->datemodified_field),
  794.                     $creator_User->dget('preferredname') );
  795.             }
  796.             else
  797.             {    // We only have a cretaor:
  798.                 $history[1] = sprintf( T_('Last mod by %s'), $creator_User->dget('preferredname') );
  799.             }
  800.         }
  801.         elseif( !empty($this->datemodified_field&& !empty($this->{$this->datemodified_field}) )
  802.         {    // We only have a create date:
  803.             $history[1] = sprintf( T_('Last mod on %s'), mysql2localedate( $this->{$this->datemodified_field) );
  804.         }
  805.  
  806.         return get_icon( 'history', $what = 'imgtag', array( 'title'=>implode( ' - ', $history ) ), true );
  807.     }
  808. }
  809.  
  810.  
  811.  
  812. /*
  813.  * $Log: _dataobject.class.php,v $
  814.  * Revision 1.35  2010/02/08 17:51:50  efy-yury
  815.  * copyright 2009 -> 2010
  816.  *
  817.  * Revision 1.34  2010/01/10 23:24:07  fplanque
  818.  * crumbs...
  819.  *
  820.  * Revision 1.33  2010/01/03 12:03:17  fplanque
  821.  * More crumbs...
  822.  *
  823.  * Revision 1.32  2009/12/01 02:04:45  fplanque
  824.  * minor
  825.  *
  826.  * Revision 1.31  2009/11/30 22:57:27  blueyed
  827.  * Add 'dbfield' dbchange type. This allows setting something to a db field. E.g. 'lastupdate=lastupdate'.
  828.  *
  829.  * Revision 1.30  2009/10/12 23:52:46  blueyed
  830.  * todo
  831.  *
  832.  * Revision 1.29  2009/10/04 23:06:30  fplanque
  833.  * doc
  834.  *
  835.  * Revision 1.28  2009/10/04 12:23:40  efy-maxim
  836.  * validate has been renamed to param_validate function
  837.  *
  838.  * Revision 1.27  2009/09/30 15:15:59  efy-maxim
  839.  * NULL check for validation function
  840.  *
  841.  * Revision 1.26  2009/09/29 21:07:24  blueyed
  842.  * todo/question
  843.  *
  844.  * Revision 1.25  2009/09/26 12:00:42  tblue246
  845.  * Minor/coding style
  846.  *
  847.  * Revision 1.24  2009/09/25 07:32:52  efy-cantor
  848.  * replace get_cache to get_*cache
  849.  *
  850.  * Revision 1.23  2009/09/24 19:48:30  efy-maxim
  851.  * validators
  852.  *
  853.  * Revision 1.22  2009/09/24 09:36:04  efy-maxim
  854.  * validation_function
  855.  *
  856.  * Revision 1.21  2009/09/23 02:46:40  fplanque
  857.  * doc
  858.  *
  859.  * Revision 1.20  2009/09/22 07:07:24  efy-bogdan
  860.  * user.ctrl.php cleanup
  861.  *
  862.  * Revision 1.19  2009/09/20 20:07:18  blueyed
  863.  *  - DataObject::dbexists quotes always
  864.  *  - phpdoc fixes
  865.  *  - style fixes
  866.  *
  867.  * Revision 1.18  2009/09/20 18:09:41  tblue246
  868.  * revert
  869.  *
  870.  * Revision 1.16  2009/09/20 12:17:15  efy-sergey
  871.  * fixed wrong ID asigning for tables without auto_increment fields
  872.  *
  873.  * Revision 1.15  2009/09/19 20:49:51  fplanque
  874.  * Cleaner way of implementing permissions.
  875.  *
  876.  * Revision 1.14  2009/09/11 18:34:05  fplanque
  877.  * userfields editing module.
  878.  * needs further cleanup but I think it works.
  879.  *
  880.  * Revision 1.13  2009/09/02 23:29:34  fplanque
  881.  * doc
  882.  *
  883.  * Revision 1.12  2009/09/02 22:50:48  efy-maxim
  884.  * Clean error message for currency/goal already exists
  885.  *
  886.  * Revision 1.11  2009/09/02 17:47:23  fplanque
  887.  * doc/minor
  888.  *
  889.  * Revision 1.10  2009/08/30 02:37:14  fplanque
  890.  * support for simple form processing
  891.  *
  892.  * Revision 1.9  2009/07/19 22:14:22  fplanque
  893.  * Clean resolution of the excerpt mod date bullcrap.
  894.  * It took 4 lines of code...
  895.  *
  896.  * Revision 1.8  2009/07/18 16:30:14  tblue246
  897.  * Better solution for preventing an update of the datemodified field when the excerpt gets autogenerated.
  898.  *
  899.  * Revision 1.7  2009/07/18 11:09:26  tblue246
  900.  * Use is_int() and is_float() instead of gettype() -- better performance.
  901.  *
  902.  * Revision 1.6  2009/07/17 23:11:11  tblue246
  903.  * - DataObject::set_param(): Correctly decide whether to update values with $fieldtype == 'number' (see code for detailed explanation).
  904.  * - Item class: Doc about updating excerpt without updating the datemodified field.
  905.  * - ItemLight class: Add missing member variable.
  906.  *
  907.  * Revision 1.5  2009/07/17 17:50:10  tblue246
  908.  * Item class: Prevent update of datemodified field if only the post excerpt gets updated.
  909.  *
  910.  * Revision 1.4  2009/03/08 23:57:40  fplanque
  911.  * 2009
  912.  *
  913.  * Revision 1.3  2008/04/17 11:53:17  fplanque
  914.  * Goal editing
  915.  *
  916.  * Revision 1.2  2008/01/21 09:35:24  fplanque
  917.  * (c) 2008
  918.  *
  919.  * Revision 1.1  2007/06/25 10:58:56  fplanque
  920.  * MODULES (refactored MVC)
  921.  *
  922.  * Revision 1.26  2007/05/14 02:43:04  fplanque
  923.  * Started renaming tables. There probably won't be a better time than 2.0.
  924.  *
  925.  * Revision 1.25  2007/05/13 22:02:07  fplanque
  926.  * removed bloated $object_def
  927.  *
  928.  * Revision 1.24  2007/04/26 00:11:09  fplanque
  929.  * (c) 2007
  930.  *
  931.  * Revision 1.23  2007/01/07 23:37:26  fplanque
  932.  * doc cleanup
  933.  *
  934.  * Revision 1.22  2006/12/10 23:20:55  fplanque
  935.  * hum...
  936.  *
  937.  * Revision 1.21  2006/12/10 03:04:31  blueyed
  938.  * todo
  939.  *
  940.  * Revision 1.20  2006/11/24 18:27:24  blueyed
  941.  * Fixed link to b2evo CVS browsing interface in file docblocks
  942.  */

Documentation generated on Sat, 06 Mar 2010 04:07:44 +0100 by phpDocumentor 1.4.2. This site is hosted and maintained by Daniel HAHLER (Contact).