diff options
Diffstat (limited to 'includes/classes/Pigeonholes.php')
| -rw-r--r-- | includes/classes/Pigeonholes.php | 1314 |
1 files changed, 1314 insertions, 0 deletions
diff --git a/includes/classes/Pigeonholes.php b/includes/classes/Pigeonholes.php new file mode 100644 index 0000000..558fca9 --- /dev/null +++ b/includes/classes/Pigeonholes.php @@ -0,0 +1,1314 @@ +<?php +/** + * @version $Header$ + * + * +----------------------------------------------------------------------+ + * | Copyright ( c ) 2004, bitweaver.org + * +----------------------------------------------------------------------+ + * | All Rights Reserved. See below for details and a complete list of authors. + * | Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details + * | + * | For comments, please use phpdocu.sourceforge.net documentation standards!!! + * | -> see http://phpdocu.sourceforge.net/ + * +----------------------------------------------------------------------+ + * | Authors: xing <xing@synapse.plus.com> + * +----------------------------------------------------------------------+ + * + * Pigeonholes class + * + * @author xing <xing@synapse.plus.com> + * @version $Revision$ + * @package pigeonholes + */ + +/** + * required setup + */ +require_once( LIBERTY_PKG_CLASS_PATH.'LibertyMime.php' ); +require_once( LIBERTY_PKG_CLASS_PATH.'LibertyStructure.php' ); + +/** + * Pigeonholes + * + * @package pigeonholes + */ +class Pigeonholes extends LibertyMime { + /** + * initiate class + * @param $pContentId content id of the pigeonhole - use either one of the ids. + * @param $pStructureId structure id of the pigeonhole - use either one of the ids. + * @param $pMembersList hash with optional values to tweak the getMemberList loading sql. Used keys are Order, Select, Join and Where. + * @return none + * @access public + **/ + function Pigeonholes( $pStructureId=NULL, $pContentId=NULL, $pMemberList=Null ) { + parent::__construct(); + $this->registerContentType( PIGEONHOLES_CONTENT_TYPE_GUID, array( + 'content_type_guid' => PIGEONHOLES_CONTENT_TYPE_GUID, + 'content_name' => 'Pigeonhole', + 'handler_class' => 'Pigeonholes', + 'handler_package' => 'pigeonholes', + 'handler_file' => 'Pigeonholes.php', + 'maintainer_url' => 'http://www.bitweaver.org' + ) ); + $this->mContentId = $pContentId; + $this->mStructureId = $pStructureId; + $this->mContentTypeGuid = PIGEONHOLES_CONTENT_TYPE_GUID; + + // Permission setup + $this->mViewContentPerm = 'p_pigeonholes_view'; + $this->mUpdateContentPerm = 'p_pigeonholes_update'; + $this->mAdminContentPerm = 'p_pigeonholes_update'; // use edit until we find the need for an admin permission + + // Allow specially constructed pigeonholes to mess with the + // getMemberList SQL so that additional data can be added on. + // This can be used in packages which want a special view on + // a category. + $this->mMemberList = $pMemberList; + } + + /** + * load the pigeonhole + * @param $pExtras boolean - if set to true, pigeonhole content is added as well + * @return bool TRUE on success, FALSE if it's not valid + * @access public + **/ + function load( $pExtras=FALSE, $pLoadAttachable=TRUE ) { + if( @BitBase::verifyId( $this->mContentId ) || @BitBase::verifyId( $this->mStructureId ) ) { + global $gBitSystem; + $lookupColumn = ( @BitBase::verifyId( $this->mContentId ) ? 'lc.`content_id`' : 'ls.`structure_id`' ); + $lookupId = ( @BitBase::verifyId( $this->mContentId ) ? $this->mContentId : $this->mStructureId ); + $query = "SELECT pig.*, ls.`root_structure_id`, ls.`parent_id`, lc.`title`, lc.`data`, + lc.`user_id`, lc.`content_type_guid`, lc.`format_guid`, + uue.`login` AS modifier_user, uue.`real_name` AS modifier_real_name, + uuc.`login` AS creator_user, uuc.`real_name` AS creator_real_name + FROM `".BIT_DB_PREFIX."pigeonholes` pig + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = pig.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."liberty_structures` ls ON ( ls.`structure_id` = pig.`structure_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON ( uue.`user_id` = lc.`modifier_user_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON ( uuc.`user_id` = lc.`user_id` ) + WHERE $lookupColumn=?"; + $result = $this->mDb->query( $query, array( $lookupId ) ); + + if( $result && $row = $result->fetchRow() ) { + $this->mInfo = $row; + $this->mContentId = $row['content_id']; + $this->mStructureId = $row['structure_id']; + $this->mInfo['user'] = $row['creator_user']; + $this->mInfo['real_name'] = ( isset( $row['creator_real_name'] ) ? $row['creator_real_name'] : $row['creator_user'] ); + $this->mInfo['display_name'] = BitUser::getTitleFromHash( $this->mInfo ); + $this->mInfo['editor'] = ( isset( $row['modifier_real_name'] ) ? $row['modifier_real_name'] : $row['modifier_user'] ); + $this->mInfo['display_link'] = $this->getDisplayLink(); + $this->mInfo['display_url'] = $this->getDisplayUrl(); + $this->parseData(); + } + + if( $pLoadAttachable ) { + LibertyMime::load(); + } + + // if the content for the pigeonhole is requested, get it + if( $pExtras ) { + $this->mInfo['path'] = $this->getPigeonholePath(); + $this->mInfo['display_path'] = $this->getDisplayPath( $this->mInfo['path'] ); + $memberHash = array( 'max_records' => -1 ); + $this->mInfo['members'] = $this->getMemberList( $memberHash ); + $this->mInfo['members_count'] = count( $this->mInfo['members'] ); + } + } + return( count( $this->mInfo ) ); + } + + /** + * get all content inserted in a given pigeonhole. if no id is given, it gets all content for all pigeonholes + * @param $pContentId content id of the pigeonhole + * @return array of pigeonhole members with according title and content type guid + * @access public + **/ + function getMemberList( &$pListHash ) { + global $gBitUser, $gLibertySystem, $gBitSystem; + $ret = FALSE; + LibertyContent::prepGetList( $pListHash ); + + $select = $where = $join = ''; + $bindVars = array(); + if( @BitBase::verifyId( $this->mContentId ) || @BitBase::verifyId( $pListHash['content_id'] ) ) { + $where = " WHERE pig.`content_id` = ? "; + $bindVars[] = @BitBase::verifyId( $pListHash['content_id'] ) ? $pListHash['content_id'] : $this->mContentId; + } + + if( !empty( $pListHash['content_type_guid'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " lc.content_type_guid = ? "; + $bindVars[] = $pListHash['content_type_guid']; + } + + if( !empty( $pListHash['title'] ) && is_string( $pListHash['title'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " pig.`content_id` = lc2.`content_id` AND UPPER( lc2.`title` ) = ?"; + $join .= ", `".BIT_DB_PREFIX."liberty_content` lc2"; + $bindVars[] = strtoupper( $pListHash['title'] ); + } + + // Do we have any special tweaks for the list? + if( !empty( $this->mMemberList['Order'] ) ) { + $order = "ORDER BY ".$this->mMemberList['Order']; + } else { + $order = "ORDER BY lc.`content_type_guid`, lc.`title` ASC"; + } + + if( !empty( $this->mMemberList['Select'] ) ) { + $select .= $this->mMemberList['Select']; + } + + if( !empty( $this->mMemberList['Join'] ) ) { + $join .= $this->mMemberList['Join']; + } + + if( !empty( $this->mMemberList['Where'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= $this->mMemberList['Where']; + } + + + $ret = array(); + $query = " + SELECT pigm.*, + lc.`content_id`, lc.`last_modified`, lc.`user_id`, lc.`title`, lc.`content_type_guid`, lc.`created`, + lct.`content_name`, lcds.`data` AS `summary`, + uu.`login`, uu.`real_name` $select + FROM `".BIT_DB_PREFIX."pigeonhole_members` pigm + INNER JOIN `".BIT_DB_PREFIX."pigeonholes` pig ON ( pig.`content_id` = pigm.`parent_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = pigm.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` lct ON ( lc.`content_type_guid` = lct.`content_type_guid` ) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON ( uu.`user_id` = lc.`user_id` ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content_data` lcds ON ( lcds.`content_id` = lc.`content_id` AND lcds.`data_type` = 'summary' ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_attachments` latt ON ( latt.`content_id` = lc.`content_id` AND latt.`is_primary` = 'y' ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_files` lf ON ( lf.`file_id` = latt.`foreign_id` ) + $join $where $order"; + $result = $this->mDb->query( $query, $bindVars, @BitBase::verifyId( $pListHash['max_records'] ) ? $pListHash['max_records'] : NULL, @BitBase::verifyId( $pListHash['offset'] ) ? $pListHash['offset'] : NULL ); + $contentTypes = $gLibertySystem->mContentTypes; + while( $aux = $result->fetchRow() ) { + if( !empty( $contentTypes[$aux['content_type_guid']] ) ) { + $type = &$contentTypes[$aux['content_type_guid']]; + if( empty( $type['content_object'] ) ) { + // crate *one* object for each object *type* to call virtual methods. + if( $typeClass = $gLibertySystem->getContentClassName( $type['content_type_guid'] ) ) { + if( $type['content_object'] = new $typeClass() ) { + if( $type['content_object']->isViewable( $aux['content_id'] )) { + $aux['display_url'] = $type['content_object']->getDisplayUrlFromHash( $aux ); + $aux['display_link'] = $type['content_object']->getDisplayLink( $aux ); + $aux['title'] = $type['content_object']->getTitleFromHash( $aux ); + // needs updating to bw3 $aux['thumbnail_url'] = liberty_fetch_thumbnails( array()); + $ret[] = $aux; + } + } + } + } + } + } + + $query_cant = " + SELECT count(*) + FROM `".BIT_DB_PREFIX."pigeonhole_members` pigm + INNER JOIN `".BIT_DB_PREFIX."pigeonholes` pig ON ( pig.`content_id` = pigm.`parent_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = pigm.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` lct ON ( lc.`content_type_guid` = lct.`content_type_guid` ) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON ( uu.`user_id` = lc.`user_id` ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content_data` lcds ON ( lcds.`content_id` = lc.`content_id` AND lcds.`data_type`='summary' ) + $join $where"; + $pListHash['cant'] = $this->mDb->getOne( $query_cant, $bindVars ); + + LibertyContent::postGetList($pListHash); + + return( !empty( $this->mErrors ) ? $this->mErrors : $ret ); + } + + /** + * get all items that are not part of a pigeonhole yet + * @return array of content not in any pigeonhole yet + * @access public + **/ + function getAssignableContent( &$pListHash ) { + global $gBitUser, $gLibertySystem, $gBitSystem; + + $where = ''; + $bindVars = array(); + LibertyContent::prepGetList( $pListHash ); + + if( empty( $pListHash['include_members'] ) ) { + $where .= "WHERE pigm.`content_id` IS NULL"; + } + + if( !empty( $pListHash['find'] ) && is_string( $pListHash['find'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " UPPER( lc.`title` ) LIKE ?"; + $bindVars[] = ( '%'.strtoupper( $pListHash['find'] ).'%'); + } + + if( !empty( $pListHash['content_type'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " lc.`content_type_guid`=?"; + $bindVars[] = $pListHash['content_type']; + } + + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " lc.`content_type_guid` != ? "; + $bindVars[] = PIGEONHOLES_CONTENT_TYPE_GUID; + + if( !empty( $pListHash['sort_mode'] ) ) { + $order = " ORDER BY ".$this->mDb->convertSortmode( $pListHash['sort_mode'] )." "; + } else { + $order = " ORDER BY lc.`content_type_guid`, lc.`title` ASC"; + } + + $query = "SELECT pigm.`parent_id`, lc.`content_id`, lc.`user_id`, lc.`title`, lc.`content_type_guid`, uu.`login`, uu.`real_name` + FROM `".BIT_DB_PREFIX."liberty_content` lc + LEFT JOIN `".BIT_DB_PREFIX."pigeonhole_members` pigm ON ( pigm.`content_id` = lc.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uu ON ( uu.`user_id` = lc.`user_id` ) + $where $order"; + $result = $this->mDb->query( $query, $bindVars, @BitBase::verifyId( $pListHash['max_records'] ) ? $pListHash['max_records'] : NULL , $pListHash['offset']); + + $query = "SELECT COUNT(lc.`content_id`) + FROM `".BIT_DB_PREFIX."liberty_content` lc + LEFT JOIN `".BIT_DB_PREFIX."pigeonhole_members` pigm ON ( pigm.`content_id` = lc.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uu ON ( uu.`user_id` = lc.`user_id` ) + $where"; + $pListHash['cant'] = $this->mDb->getOne( $query, $bindVars); + + $contentTypes = $gLibertySystem->mContentTypes; + while( $row = $result->fetchRow() ) { + $i = $row['content_id']; + $ret[$i] = $row; + if( !empty( $contentTypes[$row['content_type_guid']] ) ) { + $type = &$contentTypes[$row['content_type_guid']]; + if( empty( $type['content_object'] ) ) { + // create *one* object for each object *type* to call virtual methods. + include_once( $gBitSystem->mPackages[$type['handler_package']]['path'].$type['handler_file'] ); + $type['content_object'] = new $type['handler_class'](); + } + $ret[$i]['display_link'] = $type['content_object']->getDisplayLink( $row['title'], $row ); + $ret[$i]['title'] = $type['content_object']->getTitleFromHash( $row ); + } + + // generate a map of what items are assigned to what pigeonholes + if( !empty( $pListHash['include_members'] ) && @BitBase::verifyId( $row['parent_id'] ) ) { + $map[$i][] = $row['parent_id']; + } + } + + // complete the output + if( !empty( $pListHash['include_members'] ) && !empty( $ret ) ) { + foreach( $ret as $i => $r ) { + $ret[$i]['assigned'] = !empty( $map[$i] ) ? $map[$i] : NULL; + } + } + + LibertyContent::postGetList( $pListHash ); + return( !empty( $ret ) ? $ret : NULL ); + } + + /** + * get an array of paths for all pigeonholes. used for pages where data can be inserted into pigeonholes + * + * @param numeric $pContentId content id of pigeonhole. + * @param numeric $pTruncate Setting this to a number will do some smart truncations depending on how many parents there are + * setting it to 60 will allow 30 chars for all parents combined and 30 for the actual title + * @access public + * @return TRUE on success, FALSE if there is no pigeonhole + * @TODO We need to sort the returned values that successive pigoenholes are grouped together. + */ + function getPigeonholesPathList( $pContentId=NULL, $pTruncate = FALSE, $pShowAll = FALSE ) { + global $gBitSystem; + $where = $join = ''; + + if( $gBitSystem->isFeatureActive( 'pigeonholes_allow_forbid_insertion' ) && !$pShowAll ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= ' lcp.`pref_value` IS NULL OR lcp.`pref_value` != \'on\' '; + $join .= ' LEFT JOIN `'.BIT_DB_PREFIX.'liberty_content_prefs` lcp ON (pig.`content_id` = lcp.`content_id` AND lcp.`pref_name` = \'no_insert\') '; + } + + $query = "SELECT pig.`content_id`, pig.`structure_id` + FROM `".BIT_DB_PREFIX."pigeonholes` pig + INNER JOIN `".BIT_DB_PREFIX."liberty_structures` ls ON ( ls.`structure_id` = pig.`structure_id` ) + $join + $where + ORDER BY ls.`root_structure_id`, ls.`structure_id` ASC"; + $result = $this->mDb->query( $query ); + $pigeonholes = $result->getRows(); + foreach( $pigeonholes as $pigeonhole ) { + $ret[$pigeonhole['content_id']] = $this->getPigeonholePath( $pigeonhole['structure_id'] ); + } + + if( !empty( $ret ) ) { + if( $pTruncate ) { + foreach( $ret as $cid => $path ) { + // count here to minimise speed loss + $count = count( $path ); + foreach( $path as $pos => $pig ) { + // calculate limit at which category is truncated + if( $count == 1 ) { + $limit = $pTruncate; + } elseif( $pos == $count - 1 ) { + $limit = ceil( $pTruncate / 2 ); + } else { + $limit = ceil( $pTruncate / 2 / $count ); + } + $ret[$cid][$pos]['title'] = substr( $pig['title'], 0, $limit ).( ( strlen( $pig['title'] ) <= $limit ) ? '' : '...' ); + } + } + } + + // sort the pathlist to make the display nicer + uasort( $ret, 'pigeonholes_pathlist_sorter' ); + + if( @BitBase::verifyId( $pContentId ) && $assigned = $this->getPigeonholesFromContentId( $pContentId ) ) { + foreach( $assigned as $a ) { + $ret[$a['content_id']][0]['selected'] = TRUE; + } + } + } + + return( !empty( $ret ) ? $ret : array() ); + } + + /** + * get all pigeonholes where the contenent has been inserted + * @param $pContentId content id of item in question + * @return basic information about item requested + * @access public + **/ + function getPigeonholesFromContentId( $pContentId ) { + if( @BitBase::verifyId( $pContentId ) ) { + $query = "SELECT ls.* + FROM `".BIT_DB_PREFIX."pigeonhole_members` pigm + INNER JOIN `".BIT_DB_PREFIX."pigeonholes` pig ON ( pig.`content_id` = pigm.`parent_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_structures` ls ON ( pig.`structure_id` = ls.`structure_id` ) + WHERE pigm.`content_id`=?"; + $ret = $this->mDb->getAll( $query, array( $pContentId ) ); + } + return( !empty( $ret ) ? $ret : FALSE ); + } + + /** + * get the path of a pigeonhole + * @param $pStructureId structure id of pigeonhole, if no id is given, it gets the id from $this->mStructureId + * @return path in form of an array + * @access public + **/ + function getPigeonholePath( $pStructureId=NULL ) { + if( !@BitBase::verifyId( $pStructureId ) ) { + $pStructureId = $this->mStructureId; + } + + if( @BitBase::verifyId( $pStructureId ) ) { + global $gStructure; + // create new object if needed + if( empty( $gStructure ) ) { + $gStructure = new LibertyStructure(); + } + // get the structure path + $ret = $gStructure->getPath( $pStructureId ); + } + return( !empty( $ret ) ? $ret : FALSE ); + } + + /** + * Converts a structure path into valid html links + * @param $pPath path given by getPigeonholePath() + * @return the link to display the page. + */ + function getDisplayPath( $pPath ) { + global $gBitSystem; + $ret = ''; + if( !empty( $pPath ) && is_array( $pPath ) ) { + foreach( $pPath as $node ) { + $title = htmlspecialchars( $node['title'] ); + $ret .= ( @BitBase::verifyId( $node['parent_id'] ) ? ' » ' : '' ).'<a title="'.$title.'" href="'.$this->getDisplayUrlFromHash( $node ).'">'.preg_replace('/ /',' ',$title).'</a>'; + } + } + + return $ret; + } + + /** + * get list of all pigeonholes + * @param $pListHash contains array of items used to limit search results + * @param $pListHash[sort_mode] column and orientation by which search results are sorted + * @param $pListHash[find] search for a pigeonhole title - case insensitive + * @param $pListHash[max_records] maximum number of rows to return + * @param $pListHash[offset] number of results data is offset by + * @param $pListHash[title] pigeonhole name + * @param $pListHash[parent_id] pigeonhole parent_id, optional + * @param $pListHash[root_structure_id] only load the pigoenhole this root_structure_id is part of + * @param $pListHash[load_only_root] only load top most items + * @param $pListHash[parent_content_id] all the sons of the pigeonhole parent content_id , optional + * @param $pListHash[load_also_root] if parent_content_id is set load also the father, optionnal + * @return array of pigeonholes in 'data' and count of pigeonholes in 'cant' + * @access public + **/ + function getList( &$pListHash ) { + global $gBitSystem, $gBitUser, $gBitDbType; + LibertyContent::prepGetList( $pListHash ); + + $ret = $bindVars = array(); + $where = $order = $join = $select = ''; + + if( @BitBase::verifyId( $pListHash['root_structure_id'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " ls.`root_structure_id`=? "; + $bindVars[] = $pListHash['root_structure_id']; + } + + if( !empty( $pListHash['load_only_root'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " ls.`structure_id`=ls.`root_structure_id` "; + } + + if( !empty( $pListHash['find'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " UPPER( lc.`title` ) LIKE ? "; + $bindVars[] = '%'.strtoupper( $pListHash['find'] ).'%'; + } + + if( !empty( $pListHash['title'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= ' lc.`title` = ?'; + $bindVars[] = $pListHash['title']; + } + + if( $gBitSystem->isFeatureActive( 'pigeonholes_allow_forbid_insertion' ) && !empty( $pListHash['insertable'] )) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= ' lcp.`pref_value` IS NULL OR lcp.`pref_value` != \'on\' '; + $join .= ' LEFT JOIN `'.BIT_DB_PREFIX.'liberty_content_prefs` lcp ON (lc.`content_id` = lcp.`content_id` AND lcp.`pref_name` = \'no_insert\') '; + $select .= ' , lcp.`pref_value` AS no_insert '; + } + + if( isset( $pListHash['parent_id'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= ' ls.`parent_id` = ? '; + $bindVars[] = $pListHash['parent_id']; + } + + if( !empty( $pListHash['parent_content_id'] ) ) { + $join .= 'INNER JOIN `'.BIT_DB_PREFIX.'liberty_structures` lsf ON (ls.`parent_id` = lsf.`structure_id`'; + if ( !empty( $pListHash['load_also_root'] ) ) { + $join .= ' OR ls.`structure_id`= lsf.`structure_id`'; + } + $join .= ')'; + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= ' lsf.`content_id` = ? '; + $bindVars[] = $pListHash['parent_content_id']; + } + + if( !empty( $pListHash['sort_mode'] ) ) { + $order .= " ORDER BY ".$this->mDb->convertSortmode( $pListHash['sort_mode'] )." "; + } else { + // default sort mode makes list look nice + $order .= " ORDER BY ls.`root_structure_id`, ls.`structure_id` ASC"; + } + + // only use subselect for old crappy mysql + if( $gBitDbType != 'mysql' ) { + $subselect = ", ( + SELECT COUNT( pm.`content_id` ) + FROM `".BIT_DB_PREFIX."pigeonhole_members` pm + WHERE pm.`parent_id`=pig.`content_id` + ) AS members_count"; + } else { + $subselect = ""; + } + + $query = "SELECT pig.*, ls.`root_structure_id`, ls.`parent_id`, lc.`title`, lc.`data`, lc.`user_id`, lc.`content_type_guid`, lc.`format_guid`, + uue.`login` AS modifier_user, uue.`real_name` AS modifier_real_name, + uuc.`login` AS creator_user, uuc.`real_name` AS creator_real_name $select $subselect + FROM `".BIT_DB_PREFIX."pigeonholes` pig + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = pig.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON ( uue.`user_id` = lc.`modifier_user_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON ( uuc.`user_id` = lc.`user_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_structures` ls ON ( ls.`structure_id` = pig.`structure_id` ) + $join $where $order"; + + $result = $this->mDb->query( $query, $bindVars, $pListHash['max_records'], $pListHash['offset'] ); + + while( $aux = $result->fetchRow() ) { + //$content_ids[] = $aux['content_id']; + $aux['user'] = $aux['creator_user']; + $aux['real_name'] = ( isset( $aux['creator_real_name'] ) ? $aux['creator_real_name'] : $aux['creator_user'] ); + $aux['display_name'] = BitUser::getDisplayNameFromHash( FALSE, $aux ); + $aux['editor'] = ( isset( $aux['modifier_real_name'] ) ? $aux['modifier_real_name'] : $aux['modifier_user'] ); + $aux['display_link'] = Pigeonholes::getDisplayLink( $aux['title'], $aux ); + // get member count for mysql - haha + if( $gBitDbType == 'mysql' ) { + $aux['members_count'] = $this->mDb->getOne( "SELECT COUNT( pm.`content_id` ) FROM `".BIT_DB_PREFIX."pigeonhole_members` pm WHERE pm.`parent_id`=?", array( $aux['content_id'] )); + } + + if( !empty( $pListHash['parse_data'] ) && !empty( $aux['data'] )) { + $aux['parsed_data'] = $this->parseData( $aux['data'], $aux['format_guid'] ); + } + + if( !empty( $pListHash['force_extras'] ) || ( !empty( $pListHash['load_extras'] ) && $aux['structure_id'] == @$pListHash['structure_id'] ) ) { + $aux['path'] = $this->getPigeonholePath( $aux['structure_id'] ); + $aux['display_path'] = Pigeonholes::getDisplayPath( $aux['path'] ); + // Move all the members data into the right place + $memberListHash = array ( + 'content_id' => $aux['content_id'], + 'content_type_guid' => !empty( $pListHash['content_type_guid'] ) ? $pListHash['content_type_guid'] : NULL, + 'max_records' => !empty( $pListHash['members_max_records'] ) ? $pListHash['members_max_records'] : NULL, + 'list_page' => !empty( $pListHash['members_list_page'] ) ? $pListHash['members_list_page'] : NULL, + 'sort_mode' => !empty( $pListHash['members_sort_mode'] ) ? $pListHash['members_sort_mode'] : NULL, + 'find' => !empty( $pListHash['members_find'] ) ? $pListHash['members_find'] : NULL, + ); + $aux['members'] = $this->getMemberList( $memberListHash ); + $aux['listInfo'] = $memberListHash['listInfo']; + + //$aux['members_count'] = count( $aux['members'] ); + if( $gBitSystem->getConfig( 'pigeonholes_list_style' ) == 'table' ) { + $this->alphabetiseMembers( $aux['members'] ); + } + } + + $ret[$aux['structure_id']] = $aux; + } + + $query = "SELECT COUNT( lc.`title` ) + FROM `".BIT_DB_PREFIX."pigeonholes` pig + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON ( lc.`content_id` = pig.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON ( uue.`user_id` = lc.`modifier_user_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON ( uuc.`user_id` = lc.`user_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_structures` ls ON ( ls.`structure_id` = pig.`structure_id` ) + $join $where"; + $pListHash['cant'] = $this->mDb->getOne( $query, $bindVars ); + + LibertyContent::postGetList( $pListHash ); + return $ret; + } + + /** + * Check permissions of all nodes that lead to this + * @return a nicely grouped set of pigeonhole members in a set of columns and starting letters. + * @access public + **/ + function checkPathPermissions( $pPath ) { + global $gBitUser, $gBitSystem; + if( !empty( $pPath ) && is_array( $pPath )) { + foreach( $pPath as $path ) { + $contentIds[] = $path['content_id']; + } + if( !empty( $contentIds ) ) { + $query = "SELECT `pref_name`, `pref_value` FROM `".BIT_DB_PREFIX."liberty_content_prefs` WHERE `content_id` IN( ".preg_replace( "/,$/", "", str_repeat( "?,", count( $contentIds ) ) )." ) "; + $result = $this->mDb->query( $query, $contentIds ); + while( $aux = $result->fetchRow() ) { + ${$aux['pref_name']} = $aux['pref_value']; + if( ( !empty( $group_id ) && !$gBitUser->isInGroup( $group_id ) ) || ( !empty( $permission ) && !$gBitUser->hasPermission( $permission ) ) ) { + return FALSE; + } + } + } + } + return TRUE; + } + + /** + * Alphabetise all member items + * @return a nicely grouped set of pigeonhole members in a set of columns and starting letters. + * @access public + **/ + function alphabetiseMembers( &$pMememberHash ) { + global $gBitSystem; + if( !empty( $pMememberHash ) ) { + usort( $pMememberHash, "pigeonholes_alphabetiser" ); + $per_column = ceil( count( $pMememberHash ) / $gBitSystem->getConfig( 'pigeonholes_display_columns', 3 ) ); + $i = 1; + $j = 1; + foreach( $pMememberHash as $member ) { + $column = ( $i++ % $per_column == 0 ) ? $j++ : $j; + $index = strtoupper( substr( $member['title'], 0, 1 ) ); + // check if the previous column was using the same letter as we want to use in the new column + if( !empty( $ret[$column - 1][$index] ) || !empty( $ret[$column - 1]["…".$index] ) ) { + $index = "…".$index; + } + $ret[$column][$index][] = $member; + } + $pMememberHash = $ret; + unset( $ret ); + } + } + + /** + * Store pigeonhole data + * @param $pParamHash contains all data to store the pigeonholes + * @param $pParamHash[title] title of the new pigeonhole + * @param $pParamHash[edit] description of the pigeonhole + * @param $pParamHash[members] array of content_ids that are associated with this pigeonhole + * @param $pParamHash[root_structure_id] if this is set, it will add the pigeonhole to this structure. if it's not set, a new structure / top level pigeonhole is created + * @param $pParamHash[parent_id] set the structure_id that will server as the parent in the structure + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function store( &$pParamHash ) { + $this->mDb->StartTrans(); + if( $this->verify( $pParamHash ) && LibertyMime::store( $pParamHash ) ) { + $table = BIT_DB_PREFIX."pigeonholes"; + + // this really confusing, strange order way of saving items is due to strange behaviour of GenID + // probably has to do with not null default nextval('public.liberty_structures_id_seq'::text) + if( !empty( $pParamHash['update'] ) ) { + if( !empty( $pParamHash['pigeonhole_store'] ) ) { + $result = $this->mDb->associateUpdate( $table, $pParamHash['pigeonhole_store'], array("content_id" => $this->mContentId ) ); + } + $pParamHash['structure_location_id'] = $this->mStructureId; + } else { + // update the pigeonhole_store and structure_store content_id with the one from LibertyMime::store() + $pParamHash['structure_store']['content_id'] = $pParamHash['content_id']; + $pParamHash['pigeonhole_store']['content_id'] = $pParamHash['content_id']; + + // we need to store the new structure node now + global $gStructure; + // create new object if needed + if( empty( $gStructure ) ) { + $gStructure = new LibertyStructure(); + } + $pParamHash['structure_location_id'] = $gStructure->storeNode( $pParamHash['structure_store'] ); + + // get the corrent structure_id + // structure_id has to be done like this since it's screwed up in the schema + $pParamHash['pigeonhole_store']['structure_id'] = $this->mDb->getOne( "SELECT MAX( `structure_id` ) FROM `".BIT_DB_PREFIX."liberty_structures`" ); + $result = $this->mDb->associateInsert( $table, $pParamHash['pigeonhole_store'] ); + } + + // store content items + if( !empty( $pParamHash['pigeonhole_members_store'] ) ) { + // remove items first + $this->expungePigeonholeMember( array( 'parent_id' => $this->mContentId ) ); + if( !$this->insertPigeonholeMember( $pParamHash['pigeonhole_members_store'] ) ) { + $this->mErrors['store'] = 'The content could not be inserted into the respective categories.'; + } + } + + $this->mDb->CompleteTrans(); + $this->load(); + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * verify, clean up and prepare data to be stored + * @param $pParamHash all information that is being stored. will update $pParamHash by reference with fixed array of itmes + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access private + **/ + function verify( &$pParamHash ) { + // make sure we're all loaded up if everything is valid + if( $this->isValid() && empty( $this->mInfo ) ) { + $this->load( TRUE ); + } + + // It is possible a derived class set this to something different + if( empty( $pParamHash['content_type_guid'] ) ) { + $pParamHash['content_type_guid'] = $this->mContentTypeGuid; + } + + if( @BitBase::verifyId( $this->mContentId ) ) { + $pParamHash['content_id'] = $this->mContentId; + $pParamHash['update'] = TRUE; + } + + // content store + // check for name issues, first truncate length if too long + if( !empty( $pParamHash['title'] ) ) { + if( !@BitBase::verifyId( $this->mContentId ) ) { + if( empty( $pParamHash['title'] ) ) { + $this->mErrors['title'] = 'You must enter a name for this category.'; + } else { + $pParamHash['content_store']['title'] = substr( $pParamHash['title'], 0, 160 ); + } + } else { + $pParamHash['content_store']['title'] = ( isset( $pParamHash['title'] ) ) ? substr( $pParamHash['title'], 0, 160 ) : $this->mInfo['title']; + } + } elseif( empty( $pParamHash['title'] ) ) { + // no name specified + $this->mErrors['title'] = 'You must enter a name for this category.'; + } + + // sort out the description + if( $this->isValid() && !empty( $this->mInfo['data'] ) && empty( $pParamHash['edit'] ) ) { + $pParamHash['edit'] = ''; + } elseif( empty( $pParamHash['edit'] ) ) { + unset( $pParamHash['edit'] ); + } + + // pigeonhole member store + // work out what to do with the content of the pigeonhole + if( $this->isValid() && !empty( $this->mInfo['members'] ) && empty( $pParamHash['members'] ) ) { + $pParamHash['pigeonhole_members_store']['members'] = ''; + } elseif( empty( $pParamHash['members'] ) ) { + unset( $pParamHash['members'] ); + } else { + $i = 1; + foreach( $pParamHash['members'] as $c_id ) { + $pParamHash['pigeonhole_members_store'][$i]['content_id'] = $c_id; + $i++; + } + } + + // individual pigeonhole preference store + global $gBitSystem; + if( $gBitSystem->isFeatureActive('pigeonholes_allow_forbid_insertion') && empty( $pParamHash['prefs']['no_insert'] ) ) { + $pParamHash['prefs']['no_insert'] = '0'; + } + $pParamHash['preferences_store'] = !empty( $pParamHash['prefs'] ) ? $pParamHash['prefs'] : NULL; + + // structure store + if( @BitBase::verifyId( $pParamHash['root_structure_id'] ) ) { + $pParamHash['structure_store']['root_structure_id'] = $pParamHash['root_structure_id']; + } else { + $pParamHash['structure_store']['root_structure_id'] = NULL; + } + + if( @BitBase::verifyId( $pParamHash['parent_id'] ) ) { + $pParamHash['structure_store']['parent_id'] = $pParamHash['parent_id']; + } else { + $pParamHash['structure_store']['parent_id'] = NULL; + } + + return( count( $this->mErrors ) == 0 ); + } + + /** + * Store pigeonhole member + * @param $pParamHash an array of content to be stored. + * @param $pParamHash[parent_id] id of pigeonhole it belongs to, default is $this->mContentId + * @param $pParamHash[content_id] content_id of the item to be stored + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function insertPigeonholeMember( &$pParamHash ) { + if( $this->verifyPigeonholeMember( $pParamHash ) ) { + foreach( $pParamHash['member_store'] as $item ) { + $result = $this->mDb->associateInsert( BIT_DB_PREFIX."pigeonhole_members", $item ); + } + } else { + error_log( "Error inserting pigeonhole: " . vc($this->mErrors)); + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * verify, clean up and prepare data to be stored + * @param $pParamHash all information that is being stored. will update $pParamHash by reference with fixed array of itmes + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access private + **/ + function verifyPigeonholeMember( &$pParamHash ) { + $this->mDb->StartTrans(); + foreach( $pParamHash as $key => $item ) { + if( isset( $item['parent_id'] ) && @BitBase::verifyId( $item['parent_id'] ) ) { + $tmp['member_store'][$key]['parent_id'] = $item['parent_id']; + } elseif( @BitBase::verifyId( $this->mContentId ) ) { + $tmp['member_store'][$key]['parent_id'] = $this->mContentId; + $pParamHash[$key]['parent_id'] = $this->mContentId; + } else { + $this->mErrors['store_members'] = tra( 'The content could not be inserted because the parent_id was missing.' ); + } + + if( isset( $item['content_id'] ) && @BitBase::verifyId( $item['content_id'] ) ) { + $tmp['member_store'][$key]['content_id'] = $item['content_id']; + } else { + $this->mErrors['store_members'] = 'The content id is not valid.'; + } + } + + $this->mDb->CompleteTrans(); + $pParamHash = $tmp; + return( count( $this->mErrors ) == 0 ); + } + + /** + * Expunge pigeonhole member + * @param $pParamHash['parent_id'] parent_id of content to be deleted + * @param $pParamHash['member_id'] content_id of content to be deleted + * @param $pParamHash['deletables'] array of content_ids to check against when deleting. makes sure that only members of a given structure are removed + * Note if only one of the 2 ids is given, all items with that id will be removed. if both are given, only that one particular entry is removed + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function expungePigeonholeMember( $pParamHash ) { + if( @BitBase::verifyId( $pParamHash['parent_id'] ) || @BitBase::verifyId( $pParamHash['member_id'] ) ) { + $where = ''; + $bindVars = array(); + + if( @BitBase::verifyId( $pParamHash['parent_id'] ) ) { + $where .= " WHERE `parent_id`=? "; + $bindVars[] = $pParamHash['parent_id']; + } + + if( @BitBase::verifyId( $pParamHash['member_id'] ) ) { + $where .= ( empty( $where ) ? " WHERE " : " AND " )." `content_id`=? "; + $bindVars[] = $pParamHash['member_id']; + } + + if( !empty( $pParamHash['deletables'] ) && is_array( $pParamHash['deletables'] ) ) { + // only delete member data when it's part of the deletable structure + $where .= ( empty( $where ) ? " WHERE " : " AND " )." `parent_id` IN( ".preg_replace( "/,$/", "", str_repeat( "?,", count( $pParamHash['deletables'] ) ) )." ) "; + $bindVars = array_merge( $bindVars, $pParamHash['deletables'] ); + } + + // now we're ready to remove the actual members + $query = "DELETE FROM `".BIT_DB_PREFIX."pigeonhole_members` $where"; + $result = $this->mDb->query( $query, $bindVars ); + } else { + $this->mErrors['members_store'] = 'The category member(s) could not be removed.'; + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * Expunge currently loaded pigeonhole + * @return bool TRUE on success, FALSE if store could not occur. + * @access public + **/ + function expunge( $pStructureId = NULL ) { + $ret = FALSE; + // if we have a custom structure id we want to remove, load it + if( @BitBase::verifyId( $pStructureId ) ) { + $this->mStructureId = $pStructureId; + $this->load(); + } + + if( $this->isValid() ) { + $this->mDb->StartTrans(); + // get all items that are part of the sub tree + require_once( LIBERTY_PKG_CLASS_PATH.'LibertyStructure.php' ); + $struct = new LibertyStructure(); + + // include the current structure id as well + $structureIds[] = $this->mStructureId; + $tree = $struct->getSubTree( $this->mStructureId ); + foreach( $tree as $node ) { + $structureIds[] = $node['structure_id']; + } + + $structureIds = array_unique( $structureIds ); + $where = ''; + foreach( $structureIds as $structureId ) { + $where .= ( empty( $where ) ? " WHERE " : " OR ")."`structure_id`=?"; + } + $result = $this->mDb->query( "SELECT `content_id` FROM `".BIT_DB_PREFIX."liberty_structures` $where", $structureIds ); + $contentIds = $result->getRows(); + + foreach( $contentIds as $id ) { + // now we have the content ids - let the nuking begin + $query = "DELETE FROM `".BIT_DB_PREFIX."pigeonholes` WHERE `content_id` = ?"; + $result = $this->mDb->query( $query, array( $id['content_id'] ) ); + $query = "DELETE FROM `".BIT_DB_PREFIX."pigeonhole_members` WHERE `parent_id` = ?"; + $result = $this->mDb->query( $query, array( $id['content_id'] ) ); + + // remove all entries from content tables + $this->mContentId = $id['content_id']; + if( LibertyMime::expunge() ) { + $ret = TRUE; + $this->mDb->CompleteTrans(); + } else { + $this->mDb->RollbackTrans(); + } + } + + // finally nuke the structure in liberty_structures + $struct->removeStructureNode( $this->mStructureId, FALSE ); + } + return $ret; + } + + /** + * Generates the URL to this pigeonhole + * @param $pContentId is the pigeonhole id we want to see + * @return the link to display the page. + */ + public static function getDisplayUrlFromHash( &$pParamHash ) { + global $gBitSystem; + $ret = NULL; + + if( @BitBase::verifyId( $$pParamHash['content_id'] ) ) { + $rewrite_tag = $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ? 'view/' : ''; + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) || $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ) { + $ret = PIGEONHOLES_PKG_URL.$rewrite_tag.$pContentId; + }else{ + $ret = PIGEONHOLES_PKG_URL.'view.php?content_id='.$pContentId; + } + } + + return $ret; + } + + /** + * Returns HTML link to display a pigeonhole + * @param $pTitle is the pigeonhole we want to see + * @param $pContentId content id of the pigeonhole in question + * @return the link to display the page. + */ + function getDisplayLink( $pLinkText = NULL, $pMixed = NULL, $pAnchor = NULL ) { + global $gBitSystem; + if( empty( $pLinkText ) && !empty( $this ) ) { + $ppLinkText = $this->getTitle(); + } + + if( empty( $pMixed ) && !empty( $this ) ) { + $pMixed = $this->mInfo; + } + + $ret = $pLinkText; + if( !empty( $pLinkText ) && !empty( $pMixed ) ) { + if( $gBitSystem->isPackageActive( 'pigeonholes' ) ) { + $ret = '<a title="'.htmlspecialchars( $pLinkText ).'" href="'.Pigeonholes::getDisplayUrlFromHash( $pMixed ).'">'.htmlspecialchars( $pLinkText ).'</a>'; + } + } + + return $ret; + } + + /** + * Get all child pigeonholes starting from any parent + * + * @param array $pContentId of the pigoenhole + * @param array $pStructureId of the pigeonhole + * @access public + * @return array of child pigeonholes on success, empty array on failure + */ + function getSubPigeonholes( $pContentId = NULL, $pStructureId = NULL ) { + global $gStructure; + $ret = array(); + + if( empty( $gStructure )) { + $struct = new LibertyStructure(); + } else { + $struct = &$gStructure; + } + + if( @BitBase::verifyId( $pContentId ) && !@BitBase::verifyId( $pStructureId )) { + $pigeon = $struct->getNode( NULL, $pContentId ); + $pStructureId = $pigeon['structure_id']; + } + + if( @BitBase::verifyId( $pStructureId )) { + $tree = $struct->getSubTree( $pStructureId ); + + // weed out duplicates + foreach( $tree as $pigeon ) { + if( !in_array( $pigeon['content_id'], array_keys( $ret ))) { + $ret[$pigeon['content_id']] = $pigeon; + } + } + } + + return $ret; + } +} + +function pigeonholes_alphabetiser( $a, $b ) { + return strcasecmp( $a["title"], $b["title"] ); +} + +function pigeonholes_pathlist_sorter( $aa, $ab ) { + foreach( $aa as $key => $a ) { + if( !empty( $ab[$key] ) ) { + if( $a['pos'] < $ab[$key]['pos'] ) { + return -1; + } elseif( $a['pos'] > $ab[$key]['pos'] ) { + return 1; + } + } else { + return 1; + } + } +} + + +// ============= SERVICE FUNCTIONS ============= + +/** + * pigeonholes_content_display + * + * @param array $pObject + * @access public + * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure + */ +function pigeonholes_content_display( &$pObject ) { + global $gBitSystem, $gBitSmarty, $gBitUser, $gBitThemes; + $pigeonholes = new Pigeonholes(); + + // first we need to check permissions + if( $gBitSystem->isFeatureActive( 'pigeonhole_permissions' ) || $gBitSystem->isFeatureActive( 'pigeonholes_groups' )) { + if( $pigeons = $pigeonholes->getPigeonholesFromContentId( $pObject->mContentId )) { + foreach( $pigeons as $pigeon ) { + // we will loop through here until we get one pigeonhole that allows access + if( empty( $access_granted )) { + if( $pigeonholes->checkPathPermissions( $pigeonholes->getPigeonholePath( $pigeon['structure_id'] ))) { + $access_granted = TRUE; + } else { + $access_granted = FALSE; + } + } + } + } + + // we need to check all pigeonholes in the path, load the prefs and work out if the user is allowed to view the page + if( isset( $access_granted ) && $access_granted === FALSE ) { + $msg = tra( "This content is part of a category to which you have no access to. Please log in or request the appropriate permission from the site administrator." ); + $gBitSystem->fatalPermission( NULL, $msg ); + } + } + + if( $gBitSystem->isFeatureActive( 'pigeonholes_display_members' ) || $gBitSystem->isFeatureActive( 'pigeonholes_display_path' )) { + if( $gBitUser->hasPermission( 'p_pigeonholes_view' )) { + if( $pigeons = $pigeonholes->getPigeonholesFromContentId( $pObject->mContentId )) { + foreach( $pigeons as $key => $pigeon ) { + $pigeonholes->mContentId = $pigeon['content_id']; + $pigeonholes->load( TRUE, FALSE ); + $pigeonData[] = $pigeonholes->mInfo; + + // set the theme chosen for this page - virtually random if page is part of multiple themes + if( $gBitSystem->isFeatureActive( 'pigeonholes_themes' )) { + // loadPreferences is called by getPreference if needed + $gBitThemes->setStyle( $pigeonholes->getPreference( 'style' )); + } + } + $gBitSmarty->assign( 'pigeonData', !empty( $pigeonData ) ? $pigeonData : FALSE ); + } + } + } +} + +/** + * pigeonholes_content_edit + * + * @param array $pObject + * @access public + * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure + */ +function pigeonholes_content_edit( $pObject=NULL ) { + global $gBitSmarty, $gBitUser, $gBitSystem; + $pigeonPathList = array(); + + if( is_object($pObject) && isset($pObject->mContentTypeGuid) && + !$gBitSystem->isFeatureActive('pigeonhole_no_'.$pObject->mContentTypeGuid) && + $gBitUser->hasPermission( 'p_pigeonholes_insert_member' ) ) { + $pigeonholes = new Pigeonholes(); + + $gBitSmarty->assign('editPigeonholesEnabled', TRUE); + + // get pigeonholes path list + if( $pigeonPathList = $pigeonholes->getPigeonholesPathList(( !empty( $pObject->mContentId ) ? $pObject->mContentId : NULL ), ( $gBitSystem->isFeatureActive( 'pigeonholes_use_jstab' ) ? FALSE : 100 ))) { + $gBitSmarty->assign( 'pigeonPathList', $pigeonPathList ); + } + } else { + $gBitSmarty->assign('editPigeonholesEnabled', FALSE); + } +} + +/** + * pigeonholes_content_expunge + * + * @param array $pObject + * @access public + * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure + */ +function pigeonholes_content_expunge( $pObject=NULL ) { + $pigeonholes = new Pigeonholes(); + $pigeonholes->expungePigeonholeMember( array( 'member_id' => $pObject->mContentId ) ); +} + +/** + * pigeonholes_content_preview + * + * @access public + * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure + */ +function pigeonholes_content_preview( $pObject=NULL, $pParamHash ) { + global $gBitSmarty, $gBitUser, $gBitSystem; + $pigeonPathList = array(); + + if( is_object($pObject) && isset($pObject->mContentTypeGuid) && + !$gBitSystem->isFeatureActive('pigeonhole_no_'.$pObject->mContentTypeGuid) && + $gBitUser->hasPermission( 'p_pigeonholes_insert_member' ) ) { + $pigeonholes = new Pigeonholes(); + + // get pigeonholes path list + if( $pigeonPathList = $pigeonholes->getPigeonholesPathList() ) { + foreach( $pigeonPathList as $key => $path ) { + if( !empty( $pParamHash['pigeonholes']['pigeonhole'] ) && in_array( $key, $pParamHash['pigeonholes']['pigeonhole'] ) ) { + $pigeonPathList[$key][0]['selected'] = TRUE; + } else { + $pigeonPathList[$key][0]['selected'] = FALSE; + } + } + $gBitSmarty->assign( 'pigeonPathList', $pigeonPathList ); + } + } +} + +/** + * pigeonholes_content_store + * + * @param array $pObject + * @param array $pParamHash + * @access public + * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure + */ +function pigeonholes_content_store( $pObject, $pParamHash ) { + global $gBitSmarty, $gBitUser, $gBitSystem; + if( is_object($pObject) && isset($pObject->mContentTypeGuid) && + !$gBitSystem->isFeatureActive('pigeonhole_no_'.$pObject->mContentTypeGuid) && + $gBitUser->hasPermission( 'p_pigeonholes_insert_member' ) ) { + + if( is_object( $pObject ) && empty( $pParamHash['content_id'] ) ) { + $pParamHash['content_id'] = $pObject->mContentId; + } + + if( !empty( $pParamHash['content_id'] ) ) { + + $pigeonholes = new Pigeonholes(); + $pigeonPathList = $pigeonholes->getPigeonholesPathList( $pParamHash['content_id'] ); + + // here we need to work out if we need to save at all + // get all originally selected items + $selectedItem = array(); + if( !empty( $pigeonPathList ) ) { + foreach( $pigeonPathList as $path ) { + if( !empty( $path[0]['selected'] ) ) { + $pathItem = array_pop( $path ); + $selectedItem[] = $pathItem['content_id']; + } + } + } + + // quick and dirty check to start off with + if( empty( $pParamHash['pigeonholes'] ) || count( $pParamHash['pigeonholes']['pigeonhole'] ) != count( $selectedItem ) ) { + $modified = TRUE; + } else { + // more thorough check + foreach( $selectedItem as $item ) { + if( !in_array( $item, $pParamHash['pigeonholes']['pigeonhole'] ) ) { + $modified = TRUE; + } + } + } + + if( !empty( $modified ) ) { + // first remove all entries with this content_id + if( $pigeonholes->expungePigeonholeMember( array( 'member_id' => $pParamHash['content_id'] ) ) && !empty( $pParamHash['pigeonholes'] ) ) { + // insert the content into the desired pigeonholes + foreach( $pParamHash['pigeonholes']['pigeonhole'] as $p_id ) { + $memberHash[] = array( + 'parent_id' => $p_id, + 'content_id' => $pParamHash['content_id'] + ); + } + + if( !$pigeonholes->insertPigeonholeMember( $memberHash ) ) { + $gBitSmarty->assign( 'msg', tra( "There was a problem inserting the content into the pigeonholes." ) ); + $gBitSystem->display( 'error.tpl' , NULL, array( 'display_mode' => 'display' )); + die; + } + } + } + } + } +} + +/** + * When the list function is called and the template, a filter option will appear based on categories + * + * @param array $pObject Current object + * @param array $pParamHash Parameter hash - only works if $pParamHash[pigeonholes][filter] is passed back to the list sql funciton + * @access public + * @return void + */ +function pigeonholes_content_list( &$pObject, $pParamHash = NULL ) { + global $gBitSystem, $gBitSmarty; + if( $gBitSystem->isFeatureActive( 'pigeonholes_list_filter' )) { + $pigeonholes = new Pigeonholes(); + $listHash = array( + 'sort_mode' => array( + 'root_structure_id_asc', 'title_asc' + ), + 'insertable' => TRUE, + ); + $pigeonList = $pigeonholes->getList( $listHash ); + $list = array(); + foreach( $pigeonList as $pigeon ) { + $list[$pigeon['content_id']] = $pigeon['display_link']; + } + $gBitSmarty->assign( 'pigeonList', $list ); + } +} + +/** + * filter the search with pigeonholes + * @param $pParamHash['pigeonholes']['filter'] - a pigeonhole or an array of pigeonhole content_id + **/ +function pigeonholes_content_list_sql( &$pObject, $pParamHash = NULL ) { + global $gBitSystem; + $ret = array(); + + if( !empty( $pParamHash['pigeonholes']['no_filter'] )) { + $pParamHash['pigeonholes']['filter'] = array(); + } else { + if( !empty( $pParamHash['pigeonholes']['filter'] )) { + $pParamHash['liberty_categories'] = $pParamHash['pigeonholes']['filter']; + } + + if( !empty( $pParamHash['liberty_categories'] )) { + if( !is_array( $pParamHash['liberty_categories'] )) { + $pParamHash['liberty_categories'] = array( $pParamHash['liberty_categories'] ); + } + + // if we want to allow items in subcategories, we get those and include them in the query + if( !empty( $pParamHash['pigeonholes']['sub_holes'] )) { + $pigeonholes = new Pigeonholes(); + $contentIds = array(); + foreach( $pParamHash['liberty_categories'] as $pigeonhole ) { + $pigeons = $pigeonholes->getSubPigeonholes( $pigeonhole ); + $contentIds = array_merge( $contentIds, array_keys( $pigeons )); + } + $contentIds = array_unique( array_merge( $pParamHash['liberty_categories'], $contentIds )); + } else { + $contentIds = $pParamHash['liberty_categories']; + } + + $ret['join_sql'] = "INNER JOIN `".BIT_DB_PREFIX."pigeonhole_members` pm ON (lc.`content_id`=pm.`content_id`)"; + $ret['where_sql'] = 'AND pm.`parent_id` IN ('.implode( ',', array_fill( 0, count( $contentIds ), '?' )).')'; + $ret['bind_vars'] = $pParamHash['pigeonholes']['filter'] = $contentIds; + } + + if( !empty( $pParamHash['pigeonholes']['root_filter'] )) { + $pParamHash['liberty_root_categories'] = $pParamHash['pigeonholes']['root_filter']; + } + + if( !empty( $pParamHash['liberty_root_categories'] )) { + if( !is_array( $pParamHash['liberty_root_categories'] )) { + $pParamHash['liberty_root_categories'] = array( $pParamHash['liberty_root_categories'] ); + } + + // if we want to allow items in subcategories, we get those and include them in the query + if( !empty( $pParamHash['pigeonholes']['root_sub_holes'] )) { + $pigeonholes = new Pigeonholes(); + $contentIds = array(); + foreach( $pParamHash['liberty_root_categories'] as $pigeonhole ) { + $pigeons = $pigeonholes->getSubPigeonholes( $pigeonhole ); + $contentIds = array_merge( $contentIds, array_keys( $pigeons )); + } + $contentIds = array_unique( array_merge( $pParamHash['liberty_root_categories'], $contentIds )); + } else { + $contentIds = $pParamHash['liberty_root_categories']; + } + + $ret['join_sql'] = "INNER JOIN `".BIT_DB_PREFIX."pigeonhole_members` rpm ON (rlc.`content_id`=rpm.`content_id`)"; + $ret['where_sql'] = 'AND rpm.`parent_id` IN ('.implode( ',', array_fill( 0, count( $contentIds ), '?' )).')'; + $ret['bind_vars'] = $pParamHash['pigeonholes']['filter'] = $contentIds; + } + } + + return $ret; +} +?> |
