Your IP : 216.73.216.43


Current Path : /home/c/b/e/cbequiperp/www/components/com_flexicontent/classes/helpers/
Upload File :
Current File : /home/c/b/e/cbequiperp/www/components/com_flexicontent/classes/helpers/db.php

<?php
defined( '_JEXEC' ) or die( 'Restricted access' );

use Joomla\String\StringHelper;
use Joomla\Utilities\ArrayHelper;
use Joomla\CMS\Table\Table;

/*
 * CLASS with common methods for handling interaction with DB
 */
class flexicontent_db
{
	/**
	 * Method to set value for custom field 's common data types (INTEGER, DECIMAL(65,15), DATETIME)
	 *
	 * @return string
	 * @since 1.5
	 */
	static function setValues_commonDataTypes($obj, $all=false)
	{
		$db = JFactory::getDbo();
		$query = 'UPDATE #__flexicontent_fields_item_relations'
			. ' SET value_integer = CAST(value AS SIGNED), value_decimal = CAST(value AS DECIMAL(65,15)), value_datetime = CAST(value AS DATETIME) '
			. (!$all ? ' WHERE item_id = ' . (int) $obj->item_id . ' AND field_id = ' . (int) $obj->field_id . ' AND valueorder = ' . (int) $obj->valueorder. ' AND suborder = ' . (int) $obj->suborder : '');
		$db->setQuery($query);
		$db->execute();
	}


	/**
	 * Method to verify a record has valid JSON data for the given column
	 *
	 * @return string
	 * @since 3.1
	 */
	static function check_fix_JSON_column($colname, $tblname, $idname, $id, & $attribs=null)
	{
		$db = JFactory::getDbo();

		// This extra may seem redudant, but it is to avoid clearing valid data, due to coding or other errors
		$db->setQuery('SELECT '.$colname.' FROM #__'.$tblname.' WHERE '.$idname.' = ' . $db->Quote($id));
		$attribs = $db->loadResult();

		try {
			$json_data = new JRegistry($attribs);
		}
		catch (Exception $e)
		{
			$attribs = '{}';
			$json_data = new JRegistry($attribs);
			$db->setQuery('UPDATE #__'.$tblname.' SET '.$colname.' = '.$db->Quote($attribs).' WHERE '.$idname.' = ' .  $db->Quote($id));
			$db->execute();
			$app = JFactory::getApplication();
			if ($app->isClient('administrator'))
			{
				$app->enqueueMessage('Cleared bad JSON COLUMN: <b>'.$colname.'</b>, DB TABLE: <b>'.$tblname.'</b>, RECORD: <b>'.$id.'</b>', 'warning');
			}
		}

		return $json_data;
	}


	/**
	 * Method to verify a workflow association exists for given record, and add it
	 *
	 * @return string
	 * @since 3.1
	 */
	static function assign_default_WF($pk, $record = null, $extension = 'com_content.article', $stage_id = 0)
	{
		$db = JFactory::getDbo();
		if (!FLEXI_J40GE || !$pk) return;

		// This extra may seem redudant, but it is to avoid clearing valid data, due to coding or other errors
		if (!$record)
		{
			$query = $db->getQuery(true)
				->select('i.id AS i, wa.stage_id AS stage_id')
				->from('#__content AS i')
				->join('LEFT', '#__workflow_associations AS wa ON wa.item_id = i.id')
				->where('i.id = ' . (int) $pk);
			$record = $db->setQuery($query)->loadObject();
		}

		if ($record->stage_id === null)
		{
			if (!$stage_id)
			{
				$query = $db->getQuery(true)
					->select('ws.id AS id')
					->from('#__workflows AS w')
					->join('INNER', '#__workflow_stages AS ws ON ws.workflow_id = w.id AND ws.default = 1')
					->where('w.extension = ' . $db->Quote($extension))
					->where('w.default = 1');
				$stage_id = $db->setQuery($query)->loadResult();
			}
			if ($stage_id)
			{
				$record->stage_id = $stage_id;
				$obj = (object) array(
					'item_id' => (int) $record->id,
					'stage_id' => (int) $record->stage_id,
					'extension' => $extension,
				);
				$db->insertObject('#__workflow_associations', $obj);
			}
		}

		if (JDEBUG) JFactory::getApplication()->enqueueMessage('Assigned item to Default Workflow', 'notice');
	}


	/**
	 * Method to get the (language filtered) name of all access levels
	 *
	 * @return string
	 * @since 1.5
	 */
	static function getAccessNames($accessid=null)
	{
		static $access_names = array();

		if ( $accessid!==null && isset($access_names[$accessid]) ) return $access_names[$accessid];

		$db = JFactory::getDbo();
		$db->setQuery('SELECT id, title FROM #__viewlevels');
		$_arr = $db->loadObjectList();
		$access_names = array(0=>'Public');  // zero does not exist in J2.5+ but we set it for compatibility
		foreach ($_arr as $o) $access_names[$o->id] = JText::_($o->title);

		if ( $accessid )
			return isset($access_names[$accessid]) ? $access_names[$accessid] : 'not found access id: '.$accessid;
		else
			return $access_names;
	}


	/**
	 * Method to get the type parameters of an item
	 *
	 * @return string
	 * @since 1.5
	 */
	static function getTypeAttribs($force = false, $typeid = 0, $itemid = 0)
	{
		static $typeparams = array();
		static $item_to_type = array();
		static $_tbl_loaded = null;

		$typeid = !$typeid && isset($item_to_type[$itemid])
			? $item_to_type[$itemid]
			: $typeid;

		if (!$force && isset($typeparams[$typeid]))
		{
			return $typeparams[$typeid];
		}

		$db = JFactory::getDbo();
		$query	= 'SELECT t.id, t.attribs'
			. ' FROM #__flexicontent_types AS t'
			. ($itemid ? ' JOIN #__flexicontent_items_ext as ie ON ie.type_id = t.id' : '')
			. ' WHERE 1'
			. ($typeid ? ' AND t.id = ' . (int) $typeid : '')
			. ($itemid ? ' AND ie.item_id = ' . (int) $itemid : '')
			;
		$db->setQuery($query);

		// Select specific type for the given typeid or the type used by the given content itemid
		if ($typeid || $itemid)
		{
			$data = $db->loadObject();

			if (!$data)
			{
				return false;
			}

			$typeid = $data->id;
			$typeparams[$typeid] = $data->attribs;

			// If loading type of specific item then cache item to type mapping
			if ($itemid)
			{
				$item_to_type[$itemid] = $typeid;
			}

			return $typeparams[$typeid];
		}

		// Select all types
		else
		{
			if (!$_tbl_loaded)
			{
				$_tbl_loaded = true;
				$rows = $db->loadObjectList();

				foreach($rows as $data)
				{
					$typeid = $data->id;
					$typeparams[$typeid] = $data->attribs;
				}
			}

			return $typeparams;
		}
	}

