Source for file _genericcategorycache.class.php
Documentation is available at _genericcategorycache.class.php
* This file implements the GenericCategoryCache class.
* This is the object handling genreric category lists.
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link http://sourceforge.net/projects/evocms/}.
* @copyright (c)2003-2010 by Francois PLANQUE - {@link http://fplanque.net/}
* Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
* {@internal License choice
* - If you have received this file as part of a package, please find the license.txt file in
* the same folder or the closest folder above for complete license terms.
* - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
* then you must choose one of the following licenses before using the file:
* - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
* - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
* {@internal Open Source relicensing agreement:
* PROGIDISTRI S.A.S. grants Francois PLANQUE the right to license
* PROGIDISTRI S.A.S.'s contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
* @author fplanque: Francois PLANQUE.
* @author mbruneau: Marc BRUNEAU / PROGIDISTRI
* @version $Id: _genericcategorycache.class.php,v 1.10 2010/02/08 17:53:03 efy-yury Exp $
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
load_class( 'generic/model/_genericcache.class.php', 'GenericCache' );
// DEBUG: (Turn switch on or off to log debug info for specified category)
$GLOBALS['debug_CategoryCache'] =
false;
* GenericCategoryCache class
* Which property of the objects defines the subset
* Which subsets have been loaded
* These are the level 0 categories (which have no parent)
* These are the level 0 categories (which have no parent) for each subset
* Have the children been revealed for all subsets yet?
* Have the children been revealed for all subsets yet?
function GenericCategoryCache( $objtype, $load_all, $tablename, $prefix =
'', $dbIDname =
'ID', $name_field =
NULL, $subset_property =
NULL, $order_by =
'' )
parent::GenericCache( $objtype, $load_all, $tablename, $prefix, $dbIDname, $name_field, $order_by );
* Add a dataobject to the cache
if( parent::add( $Obj ) )
{ // Also add to subset cache:
* After this each Category will have an array pointing to its direct children
* @param integer|NULLNULL for all subsets
{ // ALL Children have already been revealed: (can happen even if we require a subset *now*)
{ // We are not handling subsets
echo
'Revealing all children -- this is not yet handling all edge cases that the subset version can handle';
// Make sure everything has been loaded:
if( !empty( $this->cache ) )
{ // There are loaded categories, so loop on all loaded categories to set their children list if it has:
foreach( $this->cache as $cat_ID =>
$GenericCategory )
// echo $GenericCategory->name;
if( ! is_null( $GenericCategory->parent_ID ) )
{ // This category has a parent, so add it to its parent children list:
$this->cache[$GenericCategory->parent_ID]->add_children( $this->cache[$cat_ID] );
{ // This category has no parent, so add it to the parent categories list
{ // We are handling subsets
{ // No specific subset requested, we are going to reveal all subsets
// Make sure everything has been loaded:
echo
'REVEALING ALL SUBSETS in a row. Is this needed?';
{ // We're interested in a specific subset
{ // Children have already been revealed:
$Timer->resume('reveal_children', false );
$Debuglog->add( 'Revealing subset of children', 'CategoryCache' );
// Make sure the requested subset has been loaded:
$this->load_subset($subset_ID);
{ // There are loaded categories
// Now check that each category has a path to the root:
foreach( $this->subset_cache[$subset_ID] as $cat_ID =>
$dummy ) // "as" would give a freakin copy of the object :(((
// loop on all loaded categories to set their children list if it has some:
foreach( $this->subset_cache[$subset_ID] as $cat_ID =>
$dummy ) // "as" would give a freakin copy of the object :(((
$GenericCategory =
& $this->subset_cache[$subset_ID][$cat_ID];
// echo $GenericCategory->name;
if( ! is_null( $GenericCategory->parent_ID ) )
{ // This category has a parent, so add it to its parent children list:
$Debuglog->add( 'adding child with ID='.
$cat_ID.
' to parent ID='.
$GenericCategory->parent_ID, 'CategoryCache' );
$this->cache[$GenericCategory->parent_ID]->add_children( $this->cache[$cat_ID] );
{ // This category has no parent, so add it to the parent categories list
$Debuglog->add( 'adding parent with ID='.
$cat_ID, 'CategoryCache' );
$this->root_cats[] =
& $GenericCategory; // $this->cache[$cat_ID];
$Timer->pause('reveal_children', false );
// Children have been revealed.
* Support function for reveal_children()
* @return true if root parent
$Debuglog->add( $padding.
'Checking path to root for cat ID='.
$cat_ID.
' with path:'.
implode(',',$path_array), 'CategoryCache' );
$GenericCategory =
& $this->subset_cache[$subset_ID][$cat_ID];
if( is_null( $GenericCategory->parent_ID ) )
$Debuglog->add( $padding.
'*OK', 'CategoryCache' );
// This is not the last parent...
$path_array[] =
$GenericCategory->ID;
if( in_array( $GenericCategory->parent_ID, $path_array ) )
{ // We are about to enter an infinite loop
$Debuglog->add( $padding.
'*LOOP! -> assign to root', 'CategoryCache' );
$GenericCategory->parent_ID =
NULL;
elseif( ! isset
($this->cache[$GenericCategory->parent_ID] ) )
$Debuglog->add( $padding.
'*Missing parent ID('.
$GenericCategory->parent_ID.
')! -> assign to root', 'CategoryCache' );
$GenericCategory->parent_ID =
NULL;
* Return recursive display of loaded categories
* @param array callback funtions (to format the display)
* @param integer|NULLNULL for all subsets
* @param array categories list to display
* @param int depth of categories list
* @return string recursive list of all loaded categories
function recurse( $callbacks, $subset_ID =
NULL, $cat_array =
NULL, $level =
0 )
// Make sure children have been revealed for specific subset:
{ // Get all parent categories:
{ // We have root cats for the requested subset:
if( is_array( $callbacks['before_level'] ) )
$r .=
$callbacks['before_level'][0]->{$callbacks['before_level'][1]}( $level ); // <ul>
$r .=
$callbacks['before_level']( $level ); // <ul>
foreach( $cat_array as $cat )
$r .=
$callbacks['line'][0]->{$callbacks['line'][1]}( $cat, $level ); // <li> Category - or - <tr><td>Category</td></tr> ...
$r .=
$callbacks['line']( $cat, $level ); // <li> Category - or - <tr><td>Category</td></tr> ...
if( !empty( $cat->children ) )
{ // Add children categories:
$r .=
$this->recurse( $callbacks, $subset_ID, $cat->children, $level+
1 );
elseif( is_array( $callbacks['no_children'] ) )
$r .=
$callbacks['no_children'][0]->{$callbacks['no_children'][1]}( $cat, $level ); // </li>
$r .=
$callbacks['no_children']( $cat, $level ); // </li>
if( is_array( $callbacks['after_level'] ) )
$r .=
$callbacks['after_level'][0]->{$callbacks['after_level'][1]}( $level ); // </ul>
$r .=
$callbacks['after_level']( $level ); // </ul>
* Return recursive select options list of all loaded categories
* @param integer selected category in the select input
* @param integer NULL for all subsets
* @param boolean Include the root element?
* @param array GenercCategory objects to display (will recurse from those starting points)
* @param integer depth of categories list
* @param array IDs of categories to exclude (their children will be ignored to)
* @return string select options list of all loaded categories
function recurse_select( $selected =
NULL, $subset_ID =
NULL, $include_root =
false, $Cat_array =
NULL,
$level =
0, $exclude_array =
array() )
// pre_dump( $exclude_array );
// Make sure children have been revealed for specific subset:
{ // Get all parent categorie:
$r .=
'<option value="">'.
T_('Root').
'</option>';
foreach( $Cat_array as $GenericCategory )
if( in_array( $GenericCategory->ID, $exclude_array ) )
{ // We want to exclude that cat.
// Set category indentation in the select:
for($i =
0; $i <
$level; $i++
)
$indent .=
' ';
$r .=
'<option value="'.
$GenericCategory->ID.
'" ';
if( $GenericCategory->ID ==
$selected ) $r .=
' selected="selected"';
$r .=
' >'.
$indent.
$GenericCategory->name.
'</option>';
if( !empty( $GenericCategory->children ) )
{ // Add children categories:
$r .=
$this->recurse_select( $selected, $subset_ID, false, $GenericCategory->children, $level+
1, $exclude_array );
* $Log: _genericcategorycache.class.php,v $
* Revision 1.10 2010/02/08 17:53:03 efy-yury
* Revision 1.9 2009/11/30 00:22:05 fplanque
* show more timers in view of block caching
* Revision 1.8 2009/09/14 13:11:37 efy-arrin
* Included the ClassName in load_class() call with proper UpperCase
* Revision 1.7 2009/03/08 23:57:43 fplanque
* Revision 1.6 2009/01/28 21:23:23 fplanque
* Manual ordering of categories
* Revision 1.5 2008/12/28 19:00:14 fplanque
* Fixed multiple category parent/child recursion issues. It should no longer be possible to "lose" categories by creating loops.
* Revision 1.4 2008/01/21 09:35:30 fplanque
* Revision 1.3 2007/10/08 08:33:15 fplanque
* Revision 1.1 2007/06/25 11:00:16 fplanque
* MODULES (refactored MVC)
* Revision 1.15 2007/04/26 00:11:11 fplanque
* Revision 1.14 2006/12/10 02:01:11 fplanque
* Revision 1.13 2006/12/10 01:52:27 fplanque
* old cats are now officially dead :>
* Revision 1.12 2006/12/09 02:37:44 fplanque
* Prevent user from creating loops in the chapter tree
* (still needs a check before writing to DB though)
* Revision 1.11 2006/11/26 01:42:09 fplanque