Source for file ObjectUtil.class.php
Documentation is available at ObjectUtil.class.php
* Zikula Application Framework
* @copyright Robert Gasch
* @link http://www.zikula.org
* @version $Id: ObjectUtil.class.php 24342 2008-06-06 12:03:14Z markwest $
* @license GNU/GPL - http://www.gnu.org/copyleft/gpl.html
* @author Robert Gasch rgasch@gmail.com
* Add standard PN architecture fields to the table definition
* @param columns The column list from the PNTables structure for the current table
* @param col_prefix The column prefix
* @return Nothing, column array is altered in place
// ensure correct handling of prefix with and without underscore
if ($col_prefix[$plen- 1] != '_')
$columns['obj_status'] = $col_prefix . 'obj_status';
$columns['cr_date'] = $col_prefix . 'cr_date';
$columns['cr_uid'] = $col_prefix . 'cr_uid';
$columns['lu_date'] = $col_prefix . 'lu_date';
$columns['lu_uid'] = $col_prefix . 'lu_uid';
* Generate the SQL to create the standard PN architecture fields
* @param columns The column list from the PNTables structure for the current table
* @return The generated SQL string
$sql = "$columns[obj_status] CHAR(1) NOT NULL DEFAULT 'A',
$columns[cr_date] DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00',
$columns[cr_uid] INTEGER NOT NULL DEFAULT '0',
$columns[lu_date] DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00',
$columns[lu_uid] INTEGER NOT NULL DEFAULT '0'";
* Generate the ADODB DD field descruptors for the standard PN architecture fields
* @param columns The column list from the PNTables structure for the current table
* @return The modified list of ADODB DD strings
$columns['obj_status'] = "C(1) NOTNULL DEFAULT 'A'";
$columns['cr_date'] = "T NOTNULL DEFAULT '1970-01-01 00:00:00'";
$columns['cr_uid'] = "I NOTNULL DEFAULT '0'";
$columns['lu_date'] = "T NOTNULL DEFAULT '1970-01-01 00:00:00'";
$columns['lu_uid'] = "I NOTNULL DEFAULT '0'";
* Generate the ADODB datadict entries to create the standard PN architecture fields
* @param $table The table to add standard fields using ADODB dictionary method
* @return The generated SQL string
$columns = $pntables["{ $table}_column "];
$columns[obj_status] C(1) NOTNULL DEFAULT 'A',
$columns[cr_date] T NOTNULL DEFAULT '1970-01-01 00:00:00',
$columns[cr_uid] I NOTNULL DEFAULT '0',
$columns[lu_date] T NOTNULL DEFAULT '1970-01-01 00:00:00',
$columns[lu_uid] I NOTNULL DEFAULT '0'";
* Set the standard PN architecture fields for object creation/insert
* @param object The object we need to set the standard fields on
* @param preserveValues whether or not to preserve value fields which have a valid value set (optional) (default=false)
* @param idcolumn The column name of the primary key column (optional) (default='id')
* @return Nothing, object is altered in place
print "ObjectUtil::setStandardFieldsOnObjectUpdate called on non-object:<br />";
$obj[$idcolumn] = ( isset ($obj[$idcolumn]) && $obj[$idcolumn] && $preserveValues ? $obj[$idcolumn] : null);
$obj['cr_date'] = ( isset ($obj['cr_date']) && $obj['cr_date'] && $preserveValues ? $obj['cr_date'] : DateUtil::getDatetime());
$obj['cr_uid'] = ( isset ($obj['cr_uid']) && $obj['cr_uid'] && $preserveValues ? $obj['cr_uid'] : pnUserGetVar('uid'));
$obj['lu_date'] = ( isset ($obj['lu_date']) && $obj['lu_date'] && $preserveValues ? $obj['lu_date'] : DateUtil::getDatetime());
$obj['lu_uid'] = ( isset ($obj['lu_uid']) && $obj['lu_uid'] && $preserveValues ? $obj['lu_uid'] : pnUserGetVar('uid'));
* Set the standard PN architecture fields to sane values for an object update
* @param object The object we need to set the standard fields on
* @param preserveValues whether or not to preserve value fields which have a valid value set (optional) (default=false)
* @return Nothing, object is altered in place
print "ObjectUtil::setStandardFieldsOnObjectUpdate called on non-object:<br />";
$obj['lu_date'] = ( isset ($obj['lu_date']) && $obj['lu_date'] && $preserveValues ? $obj['lu_date'] : DateUtil::getDatetime());
$obj['lu_uid'] = ( isset ($obj['lu_uid']) && $obj['lu_uid'] && $preserveValues ? $obj['lu_uid'] : pnUserGetVar('uid'));
* Remove the standard fields from the given object
* @param object The object to operate on
* @return Nothing, object is altered in place
unset ($obj['obj_status']);
* If the specified field is set return it, otherwise return default
* @param object The object to get the field from
* @param field The field to get
* @param default The default value to return if the field is not set on the object (default=null) (optional)
* @return The object field value or the default
function getField ($obj, $field, $default= null)
* Create an object of the reuqested type and set the cr_date and cr_uid fields.
* @param $type The type of the object to create
* @return The newly created object
return pn_exit ("ObjectUtil::createObject: unable to reference object type [$type]");
$obj['__TYPE__'] = $type;
$obj['cr_date'] = DateUtil::getDateTime ();
* @param object1 The first array/object
* @param object2 The second object/array
* @return The difference between the two objects
function diff ($obj1, $obj2)
return pn_exit ("ObjectUtil::diff: object1 is not an object ... ");
return pn_exit ("ObjectUtil::diff: object2 is not an object ... ");
* Provide an informative extended diff array when comparing 2 arrays
* @param detail whether or not to give detailed update info (optional (default=false)
* @param recurse whether or not to recurse (optional) (default=true)
* @return A data array containing the diff results
function diffExtended ($a1, $a2, $detail= false, $recurse= true)
foreach ($a1 as $k => $v)
$res[$k]['new'] = $a2[$k];
$res[$k] = 'U: ' . $a2[$k];
foreach ($a2 as $k => $v)
* Fixes the sequence numbers (column position) in a given table.
* Needed, if an object was added or deleted in a table using the
* @param tablename The tablename key for the PNTables structure
* @param field The name of the field we wish to resequence (optional) (default='position')
* @param float whether or not to use a float (optional) (default=false (uses integer))
* @param idcolumn The column which contains the unique ID
function resequenceFields ($tablename, $field= 'position', $float= false, $idcolumn= 'id')
$column = $pntables["{ $tablename}_column "];
$tab = $pntables[$tablename];
return pn_exit ("ObjectUtil::resequenceFields: there is no [$field] field in the [$tablename] table... ");
$sql = "SELECT $column[$idcolumn], $column[$field]
ORDER BY $column[$field]";
$seq = ($float ? 1.0 : 1);
while(list ($id, $curseq) = $res->fields)
* Increments or decremnts a sequence number (column position) in a table for
* a given ID. If exists, it swaps the sequence of the field above or down.
* @param object The object we wish to increment or decrement
* @param tablename The tablename key for the PNTables structure
* @param direction whether we want to increment or decrement the position of the object. Possible values are 'up' (default) and 'down'
* @param field The name of the field we wish to resequence
* @param idcolumn The column which contains the unique ID
* @param field2 An additional field to consider in the where-clause
* @param value2 An additional value to consider in the where-clause
* @return true/false on success/failure
function moveField ($obj, $tablename, $direction= 'up', $field= 'position', $idcolumn= 'id',
return pn_exit ("ObjectUtil::moveField: object is not an array ... ");
if (!isset ($obj[$idcolumn]))
return pn_exit ("ObjectUtil::moveField: no object ID ... ");
$column = $pntables["{ $tablename}_column "];
$tab = $pntables[$tablename];
return pn_exit ("ObjectUtil::moveField: there is no $field field in the specified table... ");
// Get info on current position of field
// Get info on displaced field
if ($field2 && $value2) {
if ($direction == 'up') {
$sql = "SELECT $column[$idcolumn], $column[$field]
ORDER BY $column[$field] DESC LIMIT 0,1";
}else if ($direction == 'down') {
$sql = "SELECT $column[$idcolumn], $column[$field]
ORDER BY $column[$field] ASC LIMIT 0,1";
return pn_exit ("ObjectUtil::moveField: invalid direction [$direction] supplied ... ");
if ($res->EOF) // No field directly above or below that one
list ($altid, $altseq) = $res->fields;
* Retrieve the attribute maps for the specified object
* @param object The object whose attribute we wish to retrieve
* @param type The type of the given object
* @param idcolumn The column which holds the ID value (optional) (default='id')
* @return The object attribute (array)
return pn_exit ('Invalid object passed to ObjectUtil::retrieveObjectAttributes ...');
return pn_exit ('Invalid type passed to ObjectUtil::retrieveObjectAttributes ...');
// ensure that only objects with a valid ID are used
$objattr_table = $pntables['objectdata_attributes'];
$objattr_column = $pntables['objectdata_attributes_column'];
* Expand the given object with it's attributes
* @param object The object whose attribute we wish to retrieve
* @param type The type of the given object
* @param idcolumn The column which holds the ID value (optional) (default='id')
* @return The object which has been altered in place
if (!isset ($obj[$idcolumn]) || !$obj[$idcolumn])
return pn_exit ("Unable to determine a valid ID in object [$type, $idcolumn] ...");
$obj['__ATTRIBUTES__'][$atr['attribute_name']] = $atr['value'];
* Store the attributes for the given objects.
* @param object The object whose attributes we wish to store
* @param type The type of the given object
* @param idcolumn The idcolumn of the object (optional) (default='id')
* @return true/false on success/failure
return pn_exit ('Invalid object passed to ObjectUtil::storeObjectAttributes ...');
return pn_exit ('Invalid type passed to ObjectUtil::storeObjectAttributes ...');
return pn_exit ('Invalid idcolumn passed to ObjectUtil::storeObjectAttributes ...');
if (!isset ($obj['__ATTRIBUTES__']) || !is_array($obj['__ATTRIBUTES__']))
$objattr_table = $pntables['objectdata_attributes'];
$objattr_column = $pntables['objectdata_attributes_column'];
$objID = $obj[$idcolumn];
return pn_exit ('storeObjectAttributes: Unable to determine object ID ... ');
// delete old attribute values for this object
$sql = "DELETE FROM $objattr_table WHERE $objattr_column[object_type] = '" . DataUtil::formatForStore($type) . "' AND
$atrs = (isset ($obj['__ATTRIBUTES__']) ? $obj['__ATTRIBUTES__'] : null);
// process all the attribute fields
foreach ($atrs as $k => $v)
$tobj['attribute_name'] = $k;
$tobj['object_id'] = $objID;
$tobj['object_type'] = $type;
* Delete the attributes for the given object.
* @param object The object whose attributes we wish to store
* @param type The type of the given object
* @param idcolumn The idcolumn of the object (optional) (default='id')
* @return the SQL result of the delete operation
return pn_exit ('Invalid object passed to ObjectUtil::deleteObjectAttributes ...');
return pn_exit ('Invalid type passed to ObjectUtil::deleteObjectAttributes ...');
return pn_exit ('Invalid idcolumn passed to ObjectUtil::deleteObjectAttributes ...');
$objattr_table = $pntables['objectdata_attributes'];
$objattr_column = $pntables['objectdata_attributes_column'];
// ensure module was successfully loaded
$objID = $obj[$idcolumn];
return pn_exit ('storeObjectAttributes: Unable to determine object ID ... ');
$sql = "DELETE FROM $objattr_table WHERE $objattr_column[object_type] = '" . DataUtil::formatForStore($type) . "' AND
* Delete the all attributes for the given tab
* @param type The type/tablename we wish to delete attributes for
* @return the SQL result of the delete operation
$objattr_table = $pntables['objectdata_attributes'];
$objattr_column = $pntables['objectdata_attributes_column'];
$sql = "DELETE FROM $objattr_table WHERE $objattr_column[object_type] = '" . DataUtil::formatForStore($type) . "'";
* Retrieve a list of attributes defined in the system
* @param sort The column to sort by (optional) (default='attribute_name')
* @return the system attributes field array
$objattr_table = $pntables['objectdata_attributes'];
$objattr_column = $pntables['objectdata_attributes_column'];
// ensure module was successfully loaded
* Retrieve the count for a given attribute name
* @param atrName The name of the attribute
* @return The count for the given attribute
$objattr_column = $pntables['objectdata_attributes_column'];
* Ensure that a meta-data object has reasonable default values
* @param obj The object we wish to store metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return Altered meta object (meta object is also altered in place)
if (!isset ($obj['__META__']) || !is_array($obj['__META__']))
$obj['__META__'] = array ();
$meta = & $obj['__META__'];
$meta['table'] = $tablename;
$meta['idcolumn'] = $idcolumn;
if (!isset ($meta['module']) || !$meta['module'])
if (!isset ($meta['obj_id']) || !$meta['obj_id'])
$meta['obj_id'] = (isset ($obj[$idcolumn]) ? $obj[$idcolumn] : - 1);
* Insert a meta data object
* @param obj The object we wish to store metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The result from the metadata insert operation
$obj['__META__']['metaid'] = $meta['id'];
* Update a meta data object
* @param obj The object we wish to store metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The result from the metadata insert operation
if (!isset ($obj['__META__']['id'])) {
$meta = $obj['__META__'];
if ($meta['obj_id'] > 0) {
* Delete a meta data object
* @param obj The object we wish to delete metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The result from the metadata insert operation
if (isset ($obj['__META__']['id']) && $obj['__META__']['id'])
if (isset ($obj['__META__']['idcolumn']) && $obj['__META__']['obj_id'])
$meta_column = $pntables['objectdata_meta_column'];
$meta = $obj['__META__'];
* Retrieve object meta data
* @param obj The object we wish to retrieve metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The object with the meta data filled in
$meta_column = $pntables['objectdata_meta_column'];
* Expand an object with it's Meta data
* @param obj The object we wish to get the metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The object with the meta data filled in. The object passed in is altered in place
if (!isset ($obj[$idcolumn]) || !$obj[$idcolumn])
return pn_exit ("Unable to determine a valid ID in object [$type, $idcolumn] ...");
$obj['__META__'] = $meta;
* Insert a categorization data object
* @param obj The object we wish to store categorization data for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The result from the category data insert operation
return pn_exit ('Invalid object passed to ObjectUtil::storeObjectCategories ...');
return pn_exit ('Invalid tablename passed to ObjectUtil::storeObjectCategories ...');
return pn_exit ('Invalid idcolumn passed to ObjectUtil::storeObjectCategories ...');
if (!isset ($obj['__CATEGORIES__']) || !is_array($obj['__CATEGORIES__']) || !$obj['__CATEGORIES__'])
// ensure that we don't store duplicate object mappings
foreach ($obj['__CATEGORIES__'] as $k=> $v)
unset ($obj['__CATEGORIES__'][$k]);
// Get the ids of the categories properties of the object
$modname = isset ($obj['__META__']['module']) ? $obj['__META__']['module'] : pnModGetName();
$cobj['table'] = $tablename;
$cobj['obj_idcolumn'] = $idcolumn;
foreach ($obj['__CATEGORIES__'] as $prop => $cat)
// if there's all the data and the Registry exists
// the category is mapped
if ($cat && $prop && isset ($reg_ids[$prop]))
$cobj['modname'] = $modname;
$cobj['obj_id'] = $obj[$idcolumn];
$cobj['category_id'] = $cat;
$cobj['reg_id'] = $reg_ids[$prop];
* Delete a meta data object
* @param obj The object we wish to delete categorization data for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='obj_id')
* @return The result from the metadata insert operation
* Retrieve object category data
* @param obj The object we wish to retrieve metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @return The object with the meta data filled in
$key = $tablename . '_' . $obj[$idcolumn];
if (isset ($cache[$key])) {
$cat = $pntabs ['categories_mapobj_column'];
$orderby = "ORDER BY tbl.$cat[category_id]";
$joinInfo[] = array('join_table' => 'categories_registry',
'join_field' => 'property',
'object_field_name' => 'property',
'compare_field_table' => 'reg_id',
'compare_field_join' => 'id');
* Retrieve object category data
* @param obj The object we wish to retrieve metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @param assocKey The field to use for the associative array index (optional) (default='id')
* @return The object with the meta data filled in
return pn_exit ("Unable to load array class [CategoryUtil] ...");
$where = "WHERE cat_id IN ($cats)";
foreach ($catlist as $prop => $cat) {
if (isset ($catsdata[$cat])) {
$result[$prop] = $catsdata[$cat];
* Expand an object array with it's category data
* @param objArray The object array we wish to get the category for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @param field The category field to return the object's category info (optional) (default='id')
* @return The object with the meta data filled in. The object passed in is altered in place
$tab = $pntabs ['categories_mapobj'];
$col = $pntabs ['categories_mapobj_column'];
foreach ($objArray as $obj)
$w2[] = "tbl.$col[obj_id] IN (" . $t . ')';
$where = "WHERE " . implode (' AND ', $w2);
$sort = "ORDER BY tbl.$col[obj_id], tbl.$col[category_id]";
$joinInfo[] = array('join_table' => 'categories_registry',
'join_field' => 'property',
'object_field_name' => 'property',
'compare_field_table' => 'reg_id',
'compare_field_join' => 'id');
// since we don't know the order in which our data array will be, we
// have to do this iteratively. However, this is still a lot faster
// than doing a select for every data line.
foreach ($objArray as $k => $obj)
if ($map['obj_id'] == $obj[$idcolumn])
$prop = $map['property'];
$catid = $map['category_id'];
$objArray[$k]['__CATEGORIES__'][$prop] = $catid;
if ($last && $last != $map['obj_id'])
// now retrieve the full category data
$where = 'WHERE cat_id IN ('. implode(',',$catlist) . ')';
//$cats = DBUtil::selectObjectArray ('categories_category', $where, '', -1, -1, 'id');
return pn_exit ("Unable to load array class [category] ...");
$catArray = new $catClass();
$data = $catArray->get ($where, '', - 1, - 1, 'id');
// use the cagtegory map created previously to build the object category array
foreach ($objArray as $k => $obj)
foreach ($obj['__CATEGORIES__'] as $prop => $cat)
$objArray[$k]['__CATEGORIES__'][$prop] = $data[$cat];
// now generate the relative paths
//$rootCatID = CategoryRegistryUtil::getRegisteredModuleCategory (pnModGetName(), $tablename, 'main_table', '/__SYSTEM__/Modules/Quotes/Default');
//postProcessExpandedObjectArrayCategories ($objArray, $rootCatID, false);
* Expand an object with it's category data
* @param obj The object we wish to get the metadata for
* @param tablename The object's tablename
* @param idcolumn The object's idcolumn (optional) (default='id')
* @param field The category field to return the object's category info (optional) (default='id')
* @param assocKey The field to use for the associative array index (optional) (default='id')
* @return The object with the meta data filled in. The object passed in is altered in place
if (!isset ($obj[$idcolumn]) || !$obj[$idcolumn])
return pn_exit ("Unable to determine a valid ID in object [$type, $idcolumn] ...");
$obj['__CATEGORIES__'] = $cats;
// now generate the relative paths
//$module = pnModGetName();
//$rootCatID = CategoryRegistryUtil::getRegisteredModuleCategory (pnModGetName(), $tablename, 'main_table', '/__SYSTEM__/Modules/Quotes/Default');
//postProcessExpandedObjectCategories ($obj, $rootCatID);
* Post-process an object-array's expanded categories to generate relative paths
* @param objArray The object array we wish to post-process
* @param rootCatID The root category ID for the relative path creation
* @param includeRoot whether or not to include the root folder in the relative path (optional) (default=false)
* @return The object-array with the additionally expanded category data is altered in place and returned
return pn_exit ("Invalid object in postProcessExpandedObjectArrayCategories ...");
if (isset ($objArray[$k]['__CATEGORIES__']) && $objArray[$k]['__CATEGORIES__']) {
* Post-process an object's expanded category data to generate relative paths
* @param obj The object we wish to post-process
* @param rootCat The root category ID for the relative path creation
* @param includeRoot whether or not to include the root folder in the relative path (optional) (default=false)
* @return The object with the additionally expanded category data is altered in place and returned
return pn_exit ("Invalid object in postProcessExpandedObjectCategories ...");
return pn_exit ("Unable to load array class [CategoryUtil] ...");
// if the function was called to process the object categories
if (isset ($obj['__CATEGORIES__'])) {
// else, if the function was called to process the categories array directly
|