File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/api/class.lists.php
<?php
/**
* This file contains the iwp_lists class
*
* @version $Id$
*
*
* @package IWP
* @subpackage IWP_API
*/
/**
* IWP Lists Class
* This is the class that handles all the functions related to lists
*
* @package IWP
* @subpackage IWP_API
*/
class iwp_lists extends iwp_engine {
/**
* baseTableName
* This is the name of the current working database table without its prefix.
* This is set in the child class declaration.
*
* @var String $baseTableName
*
* @see SetTableName
*/
protected $baseTableName = 'lists';
/**
* primaryKey
* This is the primary key field name for the current working db table.
*
* @var String $primaryKey
*
* @see Load
* @see Save
* @see LoadByField
* @see LoadMulti
* @see ValidColumn
*/
protected $primaryKey = 'listid';
/**
* _columns
* This is an array of the current table's columns. This array stays blank and is used
* as a table structure reference.
*
* @var array _columns
*
* @see ResetColumns
* @see ValidColumn
*/
protected $_columns = array(
'listid'=>'',
'type'=>'',
'title'=>'',
'querycache'=>'',
'datatype'=>'',
'options'=>'',
'rssurl'=>'',
'matchtype'=>'',
'blocktype'=>'',
'cssclasses'=>'',
'rssfeed'=>'',
'homepage'=>'',
'itemcount'=>0,
);
/**
* data
* This is an array of the current table's columns. This array stays blank and is used
* as a table structure reference.
*
* @var array _columns
*
* @see ResetColumns
* @see ValidColumn
*/
protected $data = array(
'type'=>'',
'title'=>'',
'querycache'=>'',
'datatype'=>'none',
'options'=>'',
'rssurl'=>'',
'matchtype'=>'none',
'blocktype'=>'',
'cssclasses'=>'',
'rssfeed'=>'no',
'homepage'=>'no',
'itemcount'=>0,
);
protected $RSSFeed = null;
protected $outputRSSFeeds = array();
public $foundRows = 0;
public static $outputCount = array();
public $ignoreCache = false;
/**
* Instance
* This static variable holds the current instance of this object being loaded.
* So using the getInstance function anywhere will return the very same instance.
*
* @var object Instance
*/
public static $Instance;
/**
* This static variable contains permissions that are available to be chosen for setting User Groups permissions.
*
* @var Array
*/
public static $PermissionOptions;
/**
* getInstance
* This is a static function that sets up the class instance and stores it to the static variable. It will then return that instantiation in the future.
*
* @return iwp_lists Returns the instantiated object
**/
public static function getInstance(){
if(!isset(self::$Instance)){
self::$Instance = new self();
}
return self::$Instance;
}
/**
* This function returns the permission options for lists
*
* @return array The value of the static member variable PermissionOptions
*
* @see $PermissionOptions
*/
public static function GetPermissionOptions () {
return self::$PermissionOptions;
}
/**
* This function generates an SQL query to run on the database based on filters specified for a list.
* A dataset must be loaded in the class from the Load() function.
*
* @param boolean $returnArray Whether to return the generated query as a strng or an array of components.
*
* @return string The query that can be run on the database to get the list items.
*
* @see LoadFilters()
*/
public function GenerateQuery($returnArray=false){
if($this->GetId() < 1){
return '';
}
$orderby = $limit = $whereFilters = array();
$formattedWhere = $contentTypeIds = array();
$where = $query = $groupby = '';
$orderFieldPrefix = 'c.';
// Load all the filters
list($whereFilters, $limit, $orderby) = $this->LoadFilters();
switch($this->Get('datatype')){
case 'categories':
$query = 'select SQL_CALC_FOUND_ROWS *, c.categoryid as rowid, c.name as title, (select count(*) from '. IWP_TABLE_CATEGORIES .' cc where cc.parentid = c.categoryid) as childcount from ' . IWP_TABLE_CATEGORIES . ' as c /*%%list_sortcache_join%%*/';
$defaultOrderField = "/*%%list_sortcache_sortfield%%*/";
break;
case 'users':
$query = 'select SQL_CALC_FOUND_ROWS *, u.userid as rowid, concat(u.firstname, " ", u.lastname) as title from ' . IWP_TABLE_USERS . ' as u';
$defaultOrderField = "u.lastname";
$orderFieldPrefix = 'u.';
break;
default:
$query = 'select SQL_CALC_FOUND_ROWS *, c.contentid as rowid,
(select count(*) from '. IWP_TABLE_CONTENT .' cc where cc.contentparentid = c.contentid) as childcount,
(select group_concat( ca.categoryid ) from '. IWP_TABLE_CATASSOC .' ca where ca.contentid=c.contentid) as categorylist,
(select urlpath from ' . IWP_TABLE_URLS .' as u where c.contentid=u.associd and u.assoctype="content") as urlpath,
c.contentid as contentid from ' . IWP_TABLE_CONTENT . ' as c
inner join '. IWP_TABLE_CONTENTTYPES .' as ct on ct.typeid = c.typeid
/*%%list_sortcache_join%%*/';
$defaultOrderField = "/*%%list_sortcache_sortfield%%*/";
}
$hasParentField = false;
// some where filters need to be specially handled
foreach($whereFilters as $k=>$row){
if($row['operator'] == 'iscontenttype'){
// we separate the content type ID's as we just want 1 sub-query with them, not one for each
$contentTypeIds[] = $row['value'];
}else{
$formattedWhere[] = $this->GetConditionFormat($row['operator'], $row['fieldname'], $row['value']);
}
if($row['fieldname'] == 'parentid'){
// flag there there is a parent ID
$hasParentField = true;
}
}
if(!$hasParentField && $this->Get('datatype') == 'categories') {
}
if(sizeof($contentTypeIds) > 0){
// use the list of content Id's to generate a single query
$formattedWhere[] = $this->GetConditionFormat('iscontenttype', '', $contentTypeIds);
}
if($limit['operator'] == 'total'){
// the list only has a limit, no paging
$limitQuery = ' limit '.(int)$limit['value'];
}else{
/**
* TODO: paging limit query here
*/
// the list has paging
$limitQuery = ' limit '.(int)$limit['value'];
}
// the visibility placeholder uses a mysql comment so the generated query can be easily run on it's own for debugging purposes
if($this->Get('datatype') != "users") {
$where = ' where /*%%visibility%%*/ /*%%listid%%*/ ';
} else {
$where = ' where ';
}
switch($this->Get('datatype')){
case 'categories':
$where .= ' /*%%categoryparentid%%*/ ';
break;
case 'content':
default:
$where .= ' /*%%contentparentid%%*/ ';
break;
}
if (sizeof($formattedWhere) > 0) {
$where .= ' (';
if($this->Get('datatype') == 'content'){
$where .= ' (' .implode(' '.$this->Get('matchtype').' ', $formattedWhere) .') and c.parentid=0 ';
}else{
$where .= implode(' '.$this->Get('matchtype').' ', $formattedWhere);
}
$where .= ')';
} else {
if ($this->Get('datatype') == 'content') {
$where .= ' c.parentid=0 ';
} else {
// because the visibility placeholder will add (visibility sql) AND (... where ...) we need *something* in the where clause
$where .= ' (1=1)';
}
}
if($this->Get('datatype') == 'content' || $this->Get('datatype') == 'categories') {
$strOrderby = $defaultOrderField;
}else{
if(is_array($orderby) && isset($orderby['fieldname']) && strlen($orderby['fieldname']) > 1){
$strOrderby = ' order by '.$orderFieldPrefix. $orderby['fieldname'] . ' ' . $orderby['value'];
}else{
$strOrderby = ' order by '.$defaultOrderField.' desc ';
}
}
if(!$returnArray) {
return $query . $where . ' ' . $groupby . $strOrderby . $limitQuery;
}
return array(
'query' => $query,
'where' => $where ,
'groupby' => $groupby,
'orderby' => $strOrderby,
'limitquery' => $limitQuery,
);
}
/**
* This function retrieves the list of RSS feeds based on output of lists
*/
public function GetFeeds(){
return $this->outputRSSFeeds;
}
/**
* This function formats the where condition for an SQL query. It takes the operator name and determines what sign and format to use the name and value with.
* It also checks if the value is an integer, string, or array
*
* @param string $operatorName The name of the condition to use, e.g. 'equalto'
* @param string $field The fieldname to use the condition on
* @param string $value The value to use for the condition/comparison
*
* @see GenerateQuery()
*/
public function GetConditionFormat($operatorName, $field, $value){
if(!is_int($value) && !is_array($value)){
$length = strlen($value);
$value = '"'.$this->db->Quote($value).'"';
}
switch($operatorName){
case 'equalto':
return $field.'='.$value;
case 'lessthan':
return $field.'<'.$value;
case 'greaterthan':
return $field.'>'.$value;
case 'equalgreaterthan':
return $field.'<='.$value;
case 'equallessthan':
return $field.'>='.$value;
case 'begins':
return 'left('.$field.', '.$length.')='.trim($value);
case 'ends':
return 'right('.$field.', '.$length.')='.$value;
case 'contain':
return 'instr('.$field.', '.$value.')>0';
case 'notcontain':
return 'not(instr('.$field.', '.$value.')>0)';
case 'notbegins':
return 'not(left('.$field.', '.strlen($value).')='.$value.')';
case 'notends':
return 'not(right('.$field.', '.strlen($value).')='.$value.')';
case 'ismemberofgroup':
return '(select count(*) from '.IWP_TABLE_GROUPASSOC.' ga where ga.userid=u.userid and ga.groupid IN('.$value.'))>0';
case 'iscontenttype':
return ' c.typeid IN('.$this->valid->FilterArrayToCsv($value).')';
case 'isincategory':
return '(select count(*) from '.IWP_TABLE_CATASSOC.' as cat where cat.contentid=c.contentid and cat.categoryid IN('.$value.'))>0';
case 'length':
return 'length('.$field.')>'.$value;
case 'isstatus':
return $field.'='.$value;
case 'checked':
return $field.'=1';
case 'notchecked':
return $field.'=0';
case 'before':
return $field.'<"'.GetMysqlDateTime(strtotime(preg_replace("/(\d{2})\/(\d{2})\/(\d{2,4})/", "$2/$1/$3", str_replace('"', '',$value)))).'"';
case 'after':
return $field.'>"'.GetMysqlDateTime(strtotime(preg_replace("/(\d{2})\/(\d{2})\/(\d{2,4})/", "$2/$1/$3", str_replace('"', '',$value))) + 86399).'"';
default:
return '';
}
}
/**
* This function selects the filters from the database and formats them into 3 arrays for processing.
* One array with the where coniditons, one array with the limit number and a third array for the order by field and direction.
* Recommended Usage: list($whereFilters, $limit, $orderby) = $this->LoadFilters();
*
* @return array An array with 3 sub-arrays
*
* @see GenerateQuery()
*/
public function LoadFilters(){
if($this->GetId() < 1){
return '';
}
$query = $this->db->Query('select * from ' . IWP_TABLE_LIST_FILTERS . ' where listid='.$this->GetId());
$orderby = $limit = $whereFilters = array();
while($row = $this->db->Fetch($query)) {
if($row['filtertype'] == 'where'){
if (in_array($row['fieldname'], array('visible', 'enableexpiry', 'status', 'startdate', 'expirydate'))) {
// visibility checks are now performed internally, not in the cached queries - see LoadQuery()
// check for and drop the field here just incase the upgrade script to remove these filters doesn't work / doesn't get created
continue;
}
$whereFilters[] = $row;
continue;
}
if($row['filtertype'] == 'limit'){
$limit = $row;
continue;
}
if($row['filtertype'] == 'orderby'){
$orderby = $row;
}
}
return array($whereFilters, $limit, $orderby);
}
/**
* This function outputs a formatted HTML list for a specified list
*
* @param integer $id The ID number of the list to load the HTML for. Optional, if a list dataset is loaded in the class.
*
* @return string The list in HTML format
*
* @see GetDynamicListOutput()
* @see GetRssListOutput()
* @see GetStaticListOutput()
*/
public function OutputListById($id=null, $section='left', $type = 'dynamic', $displayStyle=null, $outputCounter=0){
if($id === null && $this->GetId() < 1){
return;
}else{
if(!$this->SetId($id)){
return;
}
}
if(!isset(self::$outputCount[$section])){
self::$outputCount[$section] = 1;
}else{
self::$outputCount[$section]++;
}
$outputCounter++;
$this->template->Assign('blockNumberClass', ' Block' . $outputCounter . ' ');
$this->template->Append('blockNumberClass', ' listBlock' . self::$outputCount[$section] . ' ');
$cacheId = $id . '_' . md5($id . $section);
$cacheIdRss = $id . '_rss_' . md5($id . $section . 'rssFeed');
$this->cache->SetDir('lists');
$outputHTML = '';
if(!$this->cache->HasExpired($cacheId)){
$this->template->Append('headTagEnd',$this->cache->ReadCache($cacheIdRss), false);
return $this->cache->ReadCache($cacheId);
}
$this->Load();
if($this->Get('rssfeed') == 'yes'){
$safeName = substr($this->Get('title'), 0, 15);
$RssLinkHTML = '<link rel="alternate" type="application/rss+xml" title="'.$this->Get('title').'" href="'.$this->urls->GetStaticUrl('viewrss', array('name'=>$safeName, 'idnumber'=>$id)).'" />';
$this->cache->WriteCache($cacheIdRss, $RssLinkHTML);
$this->template->Append('headTagEnd', $RssLinkHTML, false);
}else{
$this->cache->WriteCache($cacheIdRss, '');
}
if($this->Get('type') == 'dynamic'){
$ignoreCache = $this->ignoreCache;
$this->ignoreCache = true;
$outputHTML = $this->GetDynamicListOutput($section, $displayStyle);
$this->cache->WriteCache($cacheId, $outputHTML);
$this->ignoreCache = $ignoreCache;
}elseif($this->Get('type') == 'static'){
$outputHTML = $this->GetStaticListOutput($section, $displayStyle);
$this->cache->WriteCache($cacheId, $outputHTML);
}elseif($this->Get('type') == 'rss'){
$outputHTML = $this->GetRssListOutput($section, $displayStyle);
$this->cache->WriteCache($cacheId, $outputHTML);
}
return $outputHTML;
}
/**
* This function outputs a custom list through a query -- Useful for category pages or any other custom query list
*
* @param string $query The query to be executed for the list of items
* @param string $displayStyle This is the display style to be used, defaults to null which means 'Standard' is used
* @param string $datatype This is the type of data being retrieved: content, users, categories, comments
* @param string $section This is the section the list is to be displayed in: middle, right, left, top, bottom
*
* @return string The resulting HTML from either a cache or running of the query
*/
public function OutputListByQuery($query, $displayStyle=null, $datatype='content', $section='middle'){
$this->Set('querycache', $query);
$this->Set('datatype', $datatype);
$return = $this->GetDynamicListOutput($section, $displayStyle);
return $return;
}
/**
* This function outputs a custom rss list through a query -- Useful for category pages or any other custom query list
*
* @param string $query The query to be executed for the list of items
* @param string $datatype This is the type of data being retrieved: content, users, categories, comments
*
* @return string The resulting RSS XML
*/
public function OutputRssByQuery($query, $datatype='content'){
$this->Set('querycache', $query);
$this->Set('datatype', $datatype);
$return = $this->GetRSSofDynamicListOutput();
return $return;
}
/**
* Private storage for a static list of content type id -> active modules for parsing of contenttype lists
*
* @var array
*/
private static $_content_type_active_modules = array();
/**
* This function gets the formatted HTML for a dynamic list and returns it.
* It uses the query cache and the template saved in the database.
*
* @return string The formatted HTML
* @see OutputListById()
*/
public function GetDynamicListOutput($section, $displayStyle=null){
$rowCount = 0;
$outputHTML = '';
$outputList = array();
$listTemplateFileContents = $listTemplateFile = '';
$query = $this->LoadQuery();
if(!$this->ignoreCache){
$cacheId = $this->GetId() . '_' . md5($query.$section);
$this->cache->SetDir('lists');
if(!$this->cache->HasExpired($cacheId)){
return $this->cache->ReadCache($cacheId);
}
}
$resource = $this->db->Query($query);
if(in_string('SQL_CALC_FOUND_ROWS', $query)){
$this->foundRows = (int)$this->db->FetchOne("SELECT found_rows()");
if((int)$this->foundRows != (int)$this->Get('itemcount')){
$this->Set('itemcount', (int)$this->foundRows);
if($this->ValidId()){
$this->Save();
}
}
}else{
$countQuery = str_replace('select *', 'select count(*) as itemcount', $query);
$itemCount = $this->db->FetchQuery($countQuery);
if((int)$itemCount['itemcount'] != (int)$this->Get('itemcount')){
$this->Set('itemcount', (int)$itemCount['itemcount']);
if($this->ValidId()){
$this->Save();
}
}
}
if($this->Get('homepage') == 'yes'){
$homepage = array();
$homepage['Url'] = iwp_config::Get('siteURL') .'/';
$homepage['Title'] = iwp_htmlspecialchars($this->lang->Get('HomePage'));
$outputList[] = $homepage;
}
if($displayStyle !== null && is_file(IWP_CACHE_SECTION_HTML_PATH .'/list_'.$displayStyle.'.html')){
$listTemplateFile = IWP_CACHE_SECTION_HTML_PATH .'/list_'.$displayStyle.'.html';
}elseif(is_file(IWP_CACHE_SECTION_HTML_PATH .'/list_'.iwp_strtolower($section).'_standard.html')){
$listTemplateFile = IWP_CACHE_SECTION_HTML_PATH .'/list_'.iwp_strtolower($section).'_standard.html';
}elseif(is_file(IWP_CACHE_SECTION_HTML_PATH .'/list_'.iwp_strtolower($section).'_linked_title.html')){
$listTemplateFile = IWP_CACHE_SECTION_HTML_PATH .'/list_'.iwp_strtolower($section).'_linked_title.html';
}
if(!empty($listTemplateFile)) {
$listTemplateFileContents = @file_get_contents($listTemplateFile);
}
$modules = iwp_modules::getInstance();
// array of references to points in a hierarchy
$mapping = array();
// 99% of the time this will be used to loop over a list of categories with a common parent
// but we can build it cope with several and only look up each ancestry line once, so we will
$categoryParentsCache = array('0' => array());
while($row = $this->db->Fetch($resource)) {
++$rowCount;
$listResultArray = array();
if(!isset($row['rowid'])){
if(isset($row['contentid'])){
$row['rowid'] = $row['contentid'];
}elseif(isset($row['userid'])){
$row['rowid'] = $row['userid'];
}elseif(isset($row['categoryid'])){
$row['rowid'] = $row['categoryid'];
}elseif(isset($row['commentid'])){
$row['rowid'] = $row['commentid'];
}
}
if ($this->Get('datatype') == 'content' && isset($row['modulelist'])) {
$contenttypes = iwp_contenttypes::getInstance();
$fieldList = $contenttypes->FlattenFieldsArray($contenttypes->ExplodeFields($row['modulelist']));
// remove unused fields
// example: old summary content if a content type once had the summary field but no longer has that field assigned
if (!in_array('field_summary', $fieldList)) {
unset($row['summary']);
}
}
$listResultArray = $row;
$listResultArray['loadModules'] = true;
if(isset($row['urlpath'])) {
$baseUrl = $row['urlpath'];
$listResultArray['Url'] = iwp_htmlspecialchars($this->urls->GetURLPrepend(true,false) . $baseUrl);
}else{
if (isset($row['categoryid']) && isset($row['parentid'])) {
if (isset($categoryParentsCache[$row['parentid']])) {
$row['parents'] = $categoryParentsCache[$row['parentid']];
} else {
$categoryParentsCache[$row['parentid']] = $row['parents'] = iwp_categories::getInstance()->GetParentsArray($row['categoryid']);
}
}
$baseUrl = $this->urls->GetUrl($this->Get('datatype'), $row['rowid'], $row);
$listResultArray['Url'] = iwp_htmlspecialchars($this->urls->GetURLPrepend(true,false) . $baseUrl);
}
if(isset($row['name'])){
$listResultArray['Title'] = iwp_htmlspecialchars($row['name']);
}
if(isset($row['views'])){
$listResultArray['Views'] = $row['views'];
}
if(isset($row['title'])){
$listResultArray['Title'] = iwp_htmlspecialchars($row['title']);
}
if(isset($row['summary'])){
$listResultArray['Summary'] = $row['summary'];
}
if(isset($row['content'])){
$listResultArray['Content'] = $row['content'];
}
if(empty($row['summary']) && !empty($row['content']) && preg_match('#<!--[ ]*pagebreak[ ]*-->#ism', $row['content'])){
$split = preg_split('#<!--[ ]*pagebreak[ ]*-->#ism', $row['content'], -1, PREG_SPLIT_NO_EMPTY);
$listResultArray['Summary'] = $split[0];
$listResultArray['Content'] = $split[1];
}elseif(empty($row['summary']) && !empty($row['content'])){
if(strlen($row['content']) < 250){
$listResultArray['Summary'] = $row['content'];
}else{
$listResultArray['Summary'] = substr(strip_tags($row['content']), 0, 250)."...";
}
}
if (isset($listResultArray['Summary'])) {
$listResultArray['Summary'] = iwp_content::getInstance()->DecodeSiteURLs($listResultArray['Summary']);
}
if (isset($listResultArray['Content'])) {
$listResultArray['Content'] = iwp_content::getInstance()->DecodeSiteURLs($listResultArray['Content']);
}
if(isset($row['name_singular'])){
$listResultArray['Contenttypename'] = iwp_htmlspecialchars($row['name_singular']);
$listResultArray['hasContentTypeName'] = true;
}else{
$listResultArray['hasContentTypeName'] = false;
$listResultArray['Contenttypename'] = '';
}
if(isset($row['startdate'])){
if($this->Get('datatype') != 'content' || ($this->Get('datatype') == 'content' && in_string('field_startdate', $row['modulelist']))) {
$listResultArray['Publishdatewithlabel'] = sprintf(GetLang('ListPublishedOnDate'), iwp_LongDate(strtotime($row['startdate'])));
$listResultArray['Publishdate'] = iwp_LongDate(strtotime($row['startdate']));
$listResultArray['Publishdatemonthshort'] = date('M', strtotime($row['startdate']));
$listResultArray['Publishdatemonthlong'] = date('F', strtotime($row['startdate']));
$listResultArray['Publishdatemonthnumber'] = date('n', strtotime($row['startdate']));
$listResultArray['Publishdatedaynumber'] = $listResultArray['Publishdatedaynum'] = date('j', strtotime($row['startdate']));
$listResultArray['Publishdateyear'] = $listResultArray['Publishdateyearlong'] = date('Y', strtotime($row['startdate']));
$listResultArray['Publishdateyearshort'] = date('y', strtotime($row['startdate']));
$listResultArray['Publishdatemonthnumberwithzero'] = date('m', strtotime($row['startdate']));
}
}
if(isset($row['contentid']) && isset($row['parentid']) && isset($row['contentparentid']) && $row['parentid'] > 0){ // is it a content item
// it's a sub page, get the URL of the actual article
$q = $this->db->Query("select * from ". IWP_TABLE_CONTENT . " where parentid=".$row['parentid'] ." AND contentid!=".$row['parentid'] ." order by `pagesortorder` asc");
$pages = array();
$page = 2;
while(($order = $this->db->Fetch($q))) {
if($row['contentid'] == $order['contentid']) {
break;
}
$page++;
}
$data = $this->db->FetchQuery('select * from ' . IWP_TABLE_URLS .' where assoctype="content" and associd='.(int)$row['parentid']);
$listResultArray['Url'] = $this->urls->GetURLPrepend(true,false) . $data['urlpath'] . '?page=' . $page;
}
if(isset($row['author'])){
$authorList = iwp_user::getInstance()->GetAuthorNameListByIdList($row['author']);
if($authorList === false || strlen($authorList) == 0){
$listResultArray['hasAuthors'] = false;
}else{
$listResultArray['Authors'] = sprintf(GetLang('ListWrittenBy'), $authorList);
$listResultArray['hasAuthors'] = true;
}
}
if(isset($row['categorylist'])){
$catList = iwp_categories::getInstance()->GetCategoryListByIdList($row['categorylist']);
if($catList === false){
$listResultArray['hasCategories'] = false;
}else{
$listResultArray['Categories'] = $catList;
$listResultArray['hasCategories'] = true;
}
}
$setVar = false;
$listResultArray['hasChildren'] = false;
$listResultArray['subCats'] = array();
if (!iwp_event::trigger(new iwp_event_lists_dynamicoutput($this, $listResultArray))) {
continue;
}
if($listResultArray['loadModules'] && $this->Get('datatype') == 'content' && $row['rowid'] > 0 && isset($row['modulelist'])) {
if (!isset(iwp_lists::$_content_type_active_modules[$row['typeid']])) {
// build a list of active modules for each encountered contenttype, keeping a runtime cache so we only check each type once per page load
$moduleList = array();
foreach ($fieldList as $fieldName) {
if (substr($fieldName, 0, 7) == 'module_') {
$moduleName = substr($fieldName, 7);
$module = $modules->GetModule($moduleName);
if (is_object($module) && $module->GetActiveId()) {
$moduleList[] = $moduleName;
}
}
}
iwp_lists::$_content_type_active_modules[$row['typeid']] = $moduleList;
} else {
// the list we want is in the cache, use that instead
$moduleList = iwp_lists::$_content_type_active_modules[$row['typeid']];
}
foreach($moduleList as $k=>$moduleName) {
$module = $modules->GetModule($moduleName);
// if the variable that the module wants to append to doesn't exist in this list template, don't call the module's function
if(!in_string('{$row1.' . $module->GetListAppendSection() . '}', $listTemplateFileContents)) {
continue;
}
$setVar = $module->LoadListOutput($row['rowid']);
if($setVar === false){
continue;
}
$setVar['lang'] = $module->lang->GetLangVars();
$setVar['urlToModule'] = IWP_MODULES_URI . '/' . $moduleName;
$this->template->Assign($moduleName, $setVar, false);
$this->template->Assign('row', $listResultArray, false);
if(!isset($listResultArray[$module->GetListAppendSection()])){
$listResultArray[$module->GetListAppendSection()] = '';
}
if(!is_null($module->GetListTemplateName()) && strlen($module->GetListTemplateName()) > 0){
$listResultArray[$module->GetListAppendSection()] .= $this->template->ParseTemplate($module->GetListTemplateName(), true, $moduleName);
}
}
}
$listResultArray['children'] = array();
if($this->Get('datatype') == 'content') {
if($row['contentparentid'] == 0) {
$outputList[$row['rowid']] = $listResultArray;
$mapping[$row['rowid']] = &$outputList[$row['rowid']];
} else {
if(!isset($mapping[$row['contentparentid']])) {
$outputList[$row['rowid']] = $listResultArray;
$mapping[$row['rowid']] = &$outputList[$row['rowid']];
}else{
$mapping[$row['contentparentid']]['children'][$row['rowid']] = $listResultArray;
$mapping[$row['rowid']] = &$mapping[$row['contentparentid']]['children'][$row['rowid']];
}
}
}elseif($this->Get('datatype') == 'categories') {
if($row['parentid'] == 0) {
$outputList[$row['rowid']] = $listResultArray;
$mapping[$row['rowid']] = &$outputList[$row['rowid']];
} else {
if(!isset($mapping[$row['parentid']])) {
$outputList[$row['rowid']] = $listResultArray;
$mapping[$row['rowid']] = &$outputList[$row['rowid']];
}else{
$mapping[$row['parentid']]['children'][$row['rowid']] = $listResultArray;
$mapping[$row['rowid']] = &$mapping[$row['parentid']]['children'][$row['rowid']];
}
}
}else{
$outputList[$row['rowid']] = $listResultArray;
}
$listResultArray = array();
}
if($rowCount == 0){
return null;
}
$outputHTML = $this->GetListHTML($outputList, $this->Get('title'), $section, $this->Get('cssclasses'), $displayStyle);
if(!$this->ignoreCache){
$this->cache->WriteCache($cacheId, $outputHTML);
}
return $outputHTML;
}
/**
* GenerateSortingCache
* Re-generates and saves the nested-tree structure sorting cache for content
*
* @param int $parentId Optional. Default 0. If a parent id is given, only children of this parent will have their cache generated, otherwise the process will begin with all root-level categories. The parent record itself is untouched. This is used internally for recursive functionality.
* @param string $parentKey Optional. Default blank. The sorting key of the parent specified by $parentId. This is used internally for recursive functionality.
* @return void Returns nothing
*/
public function GenerateSortingCache ($parentId = 0, $parentKey = '', $sortField = 'sortorder', $sortDirection = 'asc', $listQuery, $listId=false) {
$parentId = (int)$parentId;
$varName = "contentid";
$dataType = "content";
if(in_string('/*%%categoryparentid%%*/', $listQuery)) {
//$sql = str_replace('/*%%categoryparentid%%*/', 'c.parentid = ' . $parentId .' and ', $listQuery);
$varName = "categoryid";
$dataType = "categories";
$sql = str_replace('select SQL_CALC_FOUND_ROWS *', 'select c.categoryid as `pkey`, c.parentid as `parentid`', $listQuery);
}elseif(in_string('/*%%contentparentid%%*/', $listQuery)) {
//$sql = str_replace('/*%%contentparentid%%*/', 'c.contentparentid = ' . $parentId .' and ', $listQuery);
$sql = str_replace('select SQL_CALC_FOUND_ROWS *', 'select c.contentid as `pkey`, c.contentparentid as `parentid`', $listQuery);
}
$sql = str_replace('/*%%contentorderby%%*/', ' ORDER BY `' . $this->db->Quote($sortField) . '` ' . $this->db->Quote($sortDirection), $sql);
$sql = $this->InsertVisibility($sql, $dataType);
if($listId === false) {
$listId = (int)$this->GetId();
}else{
$listId = (int)$listId;
}
return $this->rebuildSortCacheTree($sql, $listId, $parentId);
}
public function rebuildSortCacheTree ($sql, $listId, $parentId=0) {
$result = $this->db->Query($sql);
if ($result === false) {
return false;
}
$rows = array();
// larger sites need memory upto around 64MB, increasing to 96MB to prevent most chances of 'out of memory errors'
@ini_set('memory_limit', '96M');
//
// build a flat list of rows from the database and add some values we need for processing
while ($row = $this->db->Fetch($result)) {
$row['childnodes'] = array();
$row['sortcache'] = '';
$rows[] = $row;
}
//
// fill in the parent-child structure using a temporary array using database table pkey values as the array key
$structure = array();
foreach ($rows as &$row) {
$structure[$row['pkey']] = &$row;
}
foreach ($rows as &$row) {
if ((string)$row['parentid'] !== (string)$parentId) {
$structure[$row['parentid']]['childnodes'][] = &$row;
}
}
//unset($rows); // this array isn't needed any more
//
// make a final structure array that doesn't include every row at the root level
$tree = array();
foreach ($structure as &$row) {
if(!isset($row['parentid'])) {
// if the parent id isn't set, the parent doesn't exist, i.e. a missing piece of content or category
// this could be an actual missing row, or the that the visibility has hidden it. If a parent is hidden, so are it's children (in menus at least)
continue;
}
if ((string)$row['parentid'] === (string)$parentId) {
$tree[] = &$row;
}
}
//
// call the recursive value populating function
$this->populateSortCacheValues($tree);
//
// update all left/right values from the database
$sqlValues = array();
foreach ($structure as &$row) {
if(isset($row['pkey']) && isset($row['sortcache'])) {
$sqlValues[] = '(' . $listId .',' . (int)$row['pkey'] . ',"' . $row['sortcache'] . '")';
}
}
// clean up some memory space
unset($tree);
unset($structure);
unset($rows);
if(sizeof($sqlValues) > 0) {
$sql = 'INSERT INTO ' . IWP_TABLE_LIST_SORTCACHE . ' (listid,contentid,sortcache) VALUES ' . implode(',', $sqlValues);
if ($this->db->Query($sql) === false) {
return false;
}
}
return true;
}
private function populateSortCacheValues (&$tree, $parentSortCache = '') {
$counter = 0;
foreach ($tree as &$node) {
if (!empty($parentSortCache)) {
$sortcache = $parentSortCache . '.' . iwp_admin_categories::Int2Sorting($counter);
} else {
$sortcache = iwp_admin_categories::Int2Sorting($counter);
}
$node['sortcache'] = $sortcache;
$this->populateSortCacheValues($node['childnodes'], $sortcache);
++$counter;
}
}
public function ClearSortingCacheByListId($listId=0) {
if(!is_array($listId)) {
$listId = array($listId);
}
return $this->db->Query('DELETE FROM ' . IWP_TABLE_LIST_SORTCACHE . ' WHERE listid IN (' . implode(',', $listId) . ')');
}
public function RegenerateSortingCacheByListId($listIds, $updateCount = true){
if(!is_array($listIds)) {
$listIds = array($listIds);
}
$this->ClearSortingCacheByListId($listIds);
foreach ($listIds as $listId) {
$list = new iwp_lists();
if(!$list->Load($listId)) {
return;
}
$generatedQuery = $list->GenerateQuery(true);
$generatedQuery['orderby'] = '/*%%contentorderby%%*/';
list($whereFilters, $limit, $orderby) = $list->LoadFilters();
$list->GenerateSortingCache(0,'', $orderby['fieldname'], $orderby['value'], implode(' ', $generatedQuery), $listId);
if($updateCount) {
$saveGeneratedQuery = $list->GenerateQuery();
switch($list->get('datatype')) {
case 'categories':
$saveGeneratedQuery = str_replace('/*%%list_sortcache_join%%*/', 'left join '. IWP_TABLE_LIST_SORTCACHE .' as lc on lc.contentid=c.categoryid', $saveGeneratedQuery);
break;
case 'content':
default:
$saveGeneratedQuery = str_replace('/*%%list_sortcache_join%%*/', 'left join '. IWP_TABLE_LIST_SORTCACHE .' as lc on lc.contentid=c.contentid', $saveGeneratedQuery);
break;
}
$saveGeneratedQuery = str_replace('/*%%list_sortcache_sortfield%%*/', 'order by lc.sortcache asc', $saveGeneratedQuery);
// count how many items this list has
$list->db->Query($list->LoadQuery(false, $saveGeneratedQuery));
$itemCountResult = $list->db->FetchQuery('select found_rows() as found_rows');
$itemCount = 0;
if(isset($itemCountResult['found_rows'])){
$itemCount = (int)$itemCountResult['found_rows'];
}
// reload the list as the sorting cache may have modified the data
$list->Load($listId);
$list->Set('itemcount', (int)$itemCount);
$list->Save();
}
}
}
/**
* This function takes the ID number of a content item, category or user and deletes any list cache files that contain that ID number within the displayed list.
*
* @param integer $itemId The ID number of the item that should have all its caches deleted, this is used to check in the lists cache and delete any list cache that contains this item ID within the list.
* @param string $dataType The type of content that is being refreshed, e.g. 'categories' or 'content'
*
* @return void Doesn't return anything
*/
public function RegenerateSortingCacheById($itemId, $dataType = 'content'){
if(!is_array($itemId)) {
$itemId = array($itemId);
}
$listsToReset = array();
$this->cache->ReadListsCacheFile();
if(!$this->cache->ConfirmDir('lists')){
return false;
}
foreach($itemId as $thisContentId) {
if (!isset($this->cache->listsTypes[$dataType])) {
continue;
}
foreach ($this->cache->listsTypes[$dataType] as $listId) {
if(!isset($this->cache->listsCache[$listId]) || !is_array($this->cache->listsCache[$listId])){
continue;
}
if(in_array($thisContentId, $this->cache->listsCache[(int) $listId])){
// clear the cache file for this list
$listsToReset[] = $listId;
}
}
}
$listsToReset= array_unique($listsToReset);
foreach($listsToReset as $listId) {
$list = new iwp_lists();
if(!$list->Load($listId)) {
continue;
}
$generatedQuery = $list->GenerateQuery(true);
$generatedQuery['orderby'] = '/*%%contentorderby%%*/';
list($whereFilters, $limit, $orderby) = $list->LoadFilters();
$list->ClearSortingCacheByListId($list->getId());
$list->GenerateSortingCache(0,'', $orderby['fieldname'], $orderby['value'], implode(' ', $generatedQuery));
}
}
/**
* This is a function used by function which outputs a list. It determines which template file to use based on the section and displayStyle passed in.
*
* @param array $outputList An array of list items that should be passed into the template.
* @param string $title The title of the list.
* @param string $section The section inwhich the list appears, i.e. one of top, middle, left, right or bottom
* @param string $cssClasses Any additional CSS classes that should be applied to the list's parent tag.
* @param string $displayStyle The list style to use which corresponds to the blockStyle="" attribute in the styleguide.
*
* @return string The parsed template for for the current list.
*/
public function GetListHTML($outputList, $title, $section, $cssClasses='',$displayStyle = null){
$this->template->Assign('OutputList', $outputList, false);
$this->template->Assign('blockTitle', $title);
$this->template->Assign('cssclasses', $cssClasses);
if($displayStyle !== null && is_file(IWP_CACHE_SECTION_HTML_PATH .'/list_'.$displayStyle.'.html')){
$outputHTML = $this->template->ParseSection('list_'.$displayStyle, true);
}elseif(is_file(IWP_CACHE_SECTION_HTML_PATH .'/list_'.iwp_strtolower($section).'_standard.html')){
$outputHTML = $this->template->ParseSection('list_'.iwp_strtolower($section).'_standard', true);
}elseif(is_file(IWP_CACHE_SECTION_HTML_PATH .'/list_'.iwp_strtolower($section).'_linked_title.html')){
$outputHTML = $this->template->ParseSection('list_'.iwp_strtolower($section).'_linked_title', true);
}else{
$outputHTML = '';
}
return $outputHTML;
}
/**
* This function retrieves the lists which have rssfeeds enabled.
*
* @return array An array of list DB information that have RSS feeds.
*/
public function GetListsRSSFeedList(){
$query = $this->db->Query('select * from ' . IWP_TABLE_LISTS . ' where rssfeed="yes" order by title asc');
$feedList = array();
while($row = $this->db->Fetch($query)){
$safeName = substr($row['title'], 0, 15);
$url = $this->urls->GetStaticUrl('viewrss', array('name'=>$safeName, 'idnumber'=>$row['listid']));
$feedList[] = array('name'=> $row['title'], 'url'=>$url, 'level'=>0);
}
return $feedList;
}
/**
* This function gets the formatted array ready for RSS output and returns it.
*
* @return array List read for RSS
*/
public function GetRSSofDynamicListOutput(){
$query = $this->LoadQuery();
$resource = $this->db->Query($query);
if(in_string('SQL_CALC_FOUND_ROWS', $query)){
$this->foundRows = (int)$this->db->FetchOne("SELECT found_rows()");
}
$returnArray = array();
$rowCount = 0;
while($row = $this->db->Fetch($resource)) {
++$rowCount;
$returnArray[$rowCount] = array('title'=>'', 'link'=>'', 'enclosure'=>false, 'description'=>'', 'lastBuildDate'=>time(), 'author'=>'');
if ($this->Get('datatype') == 'content' && isset($row['modulelist'])) {
$contenttypes = iwp_contenttypes::getInstance();
$fieldList = $contenttypes->FlattenFieldsArray($contenttypes->ExplodeFields($row['modulelist']));
// remove unused fields
// example: old summary content if a content type once had the summary field but no longer has that field assigned
if (!in_array('field_summary', $fieldList)) {
unset($row['summary']);
}
}
if(isset($row['title'])){
$returnArray[$rowCount]['title'] = $row['title'];
}elseif(isset($row['name'])){
$returnArray[$rowCount]['title'] = $row['name'];
}
if(!isset($row['rowid'])){
if(isset($row['contentid'])){
$row['rowid'] = $row['contentid'];
}elseif(isset($row['userid'])){
$row['rowid'] = $row['userid'];
}elseif(isset($row['categoryid'])){
$row['rowid'] = $row['categoryid'];
}elseif(isset($row['commentid'])){
$row['rowid'] = $row['commentid'];
}
}
if(isset($row['urlpath'])){
$returnArray[$rowCount]['link'] = iwp_config::Get('siteURL') . $row['urlpath'];
}else{
$returnArray[$rowCount]['link'] = iwp_config::Get('siteURL') . $this->urls->GetUrl($this->Get('datatype'), $row['rowid'], $row);
}
if(isset($row['summary']) && $row['summary']){
$returnArray[$rowCount]['description'] = $row['summary'];
}elseif(isset($row['description']) && $row['description']){
$returnArray[$rowCount]['description'] = $row['description'];
}elseif(isset($row['content'])){
if(strlen($row['content']) < 250){
$returnArray[$rowCount]['description'] = $row['content'];
}else{
$returnArray[$rowCount]['description'] = substr(strip_tags($row['content']), 0, 250)."...";
}
}
$returnArray[$rowCount]['description'] = iwp_content::getInstance()->DecodeSiteURLs($returnArray[$rowCount]['description']);
if(isset($row['startdate'])){
$returnArray[$rowCount]['lastBuildDate'] = $row['startdate'];
}else{
$returnArray[$rowCount]['lastBuildDate'] = time();
}
if(isset($row['author'])){
$authorList = iwp_user::getInstance()->GetAuthorNameListByIdList($row['author'], true);
if($authorList === false){
$returnArray[$rowCount]['author'] = 'none';
}else{
$returnArray[$rowCount]['author'] = $authorList;
}
}
}
return $returnArray;
}
/**
* This function gets the formatted array ready for RSS output and returns it.
*
* @return array List read for RSS
*/
public function GetRSSofStaticListOutput(){
$returnArray = array();
$rowCount = 0;
$query = $this->db->Query('select * from ' . IWP_TABLE_LIST_LINKS .' where listid=' . $this->GetId() .' order by sortorder asc');
while(($row = $this->db->Fetch($query))){
++$rowCount;
$returnArray[$rowCount] = array('title'=>'', 'link'=>'', 'enclosure'=>false, 'description'=>'', 'lastBuildDate'=>time(), 'author'=>'');
$returnArray[$rowCount]['link'] = $row['url'];
$returnArray[$rowCount]['title'] = $row['text'];
$returnArray[$rowCount]['description'] = $row['text'];
$returnArray[$rowCount]['lastBuildDate'] = time();
$returnArray[$rowCount]['author'] = 'none';
}
return $returnArray;
}
/**
* This function gets the formatted array ready for RSS output and returns it.
*
* @return array List read for RSS
*/
public function GetRSSofRSSListOutput(){
$returnArray = array();
$rowCount = 0;
if(!$this->GetFeed($this->Get('rssurl'))){ // sets $this->RSSFeed
return '';
}
$max = 20;
$count = 0;
foreach($this->RSSFeed->channel->item as $k=>$obj){
++$rowCount;
$returnArray[$rowCount] = array('title'=>'', 'link'=>'', 'enclosure'=>false, 'description'=>'', 'lastBuildDate'=>time(), 'author'=>'');
$returnArray[$rowCount]['link'] = (string)$obj->link;
$returnArray[$rowCount]['title'] = (string)$obj->title;
$returnArray[$rowCount]['description'] = (string)$obj->description;
$returnArray[$rowCount]['lastBuildDate'] = (string)$obj->pubDate;
$returnArray[$rowCount]['author'] = (string)$obj->author;
if($rowCount >= $max){
break;
}
}
return $returnArray;
}
/**
* This function gets the query from the cache variable or regenerates it and replaces any placeholders
*
* @param boolean $forceRefresh This determines whether the query should be forced to be regenerated or not. True to regenerate, false (default) to use the cache if it exists
* @param string $useThisQuery This parameter defines a specific query to use, rather than the once associated with the current class instance.
* @param string $dataType The datatype to use when calling InsertVisibility() if needed.
* @param string $options A serialised string of the options for the current list. If it is not passed in, the options from the current instance will be used.
* @param integer $listId The ID number of the current list. If it is not passed in, the ID number from the current instance will be used.
*
* @return string The resulting query to run against the database
*/
public function LoadQuery($forceRefresh=false, $useThisQuery='', $dataType=null, $options=null, $listId=null){
if(!empty($useThisQuery)){
$QueryCache = $useThisQuery;
}else{
$QueryCache = $this->Get('querycache');
if($forceRefresh || !$QueryCache ){
$Update = array();
$Update['querycache'] = $this->GenerateQuery();
$this->db->UpdateQuery(IWP_TABLE_LISTS, $Update, 'listid='.$this->GetId());
$QueryCache = $Update['querycache'];
}
}
if(in_string('{categoryid}', $QueryCache)){
$QueryCache = str_replace('{categoryid}', iwp_categories::getInstance()->GetId(), $QueryCache);
}
if(in_string('{contentid}', $QueryCache)){
$QueryCache = str_replace('{contentid}', iwp_content::getInstance()->GetId(), $QueryCache);
}
if(in_string('{userid}', $QueryCache)){
$QueryCache = str_replace('{userid}', iwp_user::getInstance()->GetId(), $QueryCache);
}
if (in_string('/*%%listid%%*/', $QueryCache)) {
if(is_null($listId)) {
$listId = $this->getId();
}
if(is_null($options)) {
$options = @unserialize($this->get('options'));
} else {
$options = @unserialize($options);
}
$groupby = '';
$depth = 1;
if(isset($options['SubContentListDepth']) && ($options['SubContentListDepth'] <= 3 && $options['SubContentListDepth'] >= 1)) {
$depth = (int)$options['SubContentListDepth'];
}elseif(isset($options['SubcatListDepth']) && ($options['SubcatListDepth'] <= 3 && $options['SubcatListDepth'] >= 1)) {
$depth = (int)$options['SubcatListDepth'];
}
$depth = $depth - 1;
// count the number of dots/fullstops/periods to determine how many content levels to display.
$groupby = ' (LENGTH(lc.sortcache) - LENGTH(REPLACE(lc.sortcache, ".", ""))) <= ' . $depth . ' ';
$QueryCache = str_replace('/*%%listid%%*/', 'lc.listid=' . $listId . ' and ' . $groupby . ' and ', $QueryCache);
}
if (in_string('/*%%visibility%%*/', $QueryCache)) {
if(!is_null($dataType)) {
$QueryCache = $this->InsertVisibility($QueryCache, $dataType);
} else {
$QueryCache = $this->InsertVisibility($QueryCache);
}
}
return $QueryCache;
}
public function InsertVisibility($query, $dataType=false) {
if (!in_string('/*%%visibility%%*/', $query)) {
return $query;
}
$visibility = '';
if(!$dataType) {
$dataType = $this->Get('datatype');
}
switch ($dataType) {
case 'categories':
$visibility = 'c.hidefrommenu = 0';
break;
case 'users':
// there's no front end user lists yet and no user visibility field, but user visibility can be added here when there is
$visibility = 'u.status = 1';
break;
case 'content':
// the list may span several content types so the visibility checks must check for fields in the content type on the database-side, not php-side
/*$visibility .= " IF(ct.modulelist LIKE '%field_visible%', c.visible, 1) = 1";
$visibility .= " and IF(ct.modulelist LIKE '%field_hidefrommenu%', c.hidefrommenu, 0) = 0";
$visibility .= " and IF(ct.modulelist LIKE '%field_startdate%', c.startdate, now()) <= now()";
$visibility .= " and IF(ct.modulelist LIKE '%field_expiryoptions%' AND c.enableexpiry = 1, c.expirydate, now()) >= now()";
$visibility .= " and IF(ct.modulelist LIKE '%field_status%', c.status, 'approved') = 'approved'";*/
$visibility .= " IF(field_visible, c.visible, 1) = 1";
$visibility .= " and IF(field_hidefrommenu, c.hidefrommenu, 0) = 0";
$visibility .= " and IF(field_startdate, c.startdate, now()) <= now()";
$visibility .= " and IF(field_expiryoptions AND c.enableexpiry = 1, c.expirydate, now()) >= now()";
$visibility .= " and IF(field_status, c.status, 'approved') = 'approved'";
break;
}
return str_replace('/*%%visibility%%*/', '('. $visibility .') AND ', $query);
}
/**
* This function gets the formatted HTML list for an RSS list and returns it
*
* @return string The formatted HTML
*
* @OutputListById()
*/
public function GetRssListOutput($section, $displayStyle){
$outputHTML = '';
$outputList = array();
if(!$this->GetFeed($this->Get('rssurl'))){ // sets $this->RSSFeed
return '';
}
list($whereFilters, $limit, $orderby) = $this->LoadFilters();
if($this->Get('homepage') == 'yes'){
$homepage = array();
$homepage['Url'] = iwp_config::Get('siteURL') .'/';
$homepage['Title'] = iwp_htmlspecialchars($this->lang->Get('HomePage'));
$outputList[] = $homepage;
}
if(!isset($limit['value'])){
$limit['value'] = 10;
}
$max = (int)$limit['value'];
$count = 0;
foreach($this->RSSFeed->channel->item as $k=>$obj){
++$count;
$listResultArray = array();
foreach($obj as $k2=>$val){
$listResultArray[$k2] = (string)$val;
}
$listResultArray['Url'] = (string)$obj->link;
$listResultArray['Title'] = iwp_htmlspecialchars((string)$obj->title);
$listResultArray['Summary'] = (string)$obj->description;
$listResultArray['Content'] = (string)$obj->description;
$listResultArray['Target'] = '_blank';
$listResultArray['subCats'] = array();
$outputList[] = $listResultArray;
if($count >= $max){
break;
}
}
if((int)count($this->RSSFeed->channel->item) != (int)$this->Get('itemcount')){
$this->Set('itemcount', (int)count($this->RSSFeed->channel->item));
$this->Save();
}
$outputHTML = $this->GetListHTML($outputList, $this->Get('title'), $section, $this->Get('cssclasses'), $displayStyle);
return $outputHTML;
}
/**
* This function gets the formatted HTML list for a static list and returns it
*
* @return string The formatted HTML
*
* @OutputListById()
*/
public function GetStaticListOutput($section, $displayStyle){
$outputHTML = '';
$outputList = array();
if($this->Get('homepage') == 'yes'){
$homepage = array();
$homepage['Url'] = iwp_config::Get('siteURL') .'/';
$homepage['Title'] = iwp_htmlspecialchars($this->lang->Get('HomePage'));
$outputList[] = $homepage;
}
$query = $this->db->Query('select * from ' . IWP_TABLE_LIST_LINKS .' where listid=' . $this->GetId() .' and parentid=0 order by sortorder asc');
while(($row = $this->db->Fetch($query))){
$listResultArray['Url'] = str_replace('{siteURL}', iwp_config::Get('siteURL'), $row['url']);
$listResultArray['Title'] = iwp_htmlspecialchars($row['text']);
if($row['target'] == "same"){
$listResultArray['Target'] = "_self";
}else{
$listResultArray['Target'] = "_blank";
}
$listResultArray['hasChildren'] = false;
$listResultArray['children'] = array();
$countChildren = 0;
// check for children
$childQuery = 'select count(*) from ' . IWP_TABLE_LIST_LINKS .' where listid=' . $this->GetId() .' and parentid='.$row['itemid'].' order by sortorder asc';
$countChildren = $this->db->FetchOne($childQuery);
if($countChildren > 0) {
$listResultArray['hasChildren'] = true;
$listResultArray['children'] = array();
$query2 = $this->db->Query('select * from ' . IWP_TABLE_LIST_LINKS .' where listid=' . $this->GetId() .' and parentid='.$row['itemid'].' order by sortorder asc');
while($childRow = $this->db->Fetch($query2)) {
$subRow = array();
$subRow['Url'] = str_replace('{siteURL}', iwp_config::Get('siteURL'), $childRow['url']);
$subRow['Title'] = iwp_htmlspecialchars($childRow['text']);
if($childRow['target'] == "same"){
$subRow['Target'] = "_self";
}else{
$subRow['Target'] = "_blank";
}
$subRow['hasChildren'] = false;
$subRow['children'] = array();
$subChildQuery = 'select count(*) from ' . IWP_TABLE_LIST_LINKS .' where listid=' . $this->GetId() .' and parentid='.$childRow['itemid'].' order by sortorder asc';
$subChildCount = $this->db->FetchOne($childQuery);
if($subChildCount > 0) {
$subRow['hasChildren'] = true;
$subRow['children'] = array();
$query3 = $this->db->Query('select * from ' . IWP_TABLE_LIST_LINKS .' where listid=' . $this->GetId() .' and parentid='.$childRow['itemid'].' order by sortorder asc');
while($subChildResult = $this->db->Fetch($query3)) {
$subChildRow = array();
$subChildRow['Url'] = str_replace('{siteURL}', iwp_config::Get('siteURL'), $subChildResult['url']);
$subChildRow['Title'] = iwp_htmlspecialchars($subChildResult['text']);
if($subChildResult['target'] == "same"){
$subChildRow['Target'] = "_self";
}else{
$subChildRow['Target'] = "_blank";
}
$subChildRow['hasChildren'] = false;
$subChildRow['children'] = array();
$subRow['children'][] = $subChildRow;
}
}
$listResultArray['children'][] = $subRow;
}
}
$outputList[] = $listResultArray;
}
$outputHTML = $this->GetListHTML($outputList, $this->Get('title'), $section, $this->Get('cssclasses'), $displayStyle);
return $outputHTML;
}
/**
* This function gets an array of all the lists in the system in no particular order
*
* @return array It returns an associative array with the list ID as the key and the table row data as the value (array)
*/
public function GetListArray(){
$query = 'select * from ' . IWP_TABLE_LISTS .' order by title asc';
$resource = $this->db->Query($query);
$return = array();
while(($row = $this->db->Fetch($resource))){
$return[$row['listid']] = $row;
}
return $return;
}
/**
* This function takes an RSS feed url or path and reads it in or reads the cache
*
* @param string $feedURL The URL/path to the RSS feed to read and validate
*
* @return boolean True if the fee was read in, false otherwise
*/
public function GetFeed($feedURL){
$cacheId = md5($feedURL);
$this->cache->SetDir('rss_in');
if(!$this->cache->HasExpired($cacheId)){
if($this->ValidateFeed($this->cache->GetFullFileName($cacheId))) {
return true;
}
return false;
}
if($this->ValidateFeed($feedURL)){
// write to the cache
return $this->cache->WriteCache($cacheId, $this->RSSFeed->asFullXml());
}
return false;
}
/**
* This function deletes any associations that a list has
*
* @param integer $id The ID number of the list to be deleted. If this is not passed in, $this->GetId() will be used.
*
* @return boolean True if the list and associations were deleted, false otherwise
*/
public function Delete($id=null){
if(parent::Delete($id)) {
$resultFilters = $this->db->Query('delete from `' . IWP_TABLE_LIST_FILTERS . '` where listid='.(int)$id);
$resultLinks = $this->db->Query('delete from `' . IWP_TABLE_LIST_LINKS. '` where listid='.(int)$id);
return true;
}
return false;
}
/**
* This function is used to ensure that a feed URL that is entered points to a valid RSS feed.
* This function just returns boolean true/false unlike RemoteValidateFeed() which echos a message and dies
*/
public function ValidateFeed($feed){
if(substr($feed,0, 4) == 'http'){
IWP::GetLib('class.remoteopener');
$remote = new connect_remote();
if(!$remote->CanOpen()){
return false;
}
if($feed == "http://" || $feed == "https://" || (substr($feed,0,strlen("http://")) !== "http://" && substr($feed,0,strlen("https://")) !== "https://")){
// don't even bother trying to open it
return false;
}
$data = '';
$remote->Open($feed, $data);
if($this->valid->IsBlank($data)){
return false;
}
}elseif(substr($feed,0,strlen(IWP_BASE_PATH)) == IWP_BASE_PATH && !in_string('..', $feed)){
$data = file_get_contents($feed);
}else{
return false; // not anything valid
}
try{
@$this->RSSFeed = new SimpleXML($data);
}catch (Exception $e) {
return false;
}
if ($this->RSSFeed->channel->item) {
return true;
}
return false;
}
public function AddFilterOrderBy($fieldName, $value='desc'){
// save the order by
$Insert = array();
$Insert['listid'] = $this->GetId();
$Insert['filtertype'] = 'orderby';
$Insert['fieldname'] = $fieldName;
$Insert['value'] = $value;
$this->db->InsertQuery(IWP_TABLE_LIST_FILTERS, $Insert);
}
public function AddFilterLimit($value, $operator='total'){
// save the limit
$Insert = array();
$Insert['listid'] = $this->GetId();
$Insert['filtertype'] = 'limit';
$Insert['value'] = max((int)$value, 1);
$Insert['operator'] = $operator;
$this->db->InsertQuery(IWP_TABLE_LIST_FILTERS, $Insert);
}
public function AddFilterWhere($value, $fieldName, $operator){
// save the where
$Insert = array();
$Insert['listid'] = $this->GetId();
$Insert['filtertype'] = 'where';
$Insert['fieldname'] = $fieldName;
$Insert['value'] = $value;
$Insert['operator'] = $operator;
$this->db->InsertQuery(IWP_TABLE_LIST_FILTERS, $Insert);
}
/**
* This function generates the SQL query for a list of sibling content or category items, sends it to the list class and returns the formatted HTML list.
*
* @param string $title The title for the list
* @param integer $levels The number of content levels to display
* @param string $section The section of the page where this list appears
* @param string $contentTypes A CSV of content type ID's to allow in the list
* @param boolean $startFromParent Whether to start from the current content item page's ID or it's parent (i.e. display children or siblings)
*
* @return string The HTML to be output to the browser for this list.
*/
public function getNestedContentList($title, $levels, $section, $contentTypes='', $startFromParent=false) {
$contentId = (int)iwp_content::getInstance()->getId();
// Are we viewing a category or content item?
if($contentId < 1) {
$categoryId = (int)iwp_categories::getInstance()->getId();
if($categoryId < 1) {
return '';
}
if($startFromParent) {
$categoryId = (int)iwp_categories::getInstance()->get('parentid');
}
$sql = 'select /** iwp_lists::getNestedContentList - category **/ SQL_CALC_FOUND_ROWS *, c.categoryid as rowid, (select count(*) from '. IWP_TABLE_CATEGORIES .' cc where cc.parentid = c.categoryid and cc.hidefrommenu=0) as childcount from '.IWP_TABLE_CATEGORIES.' c where c.parentid=' . $categoryId . ' and c.hidefrommenu=0 order by c.sortcache';
$datatype = 'categories';
}else{
if($startFromParent) {
$contentId = (int)iwp_content::getInstance()->get('contentparentid');
}
$parentSortCache = $this->db->FetchOne('select sortcache from '. IWP_TABLE_LIST_SORTCACHE .' as lc1 where lc1.listid=0 AND lc1.contentid=' . $contentId);
$sql = 'select /** iwp_lists::getNestedContentList - content **/ SQL_CALC_FOUND_ROWS c.*, ct.*, '
. 'RIGHT(lc.sortcache, (LENGTH(lc.sortcache)-'.strlen( $parentSortCache ).')) as rightsort ' // the sortcache without the parent section
. 'from '.IWP_TABLE_CONTENT.' as c inner join '. IWP_TABLE_CONTENTTYPES .' as ct on ct.typeid = c.typeid left join '. IWP_TABLE_LIST_SORTCACHE .' as lc on lc.contentid=c.contentid '
. 'where /*%%visibility%%*/ '
. '(LEFT(lc.sortcache, ' . (strlen( $parentSortCache )+1) . ') = "' . $this->db->Quote($parentSortCache) . '.") ' // check that they have the parent's sortcache to ensure they are the correct child nodes
. 'and lc.listid=0 ';
if(!empty($contentTypes)) {
$sql .= 'and c.typeid IN (' . $contentTypes . ') ';
}
$sql .=
'having (LENGTH(rightsort) - LENGTH(REPLACE(rightsort, ".", ""))) <= ' .(int)$levels . ' ' // count the number of dots/fullstops/periods to determine how many content levels to display.
. 'order by lc.sortcache asc';
$datatype = 'content';
}
$lists = new iwp_lists;
$lists->Set('title', $title);
$contentList = $lists->OutputListByQuery($sql, null, $datatype, $section);
return $contentList;
}
/**
* This function generates the SQL query for a list of years (and months) to in the archive, sends it to the list class and returns the formatted HTML list.
*
* @param string $section The section of the page where this list appears
*
* @return string The HTML to be output to the browser for this list.
*/
public function getContentArchiveList($section) {
$outputHTML = '';
$outputList = array();
$sql = $this->InsertVisibility('select *, c.contentid as rowid, left(c.startdate, 4) as postyear from '.IWP_TABLE_CONTENT.' c left join '. IWP_TABLE_CONTENTTYPES .' as ct on c.typeid=ct.typeid where /*%%visibility%%*/ 1=1 group by postyear order by postyear desc', 'content');
$resource = $this->db->Query($sql);
$outputList = array();
while($thisRow = $this->db->Fetch($resource)) {
$listResultArray['Url'] = $this->urls->GetStaticUrl('archive', array('archive_year'=>$thisRow['postyear']));
$listResultArray['Title'] = $thisRow['postyear'];
$listResultArray['Target'] = "_self";
$listResultArray['hasChildren'] = false;
$listResultArray['children'] = array();
$monthSQL = $this->InsertVisibility('select *, c.contentid as rowid, left(c.startdate, 4) as postyear, substring(c.startdate, 6, 2) as postmonth from '.IWP_TABLE_CONTENT.' c left join '. IWP_TABLE_CONTENTTYPES .' as ct on c.typeid=ct.typeid where /*%%visibility%%*/ left(c.startdate, 4)="' . (int)$thisRow['postyear'] . '" group by postmonth order by postmonth asc ', 'content');
$monthResource = $this->db->Query($monthSQL);
while($thisMonthRow = $this->db->Fetch($monthResource)) {
$thisMonth = array (
'Title' => date('F', mktime(5,5,5,(int)$thisMonthRow['postmonth'], 5, $thisRow['postyear'])),
'Url' => $this->urls->GetStaticUrl('archive', array('archive_year'=>$thisRow['postyear'], 'archive_month'=>$thisMonthRow['postmonth'])),
'hasChildren' => false,
);
$listResultArray['hasChildren'] = true;
$listResultArray['children'][] = $thisMonth;
}
$outputList[] = $listResultArray;
}
$outputHTML = $this->GetListHTML($outputList, $this->lang->Get('ArchiveTitleDefault'), $section);
return $outputHTML;
}
/**
* Returns a granularity list for this class.
*
* @param Integer $total Total will be populated with number of rows found in query (by reference)
* @param Integer $page Page number of records to return
* @param String $filter Filter string, optional
* @return Array List of value/text pairs
*/
public static function getGranularityList (&$total, &$page, $filter = '')
{
$limitStart = ($page * IWP_PERMISSIONGRANULARITEMS_PER_PAGE) - IWP_PERMISSIONGRANULARITEMS_PER_PAGE;
$where = '';
if ($filter) {
$filter = '%'. self::getInstance()->db->Quote($filter) .'%';
$where = sprintf("WHERE (`title` LIKE '%s')", $filter);
}
$result = self::getInstance()->db->Query(sprintf("SELECT SQL_CALC_FOUND_ROWS listid AS `value`, `title` AS `text` FROM %s %s ORDER BY `title` LIMIT %d, %d", IWP_TABLE_LISTS, $where, $limitStart, IWP_PERMISSIONGRANULARITEMS_PER_PAGE));
$total = self::getInstance()->db->FetchOne('SELECT found_rows()');
$list = array();
if ($result) {
while ($row = self::getInstance()->db->Fetch($result)) {
$row['value'] = (int)$row['value'];
array_push($list, $row);
}
self::getInstance()->db->FreeResult($result);
}
return $list;
}
}
iwp_lists::$PermissionOptions = array(
'full' => new iwp_permissionoption(true, false, false),
'create' => new iwp_permissionoption(false, false, false),
'delete' => new iwp_permissionoption(true, false, false),
'edit' => new iwp_permissionoption(true, false, false)
);