phpDocumentor pond
[ class tree: pond ] [ index: pond ] [ all elements ]

Source for file _dataobjectcache.class.php

Documentation is available at _dataobjectcache.class.php

  1. <?php
  2. /**
  3.  * This file implements the DataObjectCache class.
  4.  *
  5.  * This file is part of Quam Plures - {@link http://quamplures.net/}
  6.  * See also {@link https://launchpad.net/quam-plures}.
  7.  *
  8.  * @copyright (c) 2009 - 2011 by the Quam Plures developers - {@link http://quamplures.net/}
  9.  * @copyright (c)2003-2009 by Francois PLANQUE - {@link http://fplanque.net/}
  10.  *  Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  11.  *  Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
  12.  *
  13.  *  {@internal License choice
  14.  *  - If you have received this file as part of a package, please find the license.txt file in
  15.  *    the same folder or the closest folder above for complete license terms.
  16.  *  - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  17.  *    then you must choose one of the following licenses before using the file:
  18.  *    - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  19.  *    - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  20.  *  }}}
  21.  *
  22.  *  {@internal Open Source relicensing agreement:
  23.  *  Daniel HAHLER grants Francois PLANQUE the right to license
  24.  *  Daniel HAHLER's contributions to this file and the b2evolution project
  25.  *  under any OSI approved OSS license (http://www.opensource.org/licenses/).
  26.  *
  27.  *  PROGIDISTRI S.A.S. grants Francois PLANQUE the right to license
  28.  *  PROGIDISTRI S.A.S.'s contributions to this file and the b2evolution project
  29.  *  under any OSI approved OSS license (http://www.opensource.org/licenses/).
  30.  *  }}}
  31.  *
  32.  *  {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  33.  * @author blueyed: Daniel HAHLER.
  34.  * @author fplanque: Francois PLANQUE
  35.  *
  36.  * @package pond
  37.  */
  38. if!defined('QP_MAIN_INIT') ) die'Please, do not access this page directly.' );
  39.  
  40. /**
  41.  * Data Object Cache Class
  42.  *
  43.  * @todo dh> Provide iteration "interface"!
  44.  *
  45.  * @version beta
  46.  *
  47.  * @package pond
  48.  */
  49. {
  50.     var $dbtablename;
  51.     var $dbprefix;
  52.     var $dbIDname;
  53.  
  54.     /**
  55.      * Class name of objects in this cache:
  56.      */
  57.     var $objtype;
  58.  
  59.     /**
  60.      * Object array by ID
  61.      */
  62.     var $cache = array();
  63.  
  64.     /**
  65.      * Copy of previous object array
  66.      * @see DataObjectCache::clear()
  67.      */
  68.     var $shadow_cache = NULL;
  69.  
  70.     /**
  71.      * NON indexed object array
  72.      * @var array of DataObjects
  73.      */
  74.     var $DataObject_array = array();
  75.  
  76.   /**
  77.      * Index of current iteration
  78.      * @see DataObjectCache::get_next()
  79.      */
  80.     var $current_idx = NULL;
  81.  
  82.     var $load_all = false;
  83.     var $all_loaded = false;
  84.  
  85.  
  86.     var $name_field;
  87.     var $order_by;
  88.  
  89.     /**
  90.      * The text that gets used for the "None" option in the objects options list.
  91.      *
  92.      * This is especially useful for i18n, because there are several "None"s!
  93.      *
  94.      * @var string 
  95.      */
  96.     var $none_option_text;
  97.  
  98.     /**
  99.      * The value that gets used for the "None" option in the objects options list.
  100.      *
  101.      * @var mixed 
  102.      */
  103.     var $none_option_value;
  104.  
  105.  
  106.     /**
  107.      * Constructor
  108.      *
  109.      * @param string Name of DataObject class we are cacheing
  110.      * @param boolean true if it's OK to just load all items!
  111.      * @param string Name of table in database
  112.      * @param string Prefix of fields in the table
  113.      * @param string Name of the ID field (including prefix)
  114.      * @param string Name of the name field (including prefix)
  115.      * @param string field names or NULL to use name field
  116.      * @param string The text that gets used for the "None" option in the objects options list (Default: T_('None')).
  117.      * @param mixed  The value that gets used for the "None" option in the objects options list.
  118.      */
  119.     function DataObjectCache$objtype$load_all$tablename$prefix ''$dbIDname$name_field NULL$order_by ''$allow_none_text NULL$allow_none_value '' )
  120.     {
  121.         $this->objtype = $objtype;
  122.         $this->load_all = $load_all;
  123.         $this->dbtablename = $tablename;
  124.         $this->dbprefix = $prefix;
  125.         $this->dbIDname = $dbIDname;
  126.         $this->name_field = $name_field;
  127.         $this->none_option_value = $allow_none_value;
  128.  
  129.         ifempty$order_by ) )
  130.         {
  131.             ifempty$name_field ) )
  132.             {
  133.                 $this->order_by = $dbIDname;
  134.             }
  135.             else
  136.             {
  137.                 $this->order_by = $name_field;
  138.             }
  139.         }
  140.         else
  141.         {
  142.             $this->order_by = $order_by;
  143.         }
  144.  
  145.         ifisset($allow_none_text) )
  146.         {
  147.             $this->none_option_text = $allow_none_text;
  148.         }
  149.         else
  150.         {
  151.             $this->none_option_text = /* TRANS: the default value for option lists where "None" is allowed */ T_('None');
  152.         }
  153.     }
  154.  
  155.  
  156.     /**
  157.      * Instanciate a new object within this cache
  158.      */
  159.     function new_obj$row NULL )
  160.     {
  161.         $objtype $this->objtype;
  162.  
  163.         // Instantiate a custom object
  164.         $obj new $objtype$row )// COPY !!
  165.  
  166.         return $obj;
  167.     }
  168.  
  169.  
  170.     /**
  171.      * Load the cache **extensively**
  172.      */
  173.     function load_all()
  174.     {
  175.         /**
  176.          * @var DB
  177.          */
  178.         global $DB;
  179.         global $Debuglog;
  180.  
  181.         if$this->all_loaded )
  182.         // Already loaded
  183.             return false;
  184.         }
  185.  
  186.         $this->cleartrue );
  187.  
  188.         $Debuglog->addget_class($this).' - Loading <strong>'.$this->objtype.'(ALL)</strong> into cache''dataobjects' );
  189.         $sql 'SELECT *
  190.                             FROM '.$this->dbtablename.'
  191.                          ORDER BY '.$this->order_by;
  192.  
  193.         foreach$DB->get_results$sqlOBJECT'Loading '.$this->objtype.'(ALL) into cache' as $row )
  194.         {
  195.             // Instantiate a custom object
  196.             $this->instantiate$row );
  197.         }
  198.  
  199.         $this->all_loaded = true;
  200.  
  201.         return true;
  202.     }
  203.  
  204.  
  205.     /**
  206.      * Load a list of objects into the cache
  207.      *
  208.      * @param string list of IDs of objects to load
  209.      * @param boolean Invert list: Load all objects except those listed in the first parameter
  210.      */
  211.     function load_list$req_list$invert false )
  212.     {
  213.         global $DB$Debuglog;
  214.  
  215.         $Debuglog->add'Loading <strong>'.$this->objtype.'('.$invert 'ALL except ' '' ).$req_list.')</strong> into cache''dataobjects' );
  216.  
  217.         ifempty$req_list ) )
  218.         {
  219.             return false;
  220.         }
  221.  
  222.         $sql "SELECT *
  223.                   FROM $this->dbtablename
  224.                  WHERE $this->dbIDname ".$invert 'NOT ' '' )."IN ($req_list)";
  225.  
  226.         foreach$DB->get_results$sql as $row )
  227.         {
  228.             // Instantiate a custom object
  229.             $this->instantiate$row );
  230.         }
  231.     }
  232.  
  233.  
  234.     /**
  235.      * Get an array of all (loaded) IDs.
  236.      *
  237.      * @return array 
  238.      */
  239.     function get_ID_array()
  240.     {
  241.         $IDs array();
  242.  
  243.         foreach$this->cache as $obj )
  244.         {
  245.             $IDs[$obj->ID;
  246.         }
  247.  
  248.         return $IDs;
  249.     }
  250.  
  251.  
  252.     /**
  253.      * Add a dataobject to the cache
  254.      */
  255.     function add$Obj )
  256.     {
  257.         global $Debuglog;
  258.  
  259.         ifis_null($Obj->ID) )    // value 0 is used by item preview
  260.         {
  261.             $Debuglog->add'No object to add!''dataobjects' );
  262.             return false;
  263.         }
  264.  
  265.         // fplanque: I don't want an extra (and expensive) comparison here. $this->cache[$Obj->ID] === $Obj.
  266.         // If you need this you're probably misusing the cache.
  267.         ifisset($this->cache[$Obj->ID]) )
  268.         {
  269.             $Debuglog->add$this->objtype.': Object with ID '.$Obj->ID.' is already cached''dataobjects' );
  270.             return false;
  271.         }
  272.  
  273.         // If the object is valid and not already cached:
  274.         // Add object to cache:
  275.         $this->cache[$Obj->ID$Obj;
  276.         // Add a reference in the object list:
  277.         $this->DataObject_array[$Obj;
  278.  
  279.         return true;
  280.     }
  281.  
  282.  
  283.     /**
  284.      * Instantiate a DataObject from a table row and then cache it.
  285.      *
  286.      * @param Object Database row
  287.      * @return Object 
  288.      */
  289.     function instantiate$db_row )
  290.     {
  291.         ifis_null($db_row) )
  292.         {    // we can't access NULL as an object
  293.             return $db_row;
  294.         }
  295.  
  296.         // Get ID of the object we'ere preparing to instantiate...
  297.         $obj_ID $db_row->{$this->dbIDname};
  298.  
  299.         ifis_null($obj_ID) )    // value 0 is used for item preview
  300.         {
  301.             $Obj NULL;
  302.             return $Obj;
  303.         }
  304.  
  305.         ifisset$this->cache[$obj_ID) )
  306.         // Already in cache, do nothing!
  307.         }
  308.         elseifisset$this->shadow_cache[$obj_ID) )
  309.         {    // Already in shadow, recycle object:
  310.             $this->add$this->shadow_cache[$obj_ID);
  311.         }
  312.         else
  313.         // Not already cached, add new object:
  314.             $this->add$this->new_obj$db_row ) );
  315.         }
  316.  
  317.         return $this->cache[$obj_ID];
  318.     }
  319.  
  320.  
  321.     /**
  322.      * Clear the cache **extensively**
  323.      *
  324.      */
  325.     function clear$keep_shadow false )
  326.     {
  327.         if$keep_shadow )
  328.         {    // Keep copy of cache in case we try to re instantiate previous object:
  329.             $this->shadow_cache = $this->cache;
  330.         }
  331.         else
  332.         {
  333.             $this->shadow_cache = NULL;
  334.         }
  335.  
  336.         $this->cache = array();
  337.         $this->DataObject_array = array();
  338.         $this->all_loaded = false;
  339.         $this->current_idx = NULL;
  340.     }
  341.  
  342.  
  343.   /**
  344.      * This provides a simple interface for looping over the contents of the Cache.
  345.      *
  346.      * This should only be used for basic enumeration.
  347.      * If you need complex filtering of the cache contents, you should probablt use a DataObjectList instead.
  348.      *
  349.      * @see DataObject::get_next()
  350.      *
  351.      * @return DataObject 
  352.      */
  353.     function get_first()
  354.     {
  355.         $this->load_all();
  356.  
  357.         $this->current_idx = -1;
  358.         return $this->get_next();
  359.     }
  360.  
  361.  
  362.   /**
  363.      * This provides a simple interface for looping over the contents of the Cache.
  364.      *
  365.      * This should only be used for basic enumeration.
  366.      * If you need complex filtering of the cache contents, you should probablt use a DataObjectList instead.
  367.      *
  368.      * @see DataObject::get_first()
  369.      *
  370.      * @return DataObject 
  371.      */
  372.     function get_next()
  373.     {
  374.         $this->current_idx++;
  375.  
  376.         ifisset$this->DataObject_array[$this->current_idx) )
  377.         {
  378.             $this->current_idx = NULL;
  379.             $r NULL;
  380.             return $r;
  381.         }
  382.  
  383.         return $this->DataObject_array[$this->current_idx];
  384.     }
  385.  
  386.  
  387.     /**
  388.      * Get an object from cache by ID
  389.      *
  390.      * Load the cache if necessary (all at once if allowed).
  391.      *
  392.      * @param integer ID of object to load
  393.      * @param boolean true if function should die on error
  394.      * @param boolean true if function should die on empty/null
  395.      * @return DataObject reference on cached object
  396.      */
  397.     function get_by_ID$req_ID$halt_on_error true$halt_on_empty true )
  398.     {
  399.         global $DB$Debuglog;
  400.  
  401.         ifempty($req_ID) )
  402.         {
  403.             if($halt_on_empty)
  404.             {
  405.                 debug_die"Requested $this->objtype from $this->dbtablename without ID!);
  406.             }
  407.             $r NULL;
  408.             return $r;
  409.         }
  410.  
  411.         if!empty$this->cache$req_ID ) )
  412.         // Already in cache
  413.             // $Debuglog->add( "Accessing $this->objtype($req_ID) from cache", 'dataobjects' );
  414.             return $this->cache$req_ID ];
  415.         }
  416.         elseif!$this->all_loaded )
  417.         // Not in cache, but not everything is loaded yet
  418.             if$this->load_all )
  419.             // It's ok to just load everything:
  420.                 $this->load_all();
  421.             }
  422.             else
  423.             // Load just the requested object:
  424.                 $Debuglog->add"Loading <strong>$this->objtype($req_ID)</strong> into cache"'dataobjects' );
  425.                 // Note: $req_ID MUST be an unsigned integer. This is how DataObject works.
  426.                 $sql "SELECT *
  427.                           FROM $this->dbtablename
  428.                          WHERE $this->dbIDname = $req_ID";
  429.                 if$row $DB->get_row$sqlOBJECT0'DataObjectCache::get_by_ID()' ) )
  430.                 {
  431.                     if$this->instantiate$row ) )
  432.                     {
  433.                         $Debuglog->add'Could not add() object to cache!''dataobjects' );
  434.                     }
  435.                 }
  436.                 else
  437.                 {
  438.                     $Debuglog->add'Could not get DataObject by ID. Query: '.$sql'dataobjects' );
  439.                 }
  440.             }
  441.         }
  442.  
  443.         ifempty$this->cache$req_ID ) )
  444.         // Requested object does not exist
  445.             // $Debuglog->add( 'failure', 'dataobjects' );
  446.             if$halt_on_error )
  447.             {
  448.                 debug_die"Requested $this->objtype does not exist!);
  449.             }
  450.             $r false;
  451.             return $r;
  452.         }
  453.  
  454.         return $this->cache$req_ID ];
  455.     }
  456.  
  457.  
  458.     /**
  459.      * Get an object from cache by name
  460.      *
  461.      * Load the cache if necessary (all at once if allowed).
  462.      *
  463.      * @param integer ID of object to load
  464.      * @param boolean true if function should die on error
  465.      * @param boolean true if function should die on empty/null
  466.      * @return reference on cached object
  467.      */
  468.     function get_by_name$req_name$halt_on_error true$halt_on_empty true )
  469.     {
  470.         global $DB$Debuglog;
  471.  
  472.         ifempty$this->name_field ) )
  473.         {
  474.             debug_die'DataObjectCache::get_by_name() : No name field to query on' );
  475.         }
  476.  
  477.         ifempty($req_name) )
  478.         {
  479.             if($halt_on_emptydebug_die"Requested $this->objtype from $this->dbtablename without name!)}
  480.             $r NULL;
  481.             return $r;
  482.         }
  483.  
  484.         // Load just the requested object:
  485.         $Debuglog->add"Loading <strong>$this->objtype($req_name)</strong>"'dataobjects' );
  486.         $sql "SELECT *
  487.                           FROM $this->dbtablename
  488.                          WHERE $this->name_field = ".$DB->quote($req_name);
  489.  
  490.         if$db_row $DB->get_row$sqlOBJECT0'DataObjectCache::get_by_name()' ) )
  491.         {
  492.             $resolved_ID $db_row->{$this->dbIDname};
  493.             $Debuglog->add'success; ID = '.$resolved_ID'dataobjects' );
  494.             ifisset$this->cache[$resolved_ID) )
  495.             {    // Object is not already in cache:
  496.                 $Debuglog->add'Adding to cache...''dataobjects' );
  497.                 //$Obj = new $this->objtype( $row ); // COPY !!
  498.                 //if( ! $this->add( $this->new_obj( $db_row ) ) )
  499.                 if$this->add$this->new_obj$db_row ) ) )
  500.                 {    // could not add
  501.                     $Debuglog->add'Could not add() object to cache!''dataobjects' );
  502.                 }
  503.             }
  504.             return $this->cache[$resolved_ID];
  505.         }
  506.         else
  507.         {
  508.             $Debuglog->add'Could not get DataObject by name.''dataobjects' );
  509.             if$halt_on_error )
  510.             {
  511.                 debug_die"Requested $this->objtype does not exist!);
  512.             }
  513.             $r NULL;
  514.             return $r;
  515.         }
  516.     }
  517.  
  518.  
  519.     /**
  520.      * Remove an object from cache by ID
  521.      *
  522.      * @param integer ID of object to remove
  523.      */
  524.     function remove_by_ID$req_ID )
  525.     {
  526.         unset$this->cache[$req_ID);
  527.     }
  528.  
  529.  
  530.     /**
  531.      * Delete an object from DB by ID.
  532.      *
  533.      * @param integer ID of object to delete
  534.      * @return boolean 
  535.      */
  536.     function dbdelete_by_ID$req_ID )
  537.     {
  538.         ifisset$this->cache[$req_ID) )
  539.         {
  540.             // Delete from db
  541.             $this->cache[$req_ID]->dbdelete();
  542.  
  543.             // Remove from cache
  544.             $this->remove_by_ID$req_ID );
  545.  
  546.             return true;
  547.         }
  548.         else
  549.         {
  550.             return false;
  551.         }
  552.     }
  553.  
  554.  
  555.     /**
  556.      * Returns form option list with cache contents
  557.      *
  558.      * Load the cache if necessary
  559.      *
  560.      * @param integer selected ID
  561.      * @param boolean provide a choice for "none" with ID ''
  562.      * @param string Callback method name
  563.      * @param array IDs to ignore.
  564.      * @return string 
  565.      */
  566.     function get_option_list$default 0$allow_none false$method 'get_name'$ignore_IDs array() )
  567.     {
  568.         if!is_array$default ) )
  569.         {
  570.             $default array$default );
  571.         }
  572.  
  573.         if$this->all_loaded && $this->load_all )
  574.         // We have not loaded all items so far, but we're allowed to.
  575.             if empty$ignore_IDs ) )
  576.             {    // just load all items
  577.                 $this->load_all();
  578.             }
  579.             else
  580.             {    // only load those items not listed in $ignore_IDs
  581.                 $this->load_listimplode','$ignore_IDs )true );
  582.             }
  583.         }
  584.  
  585.         $r '';
  586.  
  587.         if$allow_none )
  588.         {
  589.             $r .= '<option value="'.$this->none_option_value.'"';
  590.             ifempty($default) ) $r .= ' selected="selected"';
  591.             $r .= '>'.format_to_output($this->none_option_text).'</option>'."\n";
  592.         }
  593.  
  594.         foreach$this->cache as $loop_Obj )
  595.         {
  596.             if in_array$loop_Obj->ID$ignore_IDs ) )
  597.             {    // Ignore this ID
  598.                 continue;
  599.             }
  600.  
  601.             $r .=  '<option value="'.$loop_Obj->ID.'"';
  602.             ifin_array$loop_Obj->ID$default ) ) $r .= ' selected="selected"';
  603.             $r .= '>';
  604.             $r .= format_to_output$loop_Obj->$method()'htmlbody' );
  605.             $r .=  '</option>'."\n";
  606.         }
  607.  
  608.         return $r;
  609.     }
  610.  
  611.  
  612.     /**
  613.      * Returns option array with cache contents
  614.      *
  615.      * Load the cache if necessary
  616.      *
  617.      * @param string Callback method name
  618.      * @param array IDs to ignore.
  619.      * @return string 
  620.      */
  621.     function get_option_array$method 'get_name'$ignore_IDs array() )
  622.     {
  623.         if$this->all_loaded && $this->load_all )
  624.         // We have not loaded all items so far, but we're allowed to.
  625.             if empty$ignore_IDs ) )
  626.             {    // just load all items
  627.                 $this->load_all();
  628.             }
  629.             else
  630.             {    // only load those items not listed in $ignore_IDs
  631.                 $this->load_listimplode','$ignore_IDs )true );
  632.             }
  633.         }
  634.  
  635.         $r array();
  636.  
  637.         foreach$this->cache as $loop_Obj )
  638.         {
  639.             ifin_array$loop_Obj->ID$ignore_IDs ) )
  640.             {    // Ignore this ID
  641.                 continue;
  642.             }
  643.  
  644.             $r[$loop_Obj->ID$loop_Obj->$method();
  645.         }
  646.  
  647.         return $r;
  648.     }
  649.  
  650. }
  651.  
  652.  
  653. ?>