	/**
	 * Method to get the nr of favourites of anitem
	 *
	 * @access	public
	 * @return	integer on success
	 * @since	1.0
	 */
	static function getFavourites($type, $item_id)
	{
		$db = JFactory::getDbo();

		$query = '
			SELECT COUNT(id) AS favs
			FROM #__flexicontent_favourites
			WHERE itemid = '.(int)$item_id.'
				AND type = '.(int)$type;
		$db->setQuery($query);

		return $db->loadResult();
	}


	/**
	 * Method to get the nr of favourites of an user
	 *
	 * @access	public
	 * @since	1.0
	 */
	static function getFavoured($type, $item_id, $user_id)
	{
		$db = JFactory::getDbo();

		$query = '
			SELECT COUNT(id) AS fav
			FROM #__flexicontent_favourites
			WHERE itemid = '.(int)$item_id.'
				AND userid = '.(int)$user_id.'
				AND type = '.(int)$type;
		$db->setQuery($query);

		return $db->loadResult();
	}


	/**
	 * Method to remove a favourite
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since	1.0
	 */
	static function removefav($type, $item_id, $user_id)
	{
		$db = JFactory::getDbo();

		$query = '
			DELETE FROM #__flexicontent_favourites
			WHERE itemid = '.(int)$item_id.'
				AND userid = '.(int)$user_id.'
				AND type = '.(int)$type;
		$db->setQuery($query);

		return $db->execute();
	}


	/**
	 * Method to add a favourite
	 *
	 * @access	public
	 * @return	boolean	True on success
	 * @since	1.0
	 */
	static function addfav($type, $item_id, $user_id)
	{
		$db = JFactory::getDbo();

		$obj = new stdClass();
		$obj->itemid = (int)$item_id;
		$obj->userid = (int)$user_id;
		$obj->type   = (int)$type;

		return $db->insertObject('#__flexicontent_favourites', $obj);
	}


	/*
	 * Retrieve author/user configuration
	 *
	 * @return object
	 * @since 1.5
	 */
	static function getUserConfig($user_id)
	{
		static $userConfig = array();

		if (isset($userConfig[$user_id]))
		{
			return $userConfig[$user_id];
		}

		$db = JFactory::getDbo();
		$query = 'SELECT author_basicparams'
			. ' FROM #__flexicontent_authors_ext'
			. ' WHERE user_id = ' . $user_id;
		$authorparams = $db->setQuery($query)->loadResult();

		$userConfig[$user_id] = new JRegistry($authorparams);

		return $userConfig[$user_id];
	}


	/*
	 * Find stopwords and too small words
	 *
	 * @return array
	 * @since 1.5
	 */
	static function removeInvalidWords($words, &$stopwords, &$shortwords, $tbl='flexicontent_items_ext', $col='search_index', $isprefix=1)
	{
		$db     = JFactory::getDbo();
		$app    = JFactory::getApplication();
		$option = $app->input->get('option', '', 'cmd');
		$min_word_len = $app->getUserState( $option.'.min_word_len', 0 );

		$_word_clause = $isprefix ? '+%s*' : '+%s';
		$query = 'SELECT '.$col
			.' FROM #__'.$tbl
			.' WHERE MATCH ('.$col.') AGAINST ("'.$_word_clause.'" IN BOOLEAN MODE)'
			.' LIMIT 1';

		$_words = array();
		foreach ($words as $word)
		{
			$quoted_word = $db->escape($word, true);
			$q = sprintf($query, $quoted_word);
			$result = $db->setQuery($q)->loadAssocList();

			// Word found
			if (!empty($result))
			{
				$_words[] = $word;
			}
			// Word not found and word too short
			elseif (StringHelper::strlen($word) < $min_word_len)
			{
				$shortwords[] = $word;
			}
			// Word not found
			else
			{
				$stopwords[] = $word;
			}
		}

		return $_words;
	}

	/**
	 * Helper method to execute an SQL file containing multiple queries
	 *
	 * @return object
	 * @since 1.5
	 */
	static function execute_sql_file($sql_file)
	{
		$queries = file_get_contents( $sql_file );
		$queries = preg_split("/;+(?=([^'|^\\\']*['|\\\'][^'|^\\\']*['|\\\'])*[^'|^\\\']*[^'|^\\\']$)/", $queries);

		$db = JFactory::getDbo();

		foreach ($queries as $query)
		{
			$query = trim($query);
			if (!$query) continue;

			$result = $db->setQuery($query)->execute();
		}
	}


	/**
	 * Helper method to execute a query directly, bypassing Joomla DB Layer
	 *
	 * @return object
	 * @since 1.5
	 */
	static function & directQuery($query, $assoc = false, $unbuffered = false)
	{
		$db   = JFactory::getDbo();
		$app  = JFactory::getApplication();
		$dbprefix = $app->getCfg('dbprefix');
		$dbtype   = $app->getCfg('dbtype');
		$dbtype   = $dbtype == 'mysql' && !function_exists('mysql_query') ? 'mysqli' : $dbtype;  // PHP 7 removes mysql but 'mysql' database may still be in the configuration file

		$query = $db->replacePrefix($query);  //echo "<pre>"; print_r($query); echo "\n\n";
		$db_connection = $db->getConnection();

		if ($dbtype === 'pdomysql' && is_a($db_connection, 'mysqli'))
		{
			$dbtype = 'mysqli';
		}

		$data = array();

		if ($dbtype === 'mysqli')
		{
			$result = $unbuffered
				? mysqli_query($db_connection , $query, MYSQLI_USE_RESULT)
				: mysqli_query($db_connection , $query);

			if ($result === false)
			{
				throw new Exception('error '.__FUNCTION__.'():: '.mysqli_error($db_connection));
			}

			while ($row = $assoc ? mysqli_fetch_assoc($result) : mysqli_fetch_object($result))
			{
				$data[] = $row;
			}

			mysqli_free_result($result);
		}

		elseif ($dbtype === 'mysql')
		{
			$result = $unbuffered
				? mysql_unbuffered_query($query, $db_connection)
				: mysql_query($query, $db_connection);

			if ($result===false)
			{
				throw new Exception('error '.__FUNCTION__.'():: '.mysql_error($db_connection));
			}

			while ($row = $assoc ? mysql_fetch_assoc($result) : mysql_fetch_object($result))
			{
				$data[] = $row;
			}

			mysql_free_result($result);
		}

		elseif ($dbtype === 'pdomysql')
		{
			// Exceptions maybe thrown by the below statements
			if (!$unbuffered)
			{
				$result = $db_connection->query($query);
				$data = $assoc
					? $result->fetchAll(PDO::FETCH_ASSOC)
					: $result->fetchAll(PDO::FETCH_OBJ);
			}
			else
			{
				$result = $db_connection->prepare(
					$query,
					array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false)
				);
				$result->execute();

				while ($row = $assoc ? $result->fetch(PDO::FETCH_ASSOC) : $result->fetch(PDO::FETCH_OBJ))
				{
					$data[] = $row;
				}
			}
		}

		else
		{
			throw new Exception( __FUNCTION__.'(): direct db query, unsupported DB TYPE' );
		}

		return $data;
	}


	/**
	 * Build the calculation of the rating column used for ordering an item listing
	 * @access public
	 * @return string
	 */
	static function buildRatingOrderingColumn(& $rating_join = null, $colname = 'votes', $ta = 'i')
	{
		$voting_field = reset(FlexicontentFields::getFieldsByIds(array(11)));
		$voting_field->parameters = new JRegistry($voting_field->attribs);

		$rating_resolution = (int) $voting_field->parameters->get('rating_resolution', 5);
		$rating_resolution = $rating_resolution >= 5 ? $rating_resolution : 5;
		$rating_resolution = $rating_resolution <= 100 ? $rating_resolution : 100;
		$default_rating    = (int) $voting_field->parameters->get('default_rating', 70);

		$_weights = array();

		for ($i = 1; $i <= 9; $i++)
		{
			$weight_factor = round(((int) $voting_field->parameters->get('vote_'.$i.'_weight', 100)) / 100, 2);
			//$_weights[] = 'WHEN ' . $i . ' THEN ROUND(' . $weight_factor . ' * cr.rating_sum / cr.rating_count * ' . (100 / $rating_resolution / $rating_resolution) . ') * ' . $rating_resolution;
			$_weights[] = 'WHEN ' . $i . ' THEN ROUND(' . $weight_factor . ' * cr.rating_sum / cr.rating_count * ' . (100 / $rating_resolution) . ')';
		}

		$rating_join = '#__content_rating AS cr ON cr.content_id = ' . $ta . '.id';
		$_rating_percentage = 'CASE cr.rating_count'
			. ' ' . implode(' ', $_weights)
			. ' ELSE IF (ISNULL (cr.rating_count)'
			. '   , ' . round($default_rating / $rating_resolution) * $rating_resolution
			//. '   , ROUND(cr.rating_sum / cr.rating_count * ' . (100 / $rating_resolution / $rating_resolution) . ') * ' . $rating_resolution
			. '   , ROUND(cr.rating_sum / cr.rating_count * ' . (100 / $rating_resolution) . ')'
			. ' )'
			. ' END AS ' . $colname;

		return $_rating_percentage;
	}


	/**
	 * Build the order clause of item listings
	 * precedence: $request_var ==> $order ==> $config_param ==> $default_order_col (& $default_order_dir)
	 * @access private
	 * @return string
	 */
	static function buildItemOrderBy(&$params=null, &$order='', $request_var='orderby', $config_param='orderby', $i_as='i', $rel_as='rel', $default_order_col_1st='', $default_order_dir_1st='', $sfx='', $support_2nd_lvl=false)
	{
		// Use global params ordering if parameters were not given
		if (!$params) $params = JComponentHelper::getParams( 'com_flexicontent' );
		$app = JFactory::getApplication();

		$order_fallback = 'rdate';  // Use as default or when an invalid ordering is requested
		$orderbycustomfield   = (int) $params->get('orderbycustomfield'.$sfx, 1);    // Backwards compatibility, defaults to enabled *
		$orderbycustomfieldid = (int) $params->get('orderbycustomfieldid'.$sfx, 0);  // * but this needs to be set in order for field ordering to be used

		// 1. If a FORCED -ORDER- is not given, then use ordering parameters from configuration. NOTE: custom field ordering takes priority
		if (!$order)
		{
			$order = ($orderbycustomfield && $orderbycustomfieldid)  ?  'field'  :  $params->get($config_param.$sfx, $order_fallback);
		}

		// 2. If allowing user ordering override, then get ordering from HTTP request variable
		$request_order = $app->input->get($request_var.$sfx, '', 'string');
		$order = $params->get('orderby_override') && $request_order ? $request_order : $order;

		// 3. Check various cases of invalid order, print warning, and reset ordering to default
		if ($order=='field' && !$orderbycustomfieldid )
		{
			// This can occur only if field ordering was requested explicitly, otherwise an not set 'orderbycustomfieldid' will prevent 'field' ordering
			echo "Custom field ordering was selected, but no custom field is selected to be used for ordering<br/>";
			$order = $order_fallback;
		}
		if ($order=='commented')
		{
			if (!file_exists(JPATH_SITE.DS.'components'.DS.'com_jcomments'.DS.'jcomments.php')) {
				echo "jcomments not installed, you need jcomments to use 'Most commented' ordering OR display comments information.<br/>\n";
				$order = $order_fallback;
			}
		}

		$order_col_1st = $default_order_col_1st;
		$order_dir_1st = $default_order_dir_1st;
		flexicontent_db::_getOrderByClause($params, $order, $i_as, $rel_as, $order_col_1st, $order_dir_1st, $sfx);
		$order_arr[1] = $order;
		$orderby = ' ORDER BY '.$order_col_1st.' '.$order_dir_1st;


		// ***
		// *** 2nd level ordering, (currently only supported when no SFX given)
		// ***

		if ($sfx!='' || !$support_2nd_lvl)
		{
			$orderby .= $order_col_1st != $i_as.'.title'  ?  ', '.$i_as.'.title'  :  '';
			$order_arr[2] = '';
			$order = $order_arr;
			return $orderby;
		}

		$order = '';  // Clear this, thus force retrieval from parameters (below)
		$sfx='_2nd';  // Set suffix of second level ordering
		$order_fallback = 'alpha';  // Use as default or when an invalid ordering is requested
		$orderbycustomfield   = (int) $params->get('orderbycustomfield'.$sfx, 1);    // Backwards compatibility, defaults to enabled *
		$orderbycustomfieldid = (int) $params->get('orderbycustomfieldid'.$sfx, 0);  // * but this needs to be set in order for field ordering to be used

		// 1. If a FORCED -ORDER- is not given, then use ordering parameters from configuration. NOTE: custom field ordering takes priority
		if (!$order)
		{
			$order = ($orderbycustomfield && $orderbycustomfieldid)  ?  'field'  :  $params->get($config_param.$sfx, $order_fallback);
		}

		// 2. If allowing user ordering override, then get ordering from HTTP request variable
		$request_order = $app->input->get($request_var.$sfx, '', 'string');
		$order = $request_var && $request_order ? $request_order : $order;

		// 3. Check various cases of invalid order, print warning, and reset ordering to default
		if ($order=='field' && !$orderbycustomfieldid )
		{
			// This can occur only if field ordering was requested explicitly, otherwise an not set 'orderbycustomfieldid' will prevent 'field' ordering
			echo "Custom field ordering was selected, but no custom field is selected to be used for ordering<br/>";
			$order = $order_fallback;
		}
		if ($order=='commented')
		{
			if (!file_exists(JPATH_SITE.DS.'components'.DS.'com_jcomments'.DS.'jcomments.php'))
			{
				echo "jcomments not installed, you need jcomments to use 'Most commented' ordering OR display comments information.<br/>\n";
				$order = $order_fallback;
			}
		}

		$order_col_2nd = '';
		$order_dir_2nd = '';
		if ($order!='default')
		{
			flexicontent_db::_getOrderByClause($params, $order, $i_as, $rel_as, $order_col_2nd, $order_dir_2nd, $sfx);
			$order_arr[2] = $order;
			$orderby .= ', '.$order_col_2nd.' '.$order_dir_2nd;
		}

		// Order by title after default ordering
		$orderby .= ($order_col_1st != $i_as.'.title' && $order_col_2nd != $i_as.'.title')  ?  ', '.$i_as.'.title'  :  '';
		$order = $order_arr;
		return $orderby;
	}


	// Create order clause sub-parts
	static function _getOrderByClause(&$params, &$order='', $i_as='i', $rel_as='rel', &$order_col='', &$order_dir='', $sfx='')
	{
		// 'order' contains a symbolic order name to indicate using the category / global ordering setting
		switch ($order) {
			case 'date': case 'addedrev': /* 2nd is for module (PARAMETER FORM ELEMENT: fcordering) */
				$order_col	= $i_as.'.created';
				$order_dir	= 'ASC';
				break;
			case 'rdate': case 'added': /* 2nd is for module (PARAMETER FORM ELEMENT: fcordering) */
				$order_col	= $i_as.'.created';
				$order_dir	= 'DESC';
				break;
			case 'modified': case 'updated': /* 2nd is for module (PARAMETER FORM ELEMENT: fcordering) */
				$order_col	= $i_as.'.modified DESC, ' . $i_as.'.created';
				$order_dir	= 'DESC';
				break;
			case 'published':
				$order_col	= $i_as.'.publish_up';
				$order_dir	= 'DESC';
				break;
			case 'published_oldest':
				$order_col	= $i_as.'.publish_up';
				$order_dir	= 'ASC';
				break;
			case 'expired':
				$order_col	= $i_as.'.publish_down';
				$order_dir	= 'DESC';
				break;
			case 'expired_oldest':
				$order_col	= $i_as.'.publish_down';
				$order_dir	= 'ASC';
				break;
			case 'alpha':
				$order_col	= $i_as.'.title';
				$order_dir	= 'ASC';
				break;
			case 'ralpha': case 'alpharev': /* 2nd is for module (PARAMETER FORM ELEMENT: fcordering) */
				$order_col	= $i_as.'.title';
				$order_dir	= 'DESC';
				break;
			case 'author':
				$order_col	= 'u.name';
				$order_dir	= 'ASC';
				break;
			case 'rauthor':
				$order_col	= 'u.name';
				$order_dir	= 'DESC';
				break;
			case 'hits': case 'popular': /* 2nd is for module (PARAMETER FORM ELEMENT: fcordering) */
				$order_col	= $i_as.'.hits';
				$order_dir	= 'DESC';
				break;
			case 'rhits':
				$order_col	= $i_as.'.hits';
				$order_dir	= 'ASC';
				break;
			case 'order': case 'catorder': /* 2nd is for module (PARAMETER FORM ELEMENT: fcordering) */
				$order_col	= $rel_as.'.catid, '.$rel_as.'.ordering ASC, '.$i_as.'.id DESC';
				$order_dir	= '';
				break;
			case 'rorder':
				$order_col	= $rel_as.'.catid, '.$rel_as.'.ordering DESC, '.$i_as.'.id DESC';
				$order_dir	= '';
				break;
			case 'jorder':
				$order_col	= $i_as.'.ordering';
				$order_dir	= 'ASC';
				break;
			case 'rjorder':
				$order_col	= $i_as.'.ordering';
				$order_dir	= 'DESC';
				break;

			// SPECIAL case custom field
			case 'field':
				$cf = $sfx == '_2nd' ? 'f2' : 'f';
				$order_type = $params->get('orderbycustomfieldint'.$sfx, 0);
				switch( $order_type )
				{
					case 1:  $order_col = $cf.'.value_integer';  break;   // Integer  // 'CAST('.$cf.'.value AS SIGNED)'
					case 2:  $order_col = $cf.'.value_decimal'; break;    // Decimal  // 'CAST('.$cf.'.value AS DECIMAL(65,15))'
					case 3:  $order_col = $cf.'.value_datetime';  break;  // Date     // 'CAST('.$cf.'.value AS DATETIME)'
					case 4:  $order_col = ($sfx == '_2nd' ? 'file_hits2' : 'file_hits'); break;  // Download hits
					default: $order_col = $cf.'.value'; break;  // Text
				}
				$order_dir = strtoupper($params->get('orderbycustomfielddir'.$sfx, 'ASC')) == 'ASC' ? 'ASC' : 'DESC';
				if ($order_type != 4 && $order_dir=='ASC')
				{
					$order_col = 'ISNULL('.$cf.'.value), ' . $order_col;
				}
				break;

			// NEW ADDED
			case 'random_ppr':
				$order_col	= 'RAND()';
				$order_dir	= '';
				break;
			case 'random':
				// Convert session id to array of hex strings (4 bytes each)
				$sid = JFactory::getSession()->getId();
				$sid = str_split(md5($sid), 8);
				// Create a SEED doing a XOR operation on session-ID to keep SEED to 4 bytes
				$seed = null;
				foreach($sid as $b)
				{
					$seed = ($seed == null)  ?  hexdec($b)  :  ($seed ^ hexdec($b));
				}
				$order_col	= 'RAND(' . $seed . ')';
				$order_dir	= '';
				break;
			case 'commented':
				$order_col	= 'comments_total';
				$order_dir	= 'DESC';
				break;
			case 'rated':
				$order_col	= 'votes DESC, rating_count';
				$order_dir	= 'DESC';
				break;
			case 'id':
				$order_col	= $i_as.'.id';
				$order_dir	= 'DESC';
				break;
			case 'rid':
				$order_col	= $i_as.'.id';
				$order_dir	= 'ASC';
				break;
			case 'alias':
				$order_col	= $i_as.'.alias';
				$order_dir	= 'ASC';
				break;
			case 'ralias':
				$order_col	= $i_as.'.alias';
				$order_dir	= 'DESC';
				break;

			case 'default':
			default:
				if (substr($order, 0, 7)=='custom:')
				{
					$order_parts = preg_split("/:/", $order);
					$_field_id = (int) @ $order_parts[1];
				}
				if (!empty($_field_id) && count($order_parts)==4)
				{
					$cf = $sfx == '_2nd' ? 'f2' : 'f';
					$order_type = strtolower($order_parts[2]);
					switch( $order_type )
					{
						case 'int':       $order_col = $cf.'.value_integer';  break;   // Integer  // 'CAST('.$cf.'.value AS SIGNED)'
						case 'decimal':   $order_col = $cf.'.value_decimal'; break;    // Decimal  // 'CAST('.$cf.'.value AS DECIMAL(65,15))'
						case 'date':      $order_col = $cf.'.value_datetime'; break;   // Date     // 'CAST('.$cf.'.value AS DATETIME)'
						case 'file_hits': $order_col = ($sfx == '_2nd' ? 'file_hits2' : 'file_hits'); break;  // Download hits
						default:          $order_col = $cf.'.value'; break;
					}
					$order_dir = strtoupper($order_parts[3])=='DESC' ? 'DESC' : 'ASC';
					if ($order_type != 'file_hits' && $order_dir=='ASC')
					{
						$order_col = 'ISNULL('.$cf.'.value), ' . $order_col;
					}
				} else {
					$order_col	= $order_col ? $order_col : $i_as.'.title';
					$order_dir	= $order_dir ? $order_dir : 'ASC';
				}
				break;
		}
		//echo "<br/>".$order_col." ".$order_dir."<br/>";
	}


	/**
	 * Build the order clause of category listings
	 *
	 * @access private
	 * @return string
	 */
	static function buildCatOrderBy(&$params, $order='', $request_var='', $config_param='cat_orderby', $c_as='c', $u_as='u', $default_order_col='', $default_order_dir='')
	{
		// Use global params ordering if parameters were not given
		if (!$params) $params = JComponentHelper::getParams( 'com_flexicontent' );
		$app = JFactory::getApplication();

		// 1. If forced ordering not given, then use ordering parameters from configuration
		if (!$order)
		{
			$order = $params->get($config_param, 'default');
		}

		// 2. If allowing user ordering override, then get ordering from HTTP request variable
		$request_order = $app->input->get($request_var, '', 'string');
		$order = $request_var && $request_order ? $request_order : $order;

		switch ($order)
		{
			case 'date':
				$order_col = $c_as.'.created_time';
				$order_dir = 'ASC';
				break;
			case 'rdate':
				$order_col = $c_as.'.created_time';
				$order_dir = 'DESC';
				break;
			case 'modified':
				$order_col = $c_as.'.modified_time DESC, ' . $c_as.'.created_time';
				$order_dir = 'DESC';
				break;
			case 'alpha':
				$order_col = $c_as.'.title';
				$order_dir = 'ASC';
				break;
			case 'ralpha':
				$order_col = $c_as.'.title';
				$order_dir = 'DESC';
				break;
			case 'author':
				$order_col = $u_as.'.name';
				$order_dir = 'ASC';
				break;
			case 'rauthor':
				$order_col = $u_as.'.name';
				$order_dir = 'DESC';
				break;
			case 'hits':
				$order_col = $c_as.'.hits';
				$order_dir = 'DESC';
				break;
			case 'rhits':
				$order_col = $c_as.'.hits';
				$order_dir = 'ASC';
				break;
			case 'order':
				$order_col = $c_as.'.lft';
				$order_dir = 'ASC';
				break;
			case 'random_ppr':
				$order_col	= 'RAND()';
				$order_dir	= '';
				break;
			case 'random':
				// Convert session id to array of hex strings (4 bytes each)
				$sid = JFactory::getSession()->getId();
				$sid = str_split(md5($sid), 8);
				// Create a SEED doing a XOR operation on session-ID to keep SEED to 4 bytes
				$seed = null;
				foreach($sid as $b)
				{
					$seed = ($seed == null)  ?  hexdec($b)  :  ($seed ^ hexdec($b));
				}
				$order_col	= 'RAND(' . $seed . ')';
				$order_dir	= '';
				break;
			case 'default' :
			default:
				$order_col = $default_order_col ? $default_order_col : $i_as.'.title';
				$order_dir = $default_order_dir ? $default_order_dir : 'ASC';
				break;
		}

		$orderby 	= ' ORDER BY '.$order_col.' '.$order_dir;
		$orderby .= $order_col!=$c_as.'.title' ? ', '.$c_as.'.title' : '';   // Order by title after default ordering

		return $orderby;
	}


	/**
	 * Check in a record
	 *
	 * @param   string   $jtable_name    The name of the JTable class
	 * @param   string   $redirect_url   The redirect URL to set
	 * @param   object   $controller     The controller instance
	 *
	 * @since	1.5
	 */
	static function checkin($jtable_name, $redirect_url, $controller)
	{
		$cid = JFactory::getApplication()->input->get('cid', array(0), 'array');
		$cid = ArrayHelper::toInteger($cid);

		$user = JFactory::getUser();
		$controller->setRedirect($redirect_url, '');

		static $canCheckinRecords = null;

		if ($canCheckinRecords === null)
		{
			$canCheckinRecords = $user->authorise('core.admin', 'com_checkin');
		}

		// Only attempt to check the row in if it exists.
		$checked_in = 0;
		$diff_user = array();
		$errors = array();

		foreach($cid as $pk)
		{
			if (!$pk)
			{
				continue;
			}

			// Get a new (DB) Table instance of the row to checkin.
			$table = JTable::getInstance($jtable_name, '');

			if (!$table->load($pk))
			{
				$errors[] = 'ID: ' . $pk . ': ' . $table->getError();
				continue;
			}

			// Record check-in is allowed if either (a) current user has Global Checkin privilege OR (b) record checked out by current user
			if (!$table->checked_out)
			{
				continue;
			}

			if (!$canCheckinRecords && $table->checked_out != $user->id)
			{
				$diff_user[] = $pk;
				continue;
			}

			// Attempt to check the row in.
			if (!$table->checkin($pk))
			{
				// Do not add too many errors, limit to 3
				if (count($errors) < 3)
				{
					$errors[] = 'ID: ' . $pk . ': ' . $table->getError();
				}

				continue;
			}

			$checked_in++;
		}

		// Start by mentioning the successful checkins operations
		$msg = JText::sprintf('FLEXI_RECORD_CHECKED_IN_SUCCESSFULLY', $checked_in);

		if (count($diff_user))
		{
			$msg .= '<br/><br/>IDs: ' . implode(', ', $diff_user) . ' -- ' . JText::_('FLEXI_RECORD_CHECKED_OUT_DIFF_USER');
		}

		if (count($errors))
		{
			$msg .= '<br/><br/>' . implode('<br/> ', $errors);
		}

		$controller->setRedirect( $redirect_url, $msg, ($errors ? 'error' : 'message') );
	}


	/**
	 * Return field types grouped or not
	 *
	 * @return array
	 * @since 1.5
	 */
	static function getFieldTypes($group=false, $usage=false, $published=false)
	{
		$db = JFactory::getDbo();
		$query = 'SELECT plg.element AS field_type, plg.name as title'
			.($usage ? ', count(f.id) as assigned' : '')
			.' FROM #__extensions AS plg'
			.($usage ? ' LEFT JOIN #__flexicontent_fields AS f ON (plg.element = f.field_type AND f.iscore=0)' : '')
			.' WHERE '.($published ? 'plg.enabled=1' : '1')
			.'  AND plg.`type` = ' . $db->Quote('plugin')
			.'  AND plg.`folder` = ' . $db->Quote('flexicontent_fields')
			.'  AND plg.`element` <> ' . $db->Quote('core')
			.($usage ? ' GROUP BY plg.element' : '')
			.' ORDER BY title ASC'
			;

		$db->setQuery($query);
		$field_types = $db->loadObjectList('field_type');

		foreach($field_types as $field_type) {
			$field_type->friendly = preg_replace("/FLEXIcontent[ \t]*-[ \t]*/i", "", $field_type->title);
		}
		if (!$group) return $field_types;

		$grps = array(
			JText::_('FLEXI_SELECTION_FIELDS')          => array('radio', 'radioimage', 'checkbox', 'checkboximage', 'select', 'selectmultiple'),
			JText::_('FLEXI_SINGLE_PROP_FIELDS')        => array('color', 'date', 'text', 'textarea', 'textselect'),
			JText::_('FLEXI_MULTIPLE_PROP_FIELDS')      => array('weblink', 'email', 'phonenumbers', 'termlist'),
			JText::_('FLEXI_MEDIA_MINI_APPS_FIELDS')    => array('file', 'image', 'mediafile', 'sharedmedia', 'addressint'),
			JText::_('FLEXI_ITEM_FORM_FIELDS')          => array('fieldgroup', 'account_via_submit', 'custom_form_html', 'coreprops'),
			JText::_('FLEXI_DISPLAY_MANAGEMENT_FIELDS') => array('toolbar', 'fcloadmodule', 'fcpagenav', 'linkslist', 'authoritems', 'jprofile', 'comments'),
			JText::_('FLEXI_ITEM_RELATION_FIELDS')      => array('relation', 'relation_reverse', 'autorelationfilters')
		);
		foreach($grps as $grpname => $field_type_arr)
		{
			$field_types_grp[$grpname] = array();
			foreach($field_type_arr as $field_type)
			{
				if ( !empty($field_types[$field_type]) ) {
					$field_types_grp[$grpname][$field_type] = $field_types[$field_type];
				}
				unset($field_types[$field_type]);
			}
		}
		// Remaining fields
		$field_types_grp['3rd-Party / Other Fields'] = $field_types;

		return $field_types_grp;
	}


	/**
	 * Method to get data/parameters of thie given or all types
	 *
	 * @access public
	 * @return object
	 */
	static function getTypeData($contenttypes_list = false)
	{
		static $cached = null;

		if (is_array($contenttypes_list))
		{
			$contenttypes_list = ArrayHelper::toInteger($contenttypes_list);
			$contenttypes_list = implode(',', $contenttypes_list);
		}

		if (isset($cached[$contenttypes_list]))
		{
			return $cached[$contenttypes_list];
		}

		// Retrieve item's Content Type parameters
		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('*')
			->from('#__flexicontent_types AS t');

		if ($contenttypes_list)
		{
			$query->where('id IN (' . $contenttypes_list . ')');
		}

		$types = $db->setQuery($query)->loadObjectList('id');

		foreach ($types as $type)
		{
			$type->params = new JRegistry($type->attribs);
		}

		$cached[$contenttypes_list] = $types;
		return $types;
	}


	static function getOriginalContentItemids($_items, $ids=null)
	{
		if (empty($ids) && empty($_items)) return array();

		if (is_array($_items))
			$items = & $_items;
		else
			$items = array( & $_items );

		if (empty($ids))
		{
			$ids = array();
			foreach($items as $item) $ids[] = $item->id;
		}

		// Get associated translations
		$db = JFactory::getDbo();
		$query = 'SELECT a.id as id, k.id as original_id'
			. ' FROM #__associations AS a'
			. ' JOIN #__associations AS k ON a.`key`=k.`key`'
			. ' JOIN #__content AS i ON i.id = k.id AND i.language = '. $db->Quote(flexicontent_html::getSiteDefaultLang())
			. ' WHERE a.id IN ('. implode(',', $ids) .') AND a.context = "com_content.item"'
		;
		$assoc_keys = $db->setQuery($query)->loadObjectList('id');

		if (!empty($items))
		{
			foreach($items as $item) $item->lang_parent_id = isset($assoc_keys[$item->id]) ? $assoc_keys[$item->id]->original_id : $item->id;
		}
		else
			return $assoc_keys;
	}


	static function getLangAssocs($ids, $config = null)
	{
		$config = $config ?: (object) array(
			'table'    => 'content',
			'table_ext'=> null,
			'ext_id'   => null,
			'context'  => 'com_content.item',
			'created'  => 'created',
			'modified' => 'modified',
		);

		$db = JFactory::getDbo();
		$query = 'SELECT a.id as item_id, i.id as id, i.title, i.' . $config->created . ' as created, i.' . $config->modified . ' as modified, '
			. ' i.language as language, i.language as lang, ' . $db->qn('a.key') . ' as ' . $db->qn('key') 
			. (!empty($config->state) ?', i.' . $config->state . ' AS state ' : '')
			. (!empty($config->catid) ?', i.' . $config->catid . ' AS catid ' : '')
			. (!empty($config->is_uptodate) ?', ext.' . $config->is_uptodate . ' AS is_uptodate ' : '')
			. ' FROM #__associations AS a'
			. ' JOIN #__associations AS k ON a.`key`=k.`key`'
			. ' JOIN ' . $db->qn('#__' . $config->table) . ' AS i ON i.id = k.id'
			. (!empty($config->table_ext) ? ' JOIN ' . $db->qn('#__' . $config->table_ext) . ' AS ext ON i.id = ext.' . $config->ext_id : '')
			. ' WHERE a.id IN ('. implode(',', $ids) .') AND a.context = ' . $db->quote($config->context)
		;
		$associations = $db->setQuery($query)->loadObjectList();

		$translations = array();

		foreach ($associations as $assoc)
		{
			$assoc->shortcode = strpos($assoc->language,'-')  ?  substr($assoc->language, 0, strpos($assoc->language,'-'))  :  $assoc->language;
			$translations[$assoc->item_id][$assoc->id] = $assoc;
		}

		return $translations;
	}


	/**
	 * Method to save language associations
	 *
	 * @return  boolean True if successful
	 */
	static function saveAssociations(&$item, &$data, $context, $add_current = false)
	{
		// Check if associations are enabled, but also mantain associations if associations data are no present, 
		if (!flexicontent_db::useAssociations() || !isset($data['associations']))
		{
			return true;
		}


		/**
		 * Prepare / check associations array
		 */

		// Unset empty associations from associations array, to avoid save them in the associations table
		$associations = !empty($data['associations']) ? $data['associations'] : array();

		foreach ($associations as $tag => $id)
		{
			if (empty($id)) unset($associations[$tag]);
		}

		// Raise notice that associations should be empty if language of current item is '*' (ALL)
		$all_language = $item->language == '*';
		if ($all_language && !empty($associations))
		{
			JError::raiseNotice(403, JText::_('FLEXI_ERROR_ALL_LANGUAGE_ASSOCIATED'));
		}

		// Add current item to associations if this is desired
		if ($add_current)
		{
			$associations[$item->language] = $item->id;
		}

		// Make sure associations ids are integers
		$associations = ArrayHelper::toInteger($associations);

		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select($db->qn('key'))
			->from('#__associations')
			->where($db->qn('context') . ' = ' . $db->quote($context))
			->where($db->qn('id') . ' = ' . (int) $item->id)
		;
		$key = $db->setQuery($query)->loadResult();


		// ***
		// *** Delete old associations for item, and remove given associations for other association groups
		// ***
		if ($key || $associations)
		{
			$record_ids = ArrayHelper::toInteger($associations);
			$where = array();
			if ($key) $where[] = $db->qn('key') . ' = ' . $db->quote($key);
			if ($associations) $where[] = ' id IN (' . implode(',', $record_ids) . ')';

			$query = $db->getQuery(true)
				->delete('#__associations')
				->where($db->qn('context') . ' = ' . $db->quote($context))
				->where('(' . implode(' OR ', $where) . ')');
			$db->setQuery($query)->execute();

			if ($context === 'com_content.item')
			{
				$ocLang = JComponentHelper::getParams('com_flexicontent')->get('original_content_language', '_site_default_');
				$ocLang = $ocLang === '_site_default_' ? JComponentHelper::getParams('com_languages')->get('site', '*') : $ocLang;
				$ocLang = $ocLang !== '_disable_' && $ocLang !== '*' ? $ocLang : false;
				if ($item->language === $ocLang)
				{
					$query = $db->getQuery(true)
						->update('#__flexicontent_items_ext')
						->set($db->qn('is_uptodate') . ' = 0')
						->where($db->qn('item_id') . ' IN (' . implode(',', $record_ids) . ')');
					$db->setQuery($query)->execute();
				}
			}
		}


		// ***
		// *** Add new associations
		// ***

		// Only add language associations if item language is not '*' (ALL)
		if ($all_language || count($associations)<=1) return true;

		$key = md5(json_encode($associations));
		$query->clear()
			->insert('#__associations');

		foreach ($associations as $id)
		{
			$query->values($id . ',' . $db->quote($context) . ',' . $db->quote($key));
		}

		$db->setQuery($query);
		$db->execute();

		return true;
	}


	/**
	 * Method to determine if J3.1+ associations should be used
	 *
	 * @return  boolean True if using J3 associations; false otherwise.
	 */
	static function useAssociations()
	{
		static $assoc = null;

		if (!is_null($assoc))
		{
			return $assoc;
		}

		$app = JFactory::getApplication();

		$assoc = FLEXI_J30GE && JLanguageAssociations::isEnabled();
		$component = 'com_flexicontent';
		$cname = str_replace('com_', '', $component);
		$j3x_assocs = true;

		if (!$assoc || !$component || !$cname || !$j3x_assocs)
		{
			$assoc = false;
		}
		else
		{
			$hname = $cname . 'HelperAssociation';
			JLoader::register($hname, JPATH_SITE . '/components/' . $component . '/helpers/association.php');

			$assoc = class_exists($hname) && !empty($hname::$category_association);
		}

		return $assoc;
	}


	/**
	 * Check and fix Joomla Tags table
	 *
	 * @return  void
	 *
	 * @since   3.3.8
	 */
	static function checkFixJTagsTable()
	{
		static $tags_table_fix_needed = null;

		if ($tags_table_fix_needed !== null)
		{
			return;
		}

		$db = JFactory::getDbo();

		$query = 'SELECT COUNT(*) FROM #__tags WHERE parent_id = 0 AND id <> 1';
		$tags_table_fix_needed = (boolean) $db->setQuery($query)->execute();

		// Fix Joomla tags table
		if ($tags_table_fix_needed)
		{
			$query = 'UPDATE #__tags SET parent_id = 1 WHERE parent_id = 0 AND id <> 1';
			$db->setQuery($query)->execute();

			JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_tags/tables');
			$tbl = JTable::getInstance('Tag', 'TagsTable');

			$tbl->rebuild();
		}
	}


	/**
	 * Find Joomla tags when given respective FC tags, creating them if they do not exist
	 *
	 * @param   array   $tags       Tags text array from the field
	 * @param   array   $checkACL   Flag to indicate if tag creation ACL should be used
	 * @param   string  $indexCol   Tag table column (name) whose value to use for indexing the return array
	 *
	 * @return  array   An array of tag data (or null tag data), indexed by the value of the given tag column
	 *
	 * @since   3.4.0
	 */
	static function createFindJoomlaTags($tags, $checkACL = true, $indexCol = 'null')
	{
		flexicontent_db::checkFixJTagsTable();

		$newTags = array();

		if (empty($tags) || (count($tags) === 1 && reset($tags) === ''))
		{
			return $newTags;
		}

		// We will use the tags table to store them
		Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_tags/tables');
		$tagTable  = Table::getInstance('Tag', 'TagsTable');
		$canCreate = \JFactory::getUser()->authorise('core.create', 'com_tags');

		foreach ($tags as $key => $tag)
		{
			// Get Tag Text, removing the #new# prefix that identifies new tags
			$tagText = is_object($tag) ? $tag->name : str_replace('#new#', '', $tag);

			$loaded = false;

			// Clear old data if exist
			$tagTable->reset();

			// (A) Try to load the selected tag via id
			$jtag_found = is_object($tag)
				? ((int) $tag->jtag_id && $tagTable->load((int) $tag->jtag_id))
				: ((int) $tag && $tagTable->load((int) $tag));

			$return_index = is_object($tag) && $indexCol
				? $tag->{$indexCol}
				: $tagText;

			if ($jtag_found)
			{
				$loaded = true;
			}

			// (B) Try to load the selected tag via title
			elseif ($tagTable->load(array('title' => $tagText)))
			{
				$loaded = true;
			}

			// (C) Try to load auto-created alias, and (D) Fail if not found
			else
			{
				// If user is not allowed to create tags, don't create new tag
				$is_new = is_object($tag) ? true : strpos($tag, '#new#') !== false;

				if ($checkACL && !$canCreate && $is_new)
				{
					$newTags[$return_index] = null;
					continue;
				}

				// Set title then call check() method to auto-create an alias
				$tagTable->title = $tagText;
				$tagTable->check();

				// (C) Try to load the selected tag, via auto-created alias
				if ($tagTable->alias && $tagTable->load(array('alias' => $tagTable->alias)))
				{
					$loaded = true;
				}

				// (D) Tag not found. Create a new tag at top-level with language 'ALL', with public access
				else
				{
					// Prepare tag data
					$tagTable->id        = 0;
					$tagTable->title     = $tagText;
					$tagTable->published = 1;

					// Language ALL, Public access (assumed ... 1)
					$tagTable->language = '*';
					$tagTable->access   = 1;

					// Make this item a child of the root tag
					$tagTable->parent_id = $tagTable->getRootId();
					$tagTable->setLocation($tagTable->getRootId(), 'last-child');

					// Try to store tag
					if ($tagTable->check())
					{
						// Assign the alias as path (autogenerated tags have always level 1)
						$tagTable->path = $tagTable->alias;

						if ($tagTable->store())
						{
							$loaded = true;
						}
					}
				}
			}

			if ($loaded)
			{
				$newTags[$return_index] = (object) array(
					'id'    => (int) $tagTable->id,
					'title' => $tagTable->title,
					'alias' => $tagTable->alias
				);
			}
			else
			{
				$newTags[$return_index] = null;
			}
		}

		return $newTags;
	}


	/**
	 * Method to unserialize arrays only
	 *
	 * @return  array or empty array if invalid data (serialized inner object is found)
	 */
	static function unserialize_array($v, $force_array=false, $force_value = true)
	{
		static $pattern_obj_inner = '/o:\d+:"[a-z0-9_]+":\d+:{.*?}/i';
		static $pattern_array_outer = '/^a:\d+:{.*?}$/is';

		// ***
		// *** SANITY CHECKs
		// ***

		// Already an array, return it
		if (is_array($v))
		{
			return $v;
		}

		// Zero length value, return empty array or false (error)
		if (!strlen($v))
		{
			return $force_array ? array() : false;
		}

		// ***
		// *** Unserialize
		// ***

		// Check if value contains a serialized (inner) object, (and set error)
		if (preg_match($pattern_obj_inner, $v))
		{
			if (JDEBUG) JFactory::getApplication()->enqueueMessage('Object not allowed inside serialized user-data', 'error');
			$result = false;
		}
		// Check if value is as expected a serialized array, (and unserialize or set error)
		else
		{
			$result = preg_match($pattern_array_outer, $v) ? @ unserialize($v) : false;
		}

		//***
		// *** Return result of unserialization
		//***

		if ($result!==false)
		{
			return $force_array && !is_array($result) ? array($result) : $result;
		}
		else if ($force_value)
		{
			return $force_array ? array($v) : $v;
		}

		return false;
	}


	/**
	 * Get a list of the user groups.
	 *
	 * @return  array
	 * @since   3.2
	 */
	private static function _getUserGroupIDs()
	{
		$db = JFactory::getDbo();

		$query = $db->getQuery(true);
		$query
			->select('a.id')
			->from('#__usergroups AS a');

		return $db->setQuery($query)->loadColumn();
	}


	/**
	 * Get a list of the user groups.
	 *
	 * @return  array
	 * @since   3.2
	 */
	static function getSuperUserID()
	{
		// Return already found super user ID
		static $superUserID = null;
		if ($superUserID !== null)
		{
			return $superUserID;
		}

		// Find usergroups with Super Admin privilege
		$db = JFactory::getDbo();
		$groupIDs = flexicontent_db::_getUserGroupIDs();
		$suGroupIDs = array();

		foreach($groupIDs as $groupID)
		{
			if ( JAccess::checkGroup($groupID, 'core.admin') )
			{
				$suGroupIDs[] = $groupID;
			}
		}

		// Find the fist user that is super id
		$query = 'SELECT DISTINCT id FROM #__users as u'
			. ' JOIN #__user_usergroup_map ugm ON u.id = ugm.user_id AND ugm.group_id IN (' . implode(',', $suGroupIDs) . ')'
			. ' LIMIT 1';

		return $db->setQuery($query)->loadColumn();
	}
}