Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/model.tar

application.php000064400000070613151156772460007605 0ustar00<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_config
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;
use Joomla\Utilities\ArrayHelper;

/**
 * Model for the global configuration
 *
 * @since  3.2
 */
class ConfigModelApplication extends ConfigModelForm
{
	/**
	 * Array of protected password fields from the configuration.php
	 *
	 * @var    array
	 * @since  3.9.23
	 */
	private $protectedConfigurationFields = array('password',
'secret', 'ftp_pass', 'smtppass',
'redis_server_auth', 'session_redis_server_auth');

	/**
	 * Method to get a form object.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data
(default case), false if not.
	 *
	 * @return  mixed  A JForm object on success, false on failure
	 *
	 * @since	1.6
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_config.application',
'application', array('control' => 'jform',
'load_data' => $loadData));

		if (empty($form))
		{
			return false;
		}

		return $form;
	}

	/**
	 * Method to get the configuration data.
	 *
	 * This method will load the global configuration data straight from
	 * JConfig. If configuration data has been saved in the session, that
	 * data will be merged into the original data, overwriting it.
	 *
	 * @return	array  An array containing all global config data.
	 *
	 * @since	1.6
	 */
	public function getData()
	{
		// Get the config data.
		$config = new JConfig;
		$data   = ArrayHelper::fromObject($config);

		// Get the correct driver at runtime
		$data['dbtype'] = JFactory::getDbo()->getName();

		// Prime the asset_id for the rules.
		$data['asset_id'] = 1;

		// Get the text filter data
		$params          = JComponentHelper::getParams('com_config');
		$data['filters'] =
ArrayHelper::fromObject($params->get('filters'));

		// If no filter data found, get from com_content (update of 1.6/1.7 site)
		if (empty($data['filters']))
		{
			$contentParams = JComponentHelper::getParams('com_content');
			$data['filters'] =
ArrayHelper::fromObject($contentParams->get('filters'));
		}

		// Check for data in the session.
		$temp =
JFactory::getApplication()->getUserState('com_config.config.global.data');

		// Merge in the session data.
		if (!empty($temp))
		{
			$data = array_merge($data, $temp);
		}

		return $data;
	}

	/**
	 * Method to save the configuration data.
	 *
	 * @param   array  $data  An array containing all global config data.
	 *
	 * @return	boolean  True on success, false on failure.
	 *
	 * @since	1.6
	 */
	public function save($data)
	{
		$app = JFactory::getApplication();
		$dispatcher = JEventDispatcher::getInstance();
		$config = JFactory::getConfig();

		// Try to load the values from the configuration file
		foreach ($this->protectedConfigurationFields as $fieldKey)
		{
			if (!isset($data[$fieldKey]))
			{
				$data[$fieldKey] = $config->get($fieldKey);
			}
		}

		// Check that we aren't setting wrong database configuration
		$options = array(
			'driver'   => $data['dbtype'],
			'host'     => $data['host'],
			'user'     => $data['user'],
			'password' => $data['password'],
			'database' => $data['db'],
			'prefix'   => $data['dbprefix']
		);

		try
		{
			JDatabaseDriver::getInstance($options)->getVersion();
		}
		catch (Exception $e)
		{
			$app->enqueueMessage(JText::_('JLIB_DATABASE_ERROR_DATABASE_CONNECT'),
'error');

			return false;
		}

		// Check if we can set the Force SSL option
		if ((int) $data['force_ssl'] !== 0 && (int)
$data['force_ssl'] !== (int)
JFactory::getConfig()->get('force_ssl', '0'))
		{
			try
			{
				// Make an HTTPS request to check if the site is available in HTTPS.
				$host    = JUri::getInstance()->getHost();
				$options = new \Joomla\Registry\Registry;
				$options->set('userAgent', 'Mozilla/5.0 (Windows NT
6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0');

				// Do not check for valid server certificate here, leave this to the
user, moreover disable using a proxy if any is configured.
				$options->set('transport.curl',
					array(
						CURLOPT_SSL_VERIFYPEER => false,
						CURLOPT_SSL_VERIFYHOST => false,
						CURLOPT_PROXY => null,
						CURLOPT_PROXYUSERPWD => null,
					)
				);
				$response =
JHttpFactory::getHttp($options)->get('https://' . $host .
JUri::root(true) . '/', array('Host' => $host), 10);

				// If available in HTTPS check also the status code.
				if (!in_array($response->code, array(200, 503, 301, 302, 303, 304,
305, 306, 307, 308, 309, 310, 401), true))
				{
					throw new
RuntimeException(JText::_('COM_CONFIG_ERROR_SSL_NOT_AVAILABLE_HTTP_CODE'));
				}
			}
			catch (RuntimeException $e)
			{
				$data['force_ssl'] = 0;

				// Also update the user state
				$app->setUserState('com_config.config.global.data.force_ssl',
0);

				// Inform the user
				$app->enqueueMessage(JText::sprintf('COM_CONFIG_ERROR_SSL_NOT_AVAILABLE',
$e->getMessage()), 'warning');
			}
		}

		// Save the rules
		if (isset($data['rules']))
		{
			$rules = new JAccessRules($data['rules']);

			// Check that we aren't removing our Super User permission
			// Need to get groups from database, since they might have changed
			$myGroups      =
JAccess::getGroupsByUser(JFactory::getUser()->get('id'));
			$myRules       = $rules->getData();
			$hasSuperAdmin = $myRules['core.admin']->allow($myGroups);

			if (!$hasSuperAdmin)
			{
				$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_REMOVING_SUPER_ADMIN'),
'error');

				return false;
			}

			$asset = JTable::getInstance('asset');

			if ($asset->loadByName('root.1'))
			{
				$asset->rules = (string) $rules;

				if (!$asset->check() || !$asset->store())
				{
					$app->enqueueMessage($asset->getError(), 'error');

					return;
				}
			}
			else
			{
				$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_ROOT_ASSET_NOT_FOUND'),
'error');

				return false;
			}

			unset($data['rules']);
		}

		// Save the text filters
		if (isset($data['filters']))
		{
			$registry = new Registry(array('filters' =>
$data['filters']));

			$extension = JTable::getInstance('extension');

			// Get extension_id
			$extensionId = $extension->find(array('name' =>
'com_config'));

			if ($extension->load((int) $extensionId))
			{
				$extension->params = (string) $registry;

				if (!$extension->check() || !$extension->store())
				{
					$app->enqueueMessage($extension->getError(), 'error');

					return;
				}
			}
			else
			{
				$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_CONFIG_EXTENSION_NOT_FOUND'),
'error');

				return false;
			}

			unset($data['filters']);
		}

		// Get the previous configuration.
		$prev = new JConfig;
		$prev = ArrayHelper::fromObject($prev);

		// Merge the new data in. We do this to preserve values that were not in
the form.
		$data = array_merge($prev, $data);

		/*
		 * Perform miscellaneous options based on configuration settings/changes.
		 */

		// Escape the offline message if present.
		if (isset($data['offline_message']))
		{
			$data['offline_message'] =
JFilterOutput::ampReplace($data['offline_message']);
		}

		// Purge the database session table if we are changing to the database
handler.
		if ($prev['session_handler'] != 'database' &&
$data['session_handler'] == 'database')
		{
			$table = JTable::getInstance('session');
			$table->purge(-1);
		}

		// Set the shared session configuration
		if (isset($data['shared_session']))
		{
			$currentShared = isset($prev['shared_session']) ?
$prev['shared_session'] : '0';

			// Has the user enabled shared sessions?
			if ($data['shared_session'] == 1 && $currentShared ==
0)
			{
				// Generate a random shared session name
				$data['session_name'] = JUserHelper::genRandomPassword(16);
			}

			// Has the user disabled shared sessions?
			if ($data['shared_session'] == 0 && $currentShared ==
1)
			{
				// Remove the session name value
				unset($data['session_name']);
			}
		}

		if (empty($data['cache_handler']))
		{
			$data['caching'] = 0;
		}

		/*
		 * Look for a custom cache_path
		 * First check if a path is given in the submitted data, then check if a
path exists in the previous data, otherwise use the default
		 */
		if (!empty($data['cache_path']))
		{
			$path = $data['cache_path'];
		}
		elseif (!empty($prev['cache_path']))
		{
			$path = $prev['cache_path'];
		}
		else
		{
			$path = JPATH_SITE . '/cache';
		}

		// Give a warning if the cache-folder can not be opened
		if ($data['caching'] > 0 &&
$data['cache_handler'] == 'file' &&
@opendir($path) == false)
		{
			$error = true;

			// If a custom path is in use, try using the system default instead of
disabling cache
			if ($path !== JPATH_SITE . '/cache' &&
@opendir(JPATH_SITE . '/cache') != false)
			{
				try
				{
					JLog::add(
						JText::sprintf('COM_CONFIG_ERROR_CUSTOM_CACHE_PATH_NOTWRITABLE_USING_DEFAULT',
$path, JPATH_SITE . '/cache'),
						JLog::WARNING,
						'jerror'
					);
				}
				catch (RuntimeException $logException)
				{
					$app->enqueueMessage(
						JText::sprintf('COM_CONFIG_ERROR_CUSTOM_CACHE_PATH_NOTWRITABLE_USING_DEFAULT',
$path, JPATH_SITE . '/cache'),
						'warning'
					);
				}

				$path  = JPATH_SITE . '/cache';
				$error = false;

				$data['cache_path'] = '';
			}

			if ($error)
			{
				try
				{
					JLog::add(JText::sprintf('COM_CONFIG_ERROR_CACHE_PATH_NOTWRITABLE',
$path), JLog::WARNING, 'jerror');
				}
				catch (RuntimeException $exception)
				{
					$app->enqueueMessage(JText::sprintf('COM_CONFIG_ERROR_CACHE_PATH_NOTWRITABLE',
$path), 'warning');
				}

				$data['caching'] = 0;
			}
		}

		// Did the user remove their custom cache path?  Don't save the
variable to the config
		if (empty($data['cache_path']))
		{
			unset($data['cache_path']);
		}

		// Clean the cache if disabled but previously enabled or changing cache
handlers; these operations use the `$prev` data already in memory
		if ((!$data['caching'] && $prev['caching'])
|| $data['cache_handler'] !== $prev['cache_handler'])
		{
			try
			{
				JFactory::getCache()->clean();
			}
			catch (JCacheExceptionConnecting $exception)
			{
				try
				{
					JLog::add(JText::_('COM_CONFIG_ERROR_CACHE_CONNECTION_FAILED'),
JLog::WARNING, 'jerror');
				}
				catch (RuntimeException $logException)
				{
					$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_CACHE_CONNECTION_FAILED'),
'warning');
				}
			}
			catch (JCacheExceptionUnsupported $exception)
			{
				try
				{
					JLog::add(JText::_('COM_CONFIG_ERROR_CACHE_DRIVER_UNSUPPORTED'),
JLog::WARNING, 'jerror');
				}
				catch (RuntimeException $logException)
				{
					$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_CACHE_DRIVER_UNSUPPORTED'),
'warning');
				}
			}
		}

		// Create the new configuration object.
		$config = new Registry($data);

		// Overwrite the old FTP credentials with the new ones.
		$temp = JFactory::getConfig();
		$temp->set('ftp_enable', $data['ftp_enable']);
		$temp->set('ftp_host', $data['ftp_host']);
		$temp->set('ftp_port', $data['ftp_port']);
		$temp->set('ftp_user', $data['ftp_user']);
		$temp->set('ftp_pass', $data['ftp_pass']);
		$temp->set('ftp_root', $data['ftp_root']);

		// Clear cache of com_config component.
		$this->cleanCache('_system', 0);
		$this->cleanCache('_system', 1);

		$result = $dispatcher->trigger('onApplicationBeforeSave',
array($config));

		// Store the data.
		if (in_array(false, $result, true))
		{
			throw new
RuntimeException(JText::_('COM_CONFIG_ERROR_UNKNOWN_BEFORE_SAVING'));
		}

		// Write the configuration file.
		$result = $this->writeConfigFile($config);

		// Trigger the after save event.
		$dispatcher->trigger('onApplicationAfterSave',
array($config));

		return $result;
	}

	/**
	 * Method to unset the root_user value from configuration data.
	 *
	 * This method will load the global configuration data straight from
	 * JConfig and remove the root_user value for security, then save the
configuration.
	 *
	 * @return	boolean  True on success, false on failure.
	 *
	 * @since	1.6
	 */
	public function removeroot()
	{
		$dispatcher = JEventDispatcher::getInstance();

		// Get the previous configuration.
		$prev = new JConfig;
		$prev = ArrayHelper::fromObject($prev);

		// Create the new configuration object, and unset the root_user property
		unset($prev['root_user']);
		$config = new Registry($prev);

		$result = $dispatcher->trigger('onApplicationBeforeSave',
array($config));

		// Store the data.
		if (in_array(false, $result, true))
		{
			throw new
RuntimeException(JText::_('COM_CONFIG_ERROR_UNKNOWN_BEFORE_SAVING'));
		}

		// Write the configuration file.
		$result = $this->writeConfigFile($config);

		// Trigger the after save event.
		$dispatcher->trigger('onApplicationAfterSave',
array($config));

		return $result;
	}

	/**
	 * Method to write the configuration to a file.
	 *
	 * @param   Registry  $config  A Registry object containing all global
config data.
	 *
	 * @return	boolean  True on success, false on failure.
	 *
	 * @since	2.5.4
	 * @throws  RuntimeException
	 */
	private function writeConfigFile(Registry $config)
	{
		jimport('joomla.filesystem.path');
		jimport('joomla.filesystem.file');

		// Set the configuration file path.
		$file = JPATH_CONFIGURATION . '/configuration.php';

		// Get the new FTP credentials.
		$ftp = JClientHelper::getCredentials('ftp', true);

		$app = JFactory::getApplication();

		// Attempt to make the file writeable if using FTP.
		if (!$ftp['enabled'] && JPath::isOwner($file)
&& !JPath::setPermissions($file, '0644'))
		{
			$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTWRITABLE'),
'notice');
		}

		// Attempt to write the configuration file as a PHP class named JConfig.
		$configuration = $config->toString('PHP',
array('class' => 'JConfig', 'closingtag'
=> false));

		if (!JFile::write($file, $configuration))
		{
			throw new
RuntimeException(JText::_('COM_CONFIG_ERROR_WRITE_FAILED'));
		}

		// Invalidates the cached configuration file
		if (function_exists('opcache_invalidate'))
		{
			opcache_invalidate($file);
		}

		// Attempt to make the file unwriteable if NOT using FTP.
		if (!$ftp['enabled'] && JPath::isOwner($file)
&& !JPath::setPermissions($file, '0444'))
		{
			$app->enqueueMessage(JText::_('COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTUNWRITABLE'),
'notice');
		}

		return true;
	}

	/**
	 * Method to store the permission values in the asset table.
	 *
	 * This method will get an array with permission key value pairs and
transform it
	 * into json and update the asset table in the database.
	 *
	 * @param   string  $permission  Need an array with Permissions
(component, rule, value and title)
	 *
	 * @return  array  A list of result data.
	 *
	 * @since   3.5
	 */
	public function storePermissions($permission = null)
	{
		$app  = JFactory::getApplication();
		$user = JFactory::getUser();

		if (is_null($permission))
		{
			// Get data from input.
			$permission = array(
				'component' => $app->input->get('comp'),
				'action'    => $app->input->get('action'),
				'rule'      => $app->input->get('rule'),
				'value'     => $app->input->get('value'),
				'title'     => $app->input->get('title',
'', 'RAW')
			);
		}

		// We are creating a new item so we don't have an item id so
don't allow.
		if (substr($permission['component'], -6) ===
'.false')
		{
			$app->enqueueMessage(JText::_('JLIB_RULES_SAVE_BEFORE_CHANGE_PERMISSIONS'),
'error');

			return false;
		}

		// Check if the user is authorized to do this.
		if (!$user->authorise('core.admin',
$permission['component']))
		{
			$app->enqueueMessage(JText::_('JERROR_ALERTNOAUTHOR'),
'error');

			return false;
		}

		$permission['component'] =
empty($permission['component']) ? 'root.1' :
$permission['component'];

		// Current view is global config?
		$isGlobalConfig = $permission['component'] ===
'root.1';

		// Check if changed group has Super User permissions.
		$isSuperUserGroupBefore =
JAccess::checkGroup($permission['rule'], 'core.admin');

		// Check if current user belongs to changed group.
		$currentUserBelongsToGroup = in_array((int)
$permission['rule'], $user->groups) ? true : false;

		// Get current user groups tree.
		$currentUserGroupsTree = JAccess::getGroupsByUser($user->id, true);

		// Check if current user belongs to changed group.
		$currentUserSuperUser = $user->authorise('core.admin');

		// If user is not Super User cannot change the permissions of a group it
belongs to.
		if (!$currentUserSuperUser && $currentUserBelongsToGroup)
		{
			$app->enqueueMessage(JText::_('JLIB_USER_ERROR_CANNOT_CHANGE_OWN_GROUPS'),
'error');

			return false;
		}

		// If user is not Super User cannot change the permissions of a group it
belongs to.
		if (!$currentUserSuperUser && in_array((int)
$permission['rule'], $currentUserGroupsTree))
		{
			$app->enqueueMessage(JText::_('JLIB_USER_ERROR_CANNOT_CHANGE_OWN_PARENT_GROUPS'),
'error');

			return false;
		}

		// If user is not Super User cannot change the permissions of a Super
User Group.
		if (!$currentUserSuperUser && $isSuperUserGroupBefore &&
!$currentUserBelongsToGroup)
		{
			$app->enqueueMessage(JText::_('JLIB_USER_ERROR_CANNOT_CHANGE_SUPER_USER'),
'error');

			return false;
		}

		// If user is not Super User cannot change the Super User permissions in
any group it belongs to.
		if ($isSuperUserGroupBefore && $currentUserBelongsToGroup
&& $permission['action'] === 'core.admin')
		{
			$app->enqueueMessage(JText::_('JLIB_USER_ERROR_CANNOT_DEMOTE_SELF'),
'error');

			return false;
		}

		try
		{
			$asset  = JTable::getInstance('asset');
			$result = $asset->loadByName($permission['component']);

			if ($result === false)
			{
				$data = array($permission['action'] =>
array($permission['rule'] => $permission['value']));

				$rules        = new JAccessRules($data);
				$asset->rules = (string) $rules;
				$asset->name  = (string) $permission['component'];
				$asset->title = (string) $permission['title'];

				// Get the parent asset id so we have a correct tree.
				$parentAsset = JTable::getInstance('Asset');

				if (strpos($asset->name, '.') !== false)
				{
					$assetParts = explode('.', $asset->name);
					$parentAsset->loadByName($assetParts[0]);
					$parentAssetId = $parentAsset->id;
				}
				else
				{
					$parentAssetId = $parentAsset->getRootId();
				}

				/**
				 * @to do: incorrect ACL stored
				 * When changing a permission of an item that doesn't have a row
in the asset table the row a new row is created.
				 * This works fine for item <-> component <-> global config
scenario and component <-> global config scenario.
				 * But doesn't work properly for item <-> section(s)
<-> component <-> global config scenario,
				 * because a wrong parent asset id (the component) is stored.
				 * Happens when there is no row in the asset table (ex: deleted or not
created on update).
				 */

				$asset->setLocation($parentAssetId, 'last-child');
			}
			else
			{
				// Decode the rule settings.
				$temp = json_decode($asset->rules, true);

				// Check if a new value is to be set.
				if (isset($permission['value']))
				{
					// Check if we already have an action entry.
					if (!isset($temp[$permission['action']]))
					{
						$temp[$permission['action']] = array();
					}

					// Check if we already have a rule entry.
					if
(!isset($temp[$permission['action']][$permission['rule']]))
					{
						$temp[$permission['action']][$permission['rule']]
= array();
					}

					// Set the new permission.
					$temp[$permission['action']][$permission['rule']]
= (int) $permission['value'];

					// Check if we have an inherited setting.
					if ($permission['value'] === '')
					{
						unset($temp[$permission['action']][$permission['rule']]);
					}

					// Check if we have any rules.
					if (!$temp[$permission['action']])
					{
						unset($temp[$permission['action']]);
					}
				}
				else
				{
					// There is no value so remove the action as it's not needed.
					unset($temp[$permission['action']]);
				}

				$asset->rules = json_encode($temp, JSON_FORCE_OBJECT);
			}

			if (!$asset->check() || !$asset->store())
			{
				$app->enqueueMessage(JText::_('JLIB_UNKNOWN'),
'error');

				return false;
			}
		}
		catch (Exception $e)
		{
			$app->enqueueMessage($e->getMessage(), 'error');

			return false;
		}

		// All checks done.
		$result = array(
			'text'    => '',
			'class'   => '',
			'result'  => true,
		);

		// Show the current effective calculated permission considering current
group, path and cascade.

		try
		{
			// Get the asset id by the name of the component.
			$query = $this->db->getQuery(true)
				->select($this->db->quoteName('id'))
				->from($this->db->quoteName('#__assets'))
				->where($this->db->quoteName('name') . ' =
' . $this->db->quote($permission['component']));

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

			$assetId = (int) $this->db->loadResult();

			// Fetch the parent asset id.
			$parentAssetId = null;

			/**
			 * @to do: incorrect info
			 * When creating a new item (not saving) it uses the calculated
permissions from the component (item <-> component <-> global
config).
			 * But if we have a section too (item <-> section(s) <->
component <-> global config) this is not correct.
			 * Also, currently it uses the component permission, but should use the
calculated permissions for achild of the component/section.
			 */

			// If not in global config we need the parent_id asset to calculate
permissions.
			if (!$isGlobalConfig)
			{
				// In this case we need to get the component rules too.
				$query->clear()
					->select($this->db->quoteName('parent_id'))
					->from($this->db->quoteName('#__assets'))
					->where($this->db->quoteName('id') . ' =
' . $assetId);

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

				$parentAssetId = (int) $this->db->loadResult();
			}

			// Get the group parent id of the current group.
			$query->clear()
				->select($this->db->quoteName('parent_id'))
				->from($this->db->quoteName('#__usergroups'))
				->where($this->db->quoteName('id') . ' = '
. (int) $permission['rule']);

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

			$parentGroupId = (int) $this->db->loadResult();

			// Count the number of child groups of the current group.
			$query->clear()
				->select('COUNT(' .
$this->db->quoteName('id') . ')')
				->from($this->db->quoteName('#__usergroups'))
				->where($this->db->quoteName('parent_id') . ' =
' . (int) $permission['rule']);

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

			$totalChildGroups = (int) $this->db->loadResult();
		}
		catch (Exception $e)
		{
			$app->enqueueMessage($e->getMessage(), 'error');

			return false;
		}

		// Clear access statistics.
		JAccess::clearStatics();

		// After current group permission is changed we need to check again if
the group has Super User permissions.
		$isSuperUserGroupAfter =
JAccess::checkGroup($permission['rule'], 'core.admin');

		// Get the rule for just this asset (non-recursive) and get the actual
setting for the action for this group.
		$assetRule = JAccess::getAssetRules($assetId, false,
false)->allow($permission['action'],
$permission['rule']);

		// Get the group, group parent id, and group global config recursive
calculated permission for the chosen action.
		$inheritedGroupRule = JAccess::checkGroup($permission['rule'],
$permission['action'], $assetId);

		if (!empty($parentAssetId))
		{
			$inheritedGroupParentAssetRule =
JAccess::checkGroup($permission['rule'],
$permission['action'], $parentAssetId);
		}
		else
		{
			$inheritedGroupParentAssetRule = null;
		}

		$inheritedParentGroupRule = !empty($parentGroupId) ?
JAccess::checkGroup($parentGroupId, $permission['action'],
$assetId) : null;

		// Current group is a Super User group, so calculated setting is
"Allowed (Super User)".
		if ($isSuperUserGroupAfter)
		{
			$result['class'] = 'label label-success';
			$result['text'] = '<span class="icon-lock
icon-white" aria-hidden="true"></span>' .
JText::_('JLIB_RULES_ALLOWED_ADMIN');
		}
		// Not super user.
		else
		{
			// First get the real recursive calculated setting and add (Inherited)
to it.

			// If recursive calculated setting is "Denied" or null.
Calculated permission is "Not Allowed (Inherited)".
			if ($inheritedGroupRule === null || $inheritedGroupRule === false)
			{
				$result['class'] = 'label label-important';
				$result['text']  =
JText::_('JLIB_RULES_NOT_ALLOWED_INHERITED');
			}
			// If recursive calculated setting is "Allowed". Calculated
permission is "Allowed (Inherited)".
			else
			{
				$result['class'] = 'label label-success';
				$result['text']  =
JText::_('JLIB_RULES_ALLOWED_INHERITED');
			}

			// Second part: Overwrite the calculated permissions labels if there is
an explicit permission in the current group.

			/**
			 * @todo: incorrect info
			 * If a component has a permission that doesn't exists in global
config (ex: frontend editing in com_modules) by default
			 * we get "Not Allowed (Inherited)" when we should get
"Not Allowed (Default)".
			 */

			// If there is an explicit permission "Not Allowed".
Calculated permission is "Not Allowed".
			if ($assetRule === false)
			{
				$result['class'] = 'label label-important';
				$result['text']  =
JText::_('JLIB_RULES_NOT_ALLOWED');
			}
			// If there is an explicit permission is "Allowed". Calculated
permission is "Allowed".
			elseif ($assetRule === true)
			{
				$result['class'] = 'label label-success';
				$result['text']  = JText::_('JLIB_RULES_ALLOWED');
			}

			// Third part: Overwrite the calculated permissions labels for special
cases.

			// Global configuration with "Not Set" permission. Calculated
permission is "Not Allowed (Default)".
			if (empty($parentGroupId) && $isGlobalConfig === true &&
$assetRule === null)
			{
				$result['class'] = 'label label-important';
				$result['text']  =
JText::_('JLIB_RULES_NOT_ALLOWED_DEFAULT');
			}

			/**
			 * Component/Item with explicit "Denied" permission at parent
Asset (Category, Component or Global config) configuration.
			 * Or some parent group has an explicit "Denied".
			 * Calculated permission is "Not Allowed (Locked)".
			 */
			elseif ($inheritedGroupParentAssetRule === false ||
$inheritedParentGroupRule === false)
			{
				$result['class'] = 'label label-important';
				$result['text']  = '<span class="icon-lock
icon-white" aria-hidden="true"></span>' .
JText::_('JLIB_RULES_NOT_ALLOWED_LOCKED');
			}
		}

		// If removed or added super user from group, we need to refresh the page
to recalculate all settings.
		if ($isSuperUserGroupBefore != $isSuperUserGroupAfter)
		{
			$app->enqueueMessage(JText::_('JLIB_RULES_NOTICE_RECALCULATE_GROUP_PERMISSIONS'),
'notice');
		}

		// If this group has child groups, we need to refresh the page to
recalculate the child settings.
		if ($totalChildGroups > 0)
		{
			$app->enqueueMessage(JText::_('JLIB_RULES_NOTICE_RECALCULATE_GROUP_CHILDS_PERMISSIONS'),
'notice');
		}

		return $result;
	}

	/**
	 * Method to send a test mail which is called via an AJAX request
	 *
	 * @return boolean
	 *
	 * @since   3.5
	 * @throws Exception
	 */
	public function sendTestMail()
	{
		// Set the new values to test with the current settings
		$app      = JFactory::getApplication();
		$input    = $app->input;
		$smtppass = $input->get('smtppass', null, 'RAW');

		$app->set('smtpauth', $input->get('smtpauth'));
		$app->set('smtpuser', $input->get('smtpuser',
'', 'STRING'));
		$app->set('smtphost', $input->get('smtphost'));
		$app->set('smtpsecure',
$input->get('smtpsecure'));
		$app->set('smtpport', $input->get('smtpport'));
		$app->set('mailfrom', $input->get('mailfrom',
'', 'STRING'));
		$app->set('fromname', $input->get('fromname',
'', 'STRING'));
		$app->set('mailer', $input->get('mailer'));
		$app->set('mailonline',
$input->get('mailonline'));

		// Use smtppass only if it was submitted
		if ($smtppass !== null)
		{
			$app->set('smtppass', $smtppass);
		}

		$mail = JFactory::getMailer();

		// Prepare email and send try to send it
		$mailSubject = JText::sprintf('COM_CONFIG_SENDMAIL_SUBJECT',
$app->get('sitename'));
		$mailBody    = JText::sprintf('COM_CONFIG_SENDMAIL_BODY',
JText::_('COM_CONFIG_SENDMAIL_METHOD_' .
strtoupper($mail->Mailer)));

		if ($mail->sendMail($app->get('mailfrom'),
$app->get('fromname'), $app->get('mailfrom'),
$mailSubject, $mailBody) === true)
		{
			$methodName = JText::_('COM_CONFIG_SENDMAIL_METHOD_' .
strtoupper($mail->Mailer));

			// If JMail send the mail using PHP Mail as fallback.
			if ($mail->Mailer != $app->get('mailer'))
			{
				$app->enqueueMessage(JText::sprintf('COM_CONFIG_SENDMAIL_SUCCESS_FALLBACK',
$app->get('mailfrom'), $methodName), 'warning');
			}
			else
			{
				$app->enqueueMessage(JText::sprintf('COM_CONFIG_SENDMAIL_SUCCESS',
$app->get('mailfrom'), $methodName), 'message');
			}

			return true;
		}

		$app->enqueueMessage(JText::_('COM_CONFIG_SENDMAIL_ERROR'),
'error');

		return false;
	}
}
component.php000064400000012557151156772460007307 0ustar00<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_config
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Model for component configuration
 *
 * @since  3.2
 */
class ConfigModelComponent extends ConfigModelForm
{
	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @return	void
	 *
	 * @since	3.2
	 */
	protected function populateState()
	{
		$input = JFactory::getApplication()->input;

		// Set the component (option) we are dealing with.
		$component = $input->get('component');
		$state = $this->loadState();
		$state->set('component.option', $component);

		// Set an alternative path for the configuration file.
		if ($path = $input->getString('path'))
		{
			$path = JPath::clean(JPATH_SITE . '/' . $path);
			JPath::check($path);
			$state->set('component.path', $path);
		}

		$this->setState($state);
	}

	/**
	 * Method to get a form object.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data
(default case), false if not.
	 *
	 * @return  mixed  A JForm object on success, false on failure
	 *
	 * @since	3.2
	 */
	public function getForm($data = array(), $loadData = true)
	{
		$state = $this->getState();
		$option = $state->get('component.option');

		if ($path = $state->get('component.path'))
		{
			// Add the search path for the admin component config.xml file.
			JForm::addFormPath($path);
		}
		else
		{
			// Add the search path for the admin component config.xml file.
			JForm::addFormPath(JPATH_ADMINISTRATOR . '/components/' .
$option);
		}

		// Get the form.
		$form = $this->loadForm(
			'com_config.component',
			'config',
			array('control' => 'jform', 'load_data'
=> $loadData),
			false,
			'/config'
		);

		if (empty($form))
		{
			return false;
		}

		$lang = JFactory::getLanguage();
		$lang->load($option, JPATH_BASE, null, false, true)
		|| $lang->load($option, JPATH_BASE . "/components/$option",
null, false, true);

		return $form;
	}

	/**
	 * Get the component information.
	 *
	 * @return	object
	 *
	 * @since	3.2
	 */
	public function getComponent()
	{
		$state = $this->getState();
		$option = $state->get('component.option');

		// Load common and local language files.
		$lang = JFactory::getLanguage();
		$lang->load($option, JPATH_BASE, null, false, true)
		|| $lang->load($option, JPATH_BASE . "/components/$option",
null, false, true);

		$result = JComponentHelper::getComponent($option);

		return $result;
	}

	/**
	 * Method to save the configuration data.
	 *
	 * @param   array  $data  An array containing all global config data.
	 *
	 * @return  boolean  True on success, false on failure.
	 *
	 * @since	3.2
	 * @throws  RuntimeException
	 */
	public function save($data)
	{
		$table      = JTable::getInstance('extension');
		$dispatcher = JEventDispatcher::getInstance();
		$context    = $this->option . '.' . $this->name;
		JPluginHelper::importPlugin('extension');

		// Check super user group.
		if (isset($data['params']) &&
!JFactory::getUser()->authorise('core.admin'))
		{
			$form = $this->getForm(array(), false);

			foreach ($form->getFieldsets() as $fieldset)
			{
				foreach ($form->getFieldset($fieldset->name) as $field)
				{
					if ($field->type === 'UserGroupList' &&
isset($data['params'][$field->fieldname])
						&& (int)
$field->getAttribute('checksuperusergroup', 0) === 1
						&&
JAccess::checkGroup($data['params'][$field->fieldname],
'core.admin'))
					{
						throw new
RuntimeException(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
					}
				}
			}
		}

		// Save the rules.
		if (isset($data['params']) &&
isset($data['params']['rules']))
		{
			if (!JFactory::getUser()->authorise('core.admin',
$data['option']))
			{
				throw new
RuntimeException(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
			}

			$rules = new JAccessRules($data['params']['rules']);
			$asset = JTable::getInstance('asset');

			if (!$asset->loadByName($data['option']))
			{
				$root = JTable::getInstance('asset');
				$root->loadByName('root.1');
				$asset->name = $data['option'];
				$asset->title = $data['option'];
				$asset->setLocation($root->id, 'last-child');
			}

			$asset->rules = (string) $rules;

			if (!$asset->check() || !$asset->store())
			{
				throw new RuntimeException($asset->getError());
			}

			// We don't need this anymore
			unset($data['option']);
			unset($data['params']['rules']);
		}

		// Load the previous Data
		if (!$table->load($data['id']))
		{
			throw new RuntimeException($table->getError());
		}

		unset($data['id']);

		// Bind the data.
		if (!$table->bind($data))
		{
			throw new RuntimeException($table->getError());
		}

		// Check the data.
		if (!$table->check())
		{
			throw new RuntimeException($table->getError());
		}

		$result = $dispatcher->trigger('onExtensionBeforeSave',
array($context, $table, false));

			// Store the data.
		if (in_array(false, $result, true) || !$table->store())
		{
			throw new RuntimeException($table->getError());
		}

		// Trigger the after save event.
		$dispatcher->trigger('onExtensionAfterSave', array($context,
$table, false));

		// Clean the component cache.
		$this->cleanCache('_system', 0);
		$this->cleanCache('_system', 1);

		return true;
	}
}
field/configcomponents.php000064400000003461151156772460011735
0ustar00<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_config
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Utilities\ArrayHelper;

JFormHelper::loadFieldClass('List');

/**
 * Text Filters form field.
 *
 * @since  3.7.0
 */
class JFormFieldConfigComponents extends JFormFieldList
{
	/**
	 * The form field type.
	 *
	 * @var		string
	 * @since	3.7.0
	 */
	public $type = 'ConfigComponents';

	/**
	 * Method to get a list of options for a list input.
	 *
	 * @return	array  An array of JHtml options.
	 *
	 * @since   3.7.0
	 */
	protected function getOptions()
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('name AS text, element AS value')
			->from('#__extensions')
			->where('enabled >= 1')
			->where('type =' . $db->quote('component'));

		$items = $db->setQuery($query)->loadObjectList();

		if ($items)
		{
			$lang = JFactory::getLanguage();

			foreach ($items as &$item)
			{
				// Load language
				$extension = $item->value;

				if (JFile::exists(JPATH_ADMINISTRATOR . '/components/' .
$extension . '/config.xml'))
				{
					$source = JPATH_ADMINISTRATOR . '/components/' . $extension;
					$lang->load("$extension.sys", JPATH_ADMINISTRATOR, null,
false, true)
					|| $lang->load("$extension.sys", $source, null, false,
true);

					// Translate component name
					$item->text = JText::_($item->text);
				}
				else
				{
					$item = null;
				}
			}

			// Sort by component name
			$items = ArrayHelper::sortObjects(array_filter($items),
'text', 1, true, true);
		}

		// Merge any additional options in the XML definition.
		$options = array_merge(parent::getOptions(), $items);

		return $options;
	}
}
field/filters.php000064400000015004151156772460010026 0ustar00<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_config
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Text Filters form field.
 *
 * @since  1.6
 */
class JFormFieldFilters extends JFormField
{
	/**
	 * The form field type.
	 *
	 * @var		string
	 * @since	1.6
	 */
	public $type = 'Filters';

	/**
	 * Method to get the field input markup.
	 *
	 * TODO: Add access check.
	 *
	 * @return	string	The field input markup.
	 *
	 * @since	1.6
	 */
	protected function getInput()
	{
		// Load Framework
		JHtml::_('jquery.framework');

		// Add translation string for notification
		JText::script('COM_CONFIG_TEXT_FILTERS_NOTE');

		// Add Javascript
		$doc = JFactory::getDocument();
		$doc->addScriptDeclaration('
			jQuery( document ).ready(function( $ ) {
				$("#filter-config select").change(function() {
					var currentFilter =
$(this).children("option:selected").val();

					if($(this).children("option:selected").val() ===
"NONE") {
						var child = $("#filter-config select[data-parent=" +
$(this).attr("data-id") + "]");
					
						while(child.length !== 0) {
							if(child.children("option:selected").val() !==
"NONE") {
								alert(Joomla.JText._("COM_CONFIG_TEXT_FILTERS_NOTE"));
								break;
							}
							
							child = $("#filter-config select[data-parent=" +
child.attr("data-id") + "]");
						}
						
						return;
					}

					var parent = $("#filter-config select[data-id=" +
$(this).attr("data-parent") + "]");

					while(parent.length !== 0) {
						if(parent.children("option:selected").val() ===
"NONE") {
							alert(Joomla.JText._("COM_CONFIG_TEXT_FILTERS_NOTE"));
							break;
						}
						
						parent = $("#filter-config select[data-id=" +
parent.attr("data-parent") + "]")
					}
				});
			});
		');

		// Get the available user groups.
		$groups = $this->getUserGroups();

		// Build the form control.
		$html = array();

		// Open the table.
		$html[] = '<table id="filter-config" class="table
table-striped">';

		// The table heading.
		$html[] = '	<thead>';
		$html[] = '	<tr>';
		$html[] = '		<th>';
		$html[] = '			<span class="acl-action">' .
JText::_('JGLOBAL_FILTER_GROUPS_LABEL') .
'</span>';
		$html[] = '		</th>';
		$html[] = '		<th>';
		$html[] = '			<span class="acl-action">' .
JText::_('JGLOBAL_FILTER_TYPE_LABEL') .
'</span>';
		$html[] = '		</th>';
		$html[] = '		<th>';
		$html[] = '			<span class="acl-action">' .
JText::_('JGLOBAL_FILTER_TAGS_LABEL') .
'</span>';
		$html[] = '		</th>';
		$html[] = '		<th>';
		$html[] = '			<span class="acl-action">' .
JText::_('JGLOBAL_FILTER_ATTRIBUTES_LABEL') .
'</span>';
		$html[] = '		</th>';
		$html[] = '	</tr>';
		$html[] = '	</thead>';

		// The table body.
		$html[] = '	<tbody>';

		foreach ($groups as $group)
		{
			if (!isset($this->value[$group->value]))
			{
				$this->value[$group->value] = array('filter_type' =>
'BL', 'filter_tags' => '',
'filter_attributes' => '');
			}

			$group_filter = $this->value[$group->value];

			$group_filter['filter_tags']       =
!empty($group_filter['filter_tags']) ?
$group_filter['filter_tags'] : '';
			$group_filter['filter_attributes'] =
!empty($group_filter['filter_attributes']) ?
$group_filter['filter_attributes'] : '';

			$html[] = '	<tr>';
			$html[] = '		<td class="acl-groups left">';
			$html[] = '			' .
JLayoutHelper::render('joomla.html.treeprefix',
array('level' => $group->level + 1)) . $group->text;
			$html[] = '		</td>';
			$html[] = '		<td>';
			$html[] = '				<select'
				. ' name="' . $this->name . '[' .
$group->value . '][filter_type]"'
				. ' id="' . $this->id . $group->value .
'_filter_type"'
				. ' data-parent="' . ($group->parent) . '"
'
				. ' data-id="' . ($group->value) . '"
'
				. ' class="novalidate"'
				. '>';
			$html[] = '					<option value="BL"' .
($group_filter['filter_type'] == 'BL' ? '
selected="selected"' : '') . '>'
				. JText::_('COM_CONFIG_FIELD_FILTERS_DEFAULT_BLACK_LIST') .
'</option>';
			$html[] = '					<option value="CBL"' .
($group_filter['filter_type'] == 'CBL' ? '
selected="selected"' : '') . '>'
				. JText::_('COM_CONFIG_FIELD_FILTERS_CUSTOM_BLACK_LIST') .
'</option>';
			$html[] = '					<option value="WL"' .
($group_filter['filter_type'] == 'WL' ? '
selected="selected"' : '') . '>'
				. JText::_('COM_CONFIG_FIELD_FILTERS_WHITE_LIST') .
'</option>';
			$html[] = '					<option value="NH"' .
($group_filter['filter_type'] == 'NH' ? '
selected="selected"' : '') . '>'
				. JText::_('COM_CONFIG_FIELD_FILTERS_NO_HTML') .
'</option>';
			$html[] = '					<option value="NONE"' .
($group_filter['filter_type'] == 'NONE' ? '
selected="selected"' : '') . '>'
				. JText::_('COM_CONFIG_FIELD_FILTERS_NO_FILTER') .
'</option>';
			$html[] = '				</select>';
			$html[] = '		</td>';
			$html[] = '		<td>';
			$html[] = '				<input'
				. ' name="' . $this->name . '[' .
$group->value . '][filter_tags]"'
				. ' type="text"'
				. ' id="' . $this->id . $group->value .
'_filter_tags" class="novalidate"'
				. ' value="' .
htmlspecialchars($group_filter['filter_tags'], ENT_QUOTES) .
'"'
				. '/>';
			$html[] = '		</td>';
			$html[] = '		<td>';
			$html[] = '				<input'
				. ' name="' . $this->name . '[' .
$group->value . '][filter_attributes]"'
				. ' type="text"'
				. ' id="' . $this->id . $group->value .
'_filter_attributes" class="novalidate"'
				. ' value="' .
htmlspecialchars($group_filter['filter_attributes'], ENT_QUOTES)
. '"'
				. '/>';
			$html[] = '		</td>';
			$html[] = '	</tr>';
		}

		$html[] = '	</tbody>';

		// Close the table.
		$html[] = '</table>';

		// Add notes
		$html[] = '<div class="alert">';
		$html[] = '<p>' .
JText::_('JGLOBAL_FILTER_TYPE_DESC') . '</p>';
		$html[] = '<p>' .
JText::_('JGLOBAL_FILTER_TAGS_DESC') . '</p>';
		$html[] = '<p>' .
JText::_('JGLOBAL_FILTER_ATTRIBUTES_DESC') .
'</p>';
		$html[] = '</div>';

		return implode("\n", $html);
	}

	/**
	 * A helper to get the list of user groups.
	 *
	 * @return	array
	 *
	 * @since	1.6
	 */
	protected function getUserGroups()
	{
		// Get a database object.
		$db = JFactory::getDbo();

		// Get the user groups from the database.
		$query = $db->getQuery(true);
		$query->select('a.id AS value, a.title AS text, COUNT(DISTINCT
b.id) AS level, a.parent_id as parent');
		$query->from('#__usergroups AS a');
		$query->join('LEFT', '#__usergroups AS b on a.lft >
b.lft AND a.rgt < b.rgt');
		$query->group('a.id, a.title, a.lft');
		$query->order('a.lft ASC');
		$db->setQuery($query);
		$options = $db->loadObjectList();

		return $options;
	}
}
form/application.xml000064400000072644151156772460010567 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<form>
	<fieldset
		name="cache"
		label="COM_CONFIG_CACHE_SETTINGS_LABEL">

		<field
			name="cache_handler"
			type="cachehandler"
			label="COM_CONFIG_FIELD_CACHE_HANDLER_LABEL"
			description="COM_CONFIG_FIELD_CACHE_HANDLER_DESC"
			default=""
			filter="word"
		/>

		<field
			name="cache_path"
			type="text"
			label="COM_CONFIG_FIELD_CACHE_PATH_LABEL"
			description="COM_CONFIG_FIELD_CACHE_PATH_DESC"
			showon="cache_handler:file"
			filter="string"
			size="50"
		/>

		<field
			name="memcache_persist"
			type="radio"
			label="COM_CONFIG_FIELD_MEMCACHE_PERSISTENT_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_PERSISTENT_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			showon="cache_handler:memcache"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="memcache_compress"
			type="radio"
			label="COM_CONFIG_FIELD_MEMCACHE_COMPRESSION_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_COMPRESSION_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			showon="cache_handler:memcache"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="memcache_server_host"
			type="text"
			label="COM_CONFIG_FIELD_MEMCACHE_HOST_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_HOST_DESC"
			default="localhost"
			showon="cache_handler:memcache"
			filter="string"
			size="25"
		/>

		<field
			name="memcache_server_port"
			type="number"
			label="COM_CONFIG_FIELD_MEMCACHE_PORT_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_PORT_DESC"
			showon="cache_handler:memcache"
			min="1"
			max="65535"
			default="11211"
			filter="integer"
			validate="number"
			size="5"
		/>

		<field
			name="memcached_persist"
			type="radio"
			label="COM_CONFIG_FIELD_MEMCACHE_PERSISTENT_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_PERSISTENT_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			showon="cache_handler:memcached"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="memcached_compress"
			type="radio"
			label="COM_CONFIG_FIELD_MEMCACHE_COMPRESSION_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_COMPRESSION_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			showon="cache_handler:memcached"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="memcached_server_host"
			type="text"
			label="COM_CONFIG_FIELD_MEMCACHE_HOST_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_HOST_DESC"
			default="localhost"
			showon="cache_handler:memcached"
			filter="string"
			size="25"
		/>

		<field
			name="memcached_server_port"
			type="number"
			label="COM_CONFIG_FIELD_MEMCACHE_PORT_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_PORT_DESC"
			showon="cache_handler:memcached"
			min="1"
			max="65535"
			default="11211"
			filter="integer"
			validate="number"
			size="5"
		/>

		<field
			name="redis_persist"
			type="radio"
			label="COM_CONFIG_FIELD_REDIS_PERSISTENT_LABEL"
			description="COM_CONFIG_FIELD_REDIS_PERSISTENT_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			filter="integer"
			showon="cache_handler:redis"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="redis_server_host"
			type="text"
			label="COM_CONFIG_FIELD_REDIS_HOST_LABEL"
			description="COM_CONFIG_FIELD_REDIS_HOST_DESC"
			default="localhost"
			filter="string"
			showon="cache_handler:redis"
			size="25"
		/>

		<field
			name="redis_server_port"
			type="number"
			label="COM_CONFIG_FIELD_REDIS_PORT_LABEL"
			description="COM_CONFIG_FIELD_REDIS_PORT_DESC"
			showon="cache_handler:redis"
			min="1"
			max="65535"
			default="6379"
			filter="integer"
			validate="number"
			size="5"
		/>

		<field
			name="redis_server_auth"
			type="password"
			label="COM_CONFIG_FIELD_REDIS_AUTH_LABEL"
			description="COM_CONFIG_FIELD_REDIS_AUTH_DESC"
			filter="raw"
			showon="cache_handler:redis"
			autocomplete="off"
			size="30"
			hint="***************"
			lock="true"
		/>

		<field
			name="redis_server_db"
			type="number"
			label="COM_CONFIG_FIELD_REDIS_DB_LABEL"
			description="COM_CONFIG_FIELD_REDIS_DB_DESC"
			default="0"
			filter="integer"
			showon="cache_handler:redis"
			size="4"
		/>

		<field
			name="cachetime"
			type="number"
			label="COM_CONFIG_FIELD_CACHE_TIME_LABEL"
			description="COM_CONFIG_FIELD_CACHE_TIME_DESC"
			min="1"
			default="15"
			filter="integer"
			validate="number"
			size="6"
		/>

		<field
			name="cache_platformprefix"
			type="radio"
			label="COM_CONFIG_FIELD_CACHE_PLATFORMPREFIX_LABEL"
			description="COM_CONFIG_FIELD_CACHE_PLATFORMPREFIX_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="caching"
			type="list"
			label="COM_CONFIG_FIELD_CACHE_LABEL"
			description="COM_CONFIG_FIELD_CACHE_DESC"
			default="2"
			filter="integer"
			>
			<option
value="0">COM_CONFIG_FIELD_VALUE_CACHE_OFF</option>
			<option
value="1">COM_CONFIG_FIELD_VALUE_CACHE_CONSERVATIVE</option>
			<option
value="2">COM_CONFIG_FIELD_VALUE_CACHE_PROGRESSIVE</option>
		</field>

	</fieldset>

	<fieldset
		name="memcache"
		label="COM_CONFIG_MEMCACHE_SETTINGS_LABEL">
	</fieldset>

	<fieldset
		name="database"
		label="CONFIG_DATABASE_SETTINGS_LABEL">

		<field
			name="dbtype"
			type="databaseconnection"
			label="COM_CONFIG_FIELD_DATABASE_TYPE_LABEL"
			description="COM_CONFIG_FIELD_DATABASE_TYPE_DESC"
			supported="mysql,mysqli,pgsql,pdomysql,postgresql,sqlsrv,sqlazure"
			filter="string"
		/>

		<field
			name="host"
			type="text"
			label="COM_CONFIG_FIELD_DATABASE_HOST_LABEL"
			description="COM_CONFIG_FIELD_DATABASE_HOST_DESC"
			required="true"
			filter="string"
			size="30"
		/>

		<field
			name="user"
			type="text"
			label="COM_CONFIG_FIELD_DATABASE_USERNAME_LABEL"
			description="COM_CONFIG_FIELD_DATABASE_USERNAME_DESC"
			required="true"
			filter="string"
			size="30"
		/>

		<field
			name="password"
			type="password"
			label="COM_CONFIG_FIELD_DATABASE_PASSWORD_LABEL"
			description="COM_CONFIG_FIELD_DATABASE_PASSWORD_DESC"
			filter="raw"
			autocomplete="off"
			size="30"
			lock="true"
		/>

		<field
			name="db"
			type="text"
			label="COM_CONFIG_FIELD_DATABASE_NAME_LABEL"
			description="COM_CONFIG_FIELD_DATABASE_NAME_DESC"
			required="true"
			filter="string"
			size="30"
		/>

		<field
			name="dbprefix"
			type="text"
			label="COM_CONFIG_FIELD_DATABASE_PREFIX_LABEL"
			description="COM_CONFIG_FIELD_DATABASE_PREFIX_DESC"
			default="jos_"
			filter="string"
			size="10"
		/>

	</fieldset>

	<fieldset
		name="debug"
		label="CONFIG_DEBUG_SETTINGS_LABEL">

		<field
			name="debug"
			type="radio"
			label="COM_CONFIG_FIELD_DEBUG_SYSTEM_LABEL"
			description="COM_CONFIG_FIELD_DEBUG_SYSTEM_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="debug_lang"
			type="radio"
			label="COM_CONFIG_FIELD_DEBUG_LANG_LABEL"
			description="COM_CONFIG_FIELD_DEBUG_LANG_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="debug_lang_const"
			type="radio"
			label="COM_CONFIG_FIELD_DEBUG_CONST_LANG_LABEL"
			description="COM_CONFIG_FIELD_DEBUG_CONST_LANG_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			filter="integer"
			showon="debug_lang:1"
			>
			<option
value="0">COM_CONFIG_FIELD_DEBUG_CONST</option>
			<option
value="1">COM_CONFIG_FIELD_DEBUG_VALUE</option>
		</field>

	</fieldset>

	<fieldset name="ftp"
label="CONFIG_FTP_SETTINGS_LABEL">

		<field
			name="ftp_enable"
			type="radio"
			label="COM_CONFIG_FIELD_FTP_ENABLE_LABEL"
			description="COM_CONFIG_FIELD_FTP_ENABLE_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="ftp_host"
			type="text"
			label="COM_CONFIG_FIELD_FTP_HOST_LABEL"
			description="COM_CONFIG_FIELD_FTP_HOST_DESC"
			filter="string"
			showon="ftp_enable:1"
			size="14"
		/>

		<field
			name="ftp_port"
			type="number"
			label="COM_CONFIG_FIELD_FTP_PORT_LABEL"
			description="COM_CONFIG_FIELD_FTP_PORT_DESC"
			showon="ftp_enable:1"
			min="1"
			max="65535"
			hint="21"
			validate="number"
			filter="integer"
			size="5"
		/>

		<field
			name="ftp_user"
			type="text"
			label="COM_CONFIG_FIELD_FTP_USERNAME_LABEL"
			description="COM_CONFIG_FIELD_FTP_USERNAME_DESC"
			filter="string"
			showon="ftp_enable:1"
			autocomplete="off"
			size="25"
		/>

		<field
			name="ftp_pass"
			type="password"
			label="COM_CONFIG_FIELD_FTP_PASSWORD_LABEL"
			description="COM_CONFIG_FIELD_FTP_PASSWORD_DESC"
			filter="raw"
			showon="ftp_enable:1"
			autocomplete="off"
			size="25"
			lock="true"
		/>

		<field
			name="ftp_root"
			type="text"
			label="COM_CONFIG_FIELD_FTP_ROOT_LABEL"
			description="COM_CONFIG_FIELD_FTP_ROOT_DESC"
			showon="ftp_enable:1"
			filter="string"
			size="50"
		/>

	</fieldset>

	<fieldset
		name="proxy"
		label="CONFIG_PROXY_SETTINGS_LABEL">

		<field
			name="proxy_enable"
			type="radio"
			label="COM_CONFIG_FIELD_PROXY_ENABLE_LABEL"
			description="COM_CONFIG_FIELD_PROXY_ENABLE_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="proxy_host"
			type="text"
			label="COM_CONFIG_FIELD_PROXY_HOST_LABEL"
			description="COM_CONFIG_FIELD_PROXY_HOST_DESC"
			filter="string"
			showon="proxy_enable:1"
			size="14"
		/>

		<field
			name="proxy_port"
			type="number"
			label="COM_CONFIG_FIELD_PROXY_PORT_LABEL"
			description="COM_CONFIG_FIELD_PROXY_PORT_DESC"
			showon="proxy_enable:1"
			min="1"
			max="65535"
			hint="8080"
			validate="number"
			filter="integer"
			size="5"
		/>

		<field
			name="proxy_user"
			type="text"
			label="COM_CONFIG_FIELD_PROXY_USERNAME_LABEL"
			description="COM_CONFIG_FIELD_PROXY_USERNAME_DESC"
			filter="string"
			showon="proxy_enable:1"
			autocomplete="off"
			size="25"
		/>

		<field
			name="proxy_pass"
			type="password"
			label="COM_CONFIG_FIELD_PROXY_PASSWORD_LABEL"
			description="COM_CONFIG_FIELD_PROXY_PASSWORD_DESC"
			filter="raw"
			showon="proxy_enable:1"
			autocomplete="off"
			size="25"
			lock="true"
		/>

	</fieldset>

	<fieldset
		name="locale"
		label="CONFIG_LOCATION_SETTINGS_LABEL">

		<field
			name="offset"
			type="timezone"
			label="COM_CONFIG_FIELD_SERVER_TIMEZONE_LABEL"
			description="COM_CONFIG_FIELD_SERVER_TIMEZONE_DESC"
			default="UTC"
			>
			<option
value="UTC">JLIB_FORM_VALUE_TIMEZONE_UTC</option>
		</field>

	</fieldset>

	<fieldset
		name="mail"
		label="CONFIG_MAIL_SETTINGS_LABEL">

		<field
			name="mailonline"
			type="radio"
			label="COM_CONFIG_FIELD_MAIL_MAILONLINE_LABEL"
			description="COM_CONFIG_FIELD_MAIL_MAILONLINE_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="massmailoff"
			type="radio"
			label="COM_CONFIG_FIELD_MAIL_MASSMAILOFF_LABEL"
			description="COM_CONFIG_FIELD_MAIL_MASSMAILOFF_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			showon="mailonline:1"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="mailfrom"
			type="email"
			label="COM_CONFIG_FIELD_MAIL_FROM_EMAIL_LABEL"
			description="COM_CONFIG_FIELD_MAIL_FROM_EMAIL_DESC"
			filter="string"
			size="30"
			validate="email"
			showon="mailonline:1"
		/>

		<field
			name="fromname"
			type="text"
			label="COM_CONFIG_FIELD_MAIL_FROM_NAME_LABEL"
			description="COM_CONFIG_FIELD_MAIL_FROM_NAME_DESC"
			filter="string"
			size="30"
			showon="mailonline:1"
		/>

		<field
			name="replyto"
			type="email"
			label="COM_CONFIG_FIELD_MAIL_REPLY_TO_EMAIL_LABEL"
			description="COM_CONFIG_FIELD_MAIL_REPLY_TO_EMAIL_DESC"
			filter="string"
			size="30"
			validate="email"
			showon="mailonline:1"
		/>

		<field
			name="replytoname"
			type="text"
			label="COM_CONFIG_FIELD_MAIL_REPLY_TO_NAME_LABEL"
			description="COM_CONFIG_FIELD_MAIL_REPLY_TO_NAME_DESC"
			filter="string"
			size="30"
			showon="mailonline:1"
		/>

		<field
			name="mailer"
			type="list"
			label="COM_CONFIG_FIELD_MAIL_MAILER_LABEL"
			description="COM_CONFIG_FIELD_MAIL_MAILER_DESC"
			default="mail"
			filter="word"
			showon="mailonline:1"
			>
			<option
value="mail">COM_CONFIG_FIELD_VALUE_PHP_MAIL</option>
			<option
value="sendmail">COM_CONFIG_FIELD_VALUE_SENDMAIL</option>
			<option
value="smtp">COM_CONFIG_FIELD_VALUE_SMTP</option>
		</field>

		<field
			name="sendmail"
			type="text"
			label="COM_CONFIG_FIELD_MAIL_SENDMAIL_PATH_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SENDMAIL_PATH_DESC"
			default="/usr/sbin/sendmail"
			showon="mailonline:1[AND]mailer:sendmail"
			filter="string"
			size="30"
		/>

		<field
			name="smtphost"
			type="text"
			label="COM_CONFIG_FIELD_MAIL_SMTP_HOST_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SMTP_HOST_DESC"
			default="localhost"
			showon="mailonline:1[AND]mailer:smtp"
			filter="string"
			size="30"
		/>

		<field
			name="smtpport"
			type="number"
			label="COM_CONFIG_FIELD_MAIL_SMTP_PORT_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SMTP_PORT_DESC"
			showon="mailonline:1[AND]mailer:smtp"
			min="1"
			max="65535"
			default="25"
			hint="25"
			validate="number"
			filter="integer"
			size="5"
		/>

		<field
			name="smtpsecure"
			type="list"
			label="COM_CONFIG_FIELD_MAIL_SMTP_SECURE_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SMTP_SECURE_DESC"
			default="none"
			showon="mailonline:1[AND]mailer:smtp"
			filter="word"
			>
			<option
value="none">COM_CONFIG_FIELD_VALUE_NONE</option>
			<option
value="ssl">COM_CONFIG_FIELD_VALUE_SSL</option>
			<option
value="tls">COM_CONFIG_FIELD_VALUE_TLS</option>
		</field>

		<field
			name="smtpauth"
			type="radio"
			label="COM_CONFIG_FIELD_MAIL_SMTP_AUTH_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SMTP_AUTH_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			showon="mailonline:1[AND]mailer:smtp"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="smtpuser"
			type="text"
			label="COM_CONFIG_FIELD_MAIL_SMTP_USERNAME_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SMTP_USERNAME_DESC"
			showon="mailonline:1[AND]mailer:smtp[AND]smtpauth:1"
			filter="string"
			autocomplete="off"
			size="30"
		/>

		<field
			name="smtppass"
			type="password"
			label="COM_CONFIG_FIELD_MAIL_SMTP_PASSWORD_LABEL"
			description="COM_CONFIG_FIELD_MAIL_SMTP_PASSWORD_DESC"
			showon="mailonline:1[AND]mailer:smtp[AND]smtpauth:1"
			filter="raw"
			autocomplete="off"
			size="30"
			lock="true"
		/>

	</fieldset>

	<fieldset
		name="metadata"
		label="COM_CONFIG_METADATA_SETTINGS">

		<field
			name="MetaDesc"
			type="textarea"
			label="COM_CONFIG_FIELD_METADESC_LABEL"
			description="COM_CONFIG_FIELD_METADESC_DESC"
			filter="string"
			cols="60"
			rows="3"
		/>

		<field
			name="MetaKeys"
			type="textarea"
			label="COM_CONFIG_FIELD_METAKEYS_LABEL"
			description="COM_CONFIG_FIELD_METAKEYS_DESC"
			filter="string"
			cols="60"
			rows="3"
		/>

		<field
			name="robots"
			type="list"
			label="JFIELD_METADATA_ROBOTS_LABEL"
			description="JFIELD_METADATA_ROBOTS_DESC"
			default=""
			>
			<option value="">index, follow</option>
			<option value="noindex, follow"></option>
			<option value="index, nofollow"></option>
			<option value="noindex, nofollow"></option>
		</field>

		<field
			name="MetaRights"
			type="textarea"
			label="JFIELD_META_RIGHTS_LABEL"
			description="JFIELD_META_RIGHTS_DESC"
			filter="string"
			cols="60"
			rows="2"
		/>

		<field
			name="MetaAuthor"
			type="radio"
			label="COM_CONFIG_FIELD_METAAUTHOR_LABEL"
			description="COM_CONFIG_FIELD_METAAUTHOR_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="MetaVersion"
			type="radio"
			label="COM_CONFIG_FIELD_METAVERSION_LABEL"
			description="COM_CONFIG_FIELD_METAVERSION_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

	</fieldset>

	<fieldset
		name="seo"
		label="CONFIG_SEO_SETTINGS_LABEL">

		<field
			name="sef"
			type="radio"
			label="COM_CONFIG_FIELD_SEF_URL_LABEL"
			description="COM_CONFIG_FIELD_SEF_URL_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="sef_rewrite"
			type="radio"
			label="COM_CONFIG_FIELD_SEF_REWRITE_LABEL"
			description="COM_CONFIG_FIELD_SEF_REWRITE_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			showon="sef:1"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="sef_suffix"
			type="radio"
			label="COM_CONFIG_FIELD_SEF_SUFFIX_LABEL"
			description="COM_CONFIG_FIELD_SEF_SUFFIX_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			showon="sef:1"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="unicodeslugs"
			type="radio"
			label="COM_CONFIG_FIELD_UNICODESLUGS_LABEL"
			description="COM_CONFIG_FIELD_UNICODESLUGS_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			showon="sef:1"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="sitename_pagetitles"
			type="list"
			label="COM_CONFIG_FIELD_SITENAME_PAGETITLES_LABEL"
			description="COM_CONFIG_FIELD_SITENAME_PAGETITLES_DESC"
			default="0"
			filter="integer"
			>
			<option
value="2">COM_CONFIG_FIELD_VALUE_AFTER</option>
			<option
value="1">COM_CONFIG_FIELD_VALUE_BEFORE</option>
			<option value="0">JNO</option>
		</field>

	</fieldset>

	<fieldset
		name="server"
		label="CONFIG_SERVER_SETTINGS_LABEL">

		<field
			name="tmp_path"
			type="text"
			label="COM_CONFIG_FIELD_TEMP_PATH_LABEL"
			description="COM_CONFIG_FIELD_TEMP_PATH_DESC"
			filter="string"
			size="50"
		/>

		<field
			name="gzip"
			type="radio"
			label="COM_CONFIG_FIELD_GZIP_COMPRESSION_LABEL"
			description="COM_CONFIG_FIELD_GZIP_COMPRESSION_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="error_reporting"
			type="list"
			label="COM_CONFIG_FIELD_ERROR_REPORTING_LABEL"
			description="COM_CONFIG_FIELD_ERROR_REPORTING_DESC"
			default="default"
			filter="cmd"
			>
			<option
value="default">COM_CONFIG_FIELD_VALUE_SYSTEM_DEFAULT</option>
			<option
value="none">COM_CONFIG_FIELD_VALUE_NONE</option>
			<option
value="simple">COM_CONFIG_FIELD_VALUE_SIMPLE</option>
			<option
value="maximum">COM_CONFIG_FIELD_VALUE_MAXIMUM</option>
			<option
value="development">COM_CONFIG_FIELD_VALUE_DEVELOPMENT</option>
		</field>

		<field
			name="force_ssl"
			type="list"
			label="COM_CONFIG_FIELD_FORCE_SSL_LABEL"
			description="COM_CONFIG_FIELD_FORCE_SSL_DESC"
			default="-1"
			filter="integer"
			>
			<option
value="0">COM_CONFIG_FIELD_VALUE_NONE</option>
			<option
value="1">COM_CONFIG_FIELD_VALUE_ADMINISTRATOR_ONLY</option>
			<option
value="2">COM_CONFIG_FIELD_VALUE_ENTIRE_SITE</option>
		</field>

	</fieldset>

	<fieldset
		name="session"
		label="CONFIG_SESSION_SETTINGS_LABEL">

		<field
			name="session_handler"
			type="sessionhandler"
			label="COM_CONFIG_FIELD_SESSION_HANDLER_LABEL"
			description="COM_CONFIG_FIELD_SESSION_HANDLER_DESC"
			default="none"
			filter="word"
		/>

		<field
			name="session_memcache_server_host"
			type="text"
			label="COM_CONFIG_FIELD_MEMCACHE_HOST_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_HOST_DESC"
			default="localhost"
			filter="string"
			showon="session_handler:memcache"
			size="25"
		/>

		<field
			name="session_memcache_server_port"
			type="number"
			label="COM_CONFIG_FIELD_MEMCACHE_PORT_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_PORT_DESC"
			showon="session_handler:memcache"
			min="1"
			max="65535"
			default="11211"
			validate="number"
			filter="integer"
			size="5"
		/>

		<field
			name="session_memcached_server_host"
			type="text"
			label="COM_CONFIG_FIELD_MEMCACHE_HOST_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_HOST_DESC"
			default="localhost"
			filter="string"
			showon="session_handler:memcached"
			size="25"
		/>

		<field
			name="session_memcached_server_port"
			type="number"
			label="COM_CONFIG_FIELD_MEMCACHE_PORT_LABEL"
			description="COM_CONFIG_FIELD_MEMCACHE_PORT_DESC"
			showon="session_handler:memcached"
			min="1"
			max="65535"
			default="11211"
			validate="number"
			filter="integer"
			size="5"
		/>

		<field
			name="session_redis_persist"
			type="radio"
			label="COM_CONFIG_FIELD_REDIS_PERSISTENT_LABEL"
			description="COM_CONFIG_FIELD_REDIS_PERSISTENT_DESC"
			class="btn-group btn-group-yesno"
			default="1"
			filter="integer"
			showon="session_handler:redis"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="session_redis_server_host"
			type="text"
			label="COM_CONFIG_FIELD_REDIS_HOST_LABEL"
			description="COM_CONFIG_FIELD_REDIS_HOST_DESC"
			default="localhost"
			filter="string"
			showon="session_handler:redis"
			size="25"
		/>

		<field
			name="session_redis_server_port"
			type="number"
			label="COM_CONFIG_FIELD_REDIS_PORT_LABEL"
			description="COM_CONFIG_FIELD_REDIS_PORT_DESC"
			showon="session_handler:redis"
			min="1"
			max="65535"
			default="6379"
			validate="number"
			filter="integer"
			size="5"
		/>

		<field
			name="session_redis_server_auth"
			type="password"
			label="COM_CONFIG_FIELD_REDIS_AUTH_LABEL"
			description="COM_CONFIG_FIELD_REDIS_AUTH_DESC"
			filter="raw"
			showon="session_handler:redis"
			autocomplete="off"
			size="30"
			lock="true"
		/>

		<field
			name="session_redis_server_db"
			type="number"
			label="COM_CONFIG_FIELD_REDIS_DB_LABEL"
			description="COM_CONFIG_FIELD_REDIS_DB_DESC"
			default="0"
			filter="integer"
			showon="session_handler:redis"
			size="4"
		/>
		<field
			name="lifetime"
			type="number"
			label="COM_CONFIG_FIELD_SESSION_TIME_LABEL"
			description="COM_CONFIG_FIELD_SESSION_TIME_DESC"
			min="1"
			max="16383"
			default="15"
			filter="integer"
			validate="number"
			size="6"
		/>

		<field
			name="shared_session"
			type="radio"
			label="COM_CONFIG_FIELD_SHARED_SESSION_LABEL"
			description="COM_CONFIG_FIELD_SHARED_SESSION_DESC"
			class="btn-group btn-group-yesno"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

	</fieldset>

	<fieldset
		name="site"
		label="CONFIG_SITE_SETTINGS_LABEL">

		<field
			name="sitename"
			type="text"
			label="COM_CONFIG_FIELD_SITE_NAME_LABEL"
			description="COM_CONFIG_FIELD_SITE_NAME_DESC"
			required="true"
			filter="string"
			size="50"
		/>

		<field
			name="offline"
			type="radio"
			label="COM_CONFIG_FIELD_SITE_OFFLINE_LABEL"
			description="COM_CONFIG_FIELD_SITE_OFFLINE_DESC"
			class="btn-group btn-group-yesno btn-group-reversed"
			default="0"
			filter="integer"
			>
			<option value="1">JYES</option>
			<option value="0">JNO</option>
		</field>

		<field
			name="display_offline_message"
			type="list"
			label="COM_CONFIG_FIELD_SITE_DISPLAY_MESSAGE_LABEL"
			description="COM_CONFIG_FIELD_SITE_DISPLAY_MESSAGE_DESC"
			default="1"
			filter="integer"
			showon="offline:1"
			>
			<option value="0">JHIDE</option>
			<option
value="1">COM_CONFIG_FIELD_VALUE_DISPLAY_OFFLINE_MESSAGE_CUSTOM</option>
			<option
value="2">COM_CONFIG_FIELD_VALUE_DISPLAY_OFFLINE_MESSAGE_LANGUAGE</option>
		</field>

		<field
			name="offline_message"
			type="textarea"
			label="COM_CONFIG_FIELD_OFFLINE_MESSAGE_LABEL"
			description="COM_CONFIG_FIELD_OFFLINE_MESSAGE_DESC"
			filter="safehtml"
			cols="60"
			rows="2"
			showon="offline:1[AND]display_offline_message:1"
		/>

		<field
			name="offline_image"
			type="media"
			label="COM_CONFIG_FIELD_OFFLINE_IMAGE_LABEL"
			description="COM_CONFIG_FIELD_OFFLINE_IMAGE_DESC"
			showon="offline:1"
		/>

		<field
			name="frontediting"
			type="list"
			label="COM_CONFIG_FRONTEDITING_LABEL"
			description="COM_CONFIG_FRONTEDITING_DESC"
			default="1"
			filter="integer"
			>
			<option
value="2">COM_CONFIG_FRONTEDITING_MENUSANDMODULES</option>
			<option
value="1">COM_CONFIG_FRONTEDITING_MODULES</option>
			<option value="0">JNONE</option>
		</field>

		<field
			name="editor"
			type="plugins"
			label="COM_CONFIG_FIELD_DEFAULT_EDITOR_LABEL"
			description="COM_CONFIG_FIELD_DEFAULT_EDITOR_DESC"
			folder="editors"
			default="tinymce"
			filter="cmd"
		/>

		<field
			name="captcha"
			type="plugins"
			label="COM_CONFIG_FIELD_DEFAULT_CAPTCHA_LABEL"
			description="COM_CONFIG_FIELD_DEFAULT_CAPTCHA_DESC"
			folder="captcha"
			default="0"
			filter="cmd"
			>
			<option value="0">JOPTION_DO_NOT_USE</option>
		</field>

		<field
			name="access"
			type="accesslevel"
			label="COM_CONFIG_FIELD_DEFAULT_ACCESS_LEVEL_LABEL"
			description="COM_CONFIG_FIELD_DEFAULT_ACCESS_LEVEL_DESC"
			default="1"
			filter="integer"
		/>

		<field
			name="list_limit"
			type="list"
			label="COM_CONFIG_FIELD_DEFAULT_LIST_LIMIT_LABEL"
			description="COM_CONFIG_FIELD_DEFAULT_LIST_LIMIT_DESC"
			default="20"
			filter="integer"
			>
			<option value="5">J5</option>
			<option value="10">J10</option>
			<option value="15">J15</option>
			<option value="20">J20</option>
			<option value="25">J25</option>
			<option value="30">J30</option>
			<option value="50">J50</option>
			<option value="100">J100</option>
			<option value="200">J200</option>
			<option value="500">J500</option>
		</field>

		<field
			name="feed_limit"
			type="list"
			label="COM_CONFIG_FIELD_DEFAULT_FEED_LIMIT_LABEL"
			description="COM_CONFIG_FIELD_DEFAULT_FEED_LIMIT_DESC"
			default="10"
			filter="integer"
			>
			<option value="5">J5</option>
			<option value="10">J10</option>
			<option value="15">J15</option>
			<option value="20">J20</option>
			<option value="25">J25</option>
			<option value="30">J30</option>
			<option value="50">J50</option>
			<option value="100">J100</option>
		</field>

		<field
			name="feed_email"
			type="list"
			label="COM_CONFIG_FIELD_FEED_EMAIL_LABEL"
			description="COM_CONFIG_FIELD_FEED_EMAIL_DESC"
			default="none"
			filter="word"
			>
			<option
value="author">COM_CONFIG_FIELD_VALUE_AUTHOR_EMAIL</option>
			<option
value="site">COM_CONFIG_FIELD_VALUE_SITE_EMAIL</option>
			<option
value="none">COM_CONFIG_FIELD_VALUE_NO_EMAIL</option>

		</field>

	</fieldset>

	<fieldset
		name="system"
		label="CONFIG_SYSTEM_SETTINGS_LABEL">

		<field
			name="log_path"
			type="text"
			label="COM_CONFIG_FIELD_LOG_PATH_LABEL"
			description="COM_CONFIG_FIELD_LOG_PATH_DESC"
			required="true"
			filter="string"
			size="50"
		/>

	</fieldset>

	<fieldset
		name="cookie"
		label="CONFIG_COOKIE_SETTINGS_LABEL">

		<field
			name="cookie_domain"
			type="text"
			label="COM_CONFIG_FIELD_COOKIE_DOMAIN_LABEL"
			description="COM_CONFIG_FIELD_COOKIE_DOMAIN_DESC"
			filter="string"
			size="40"
		/>

		<field
			name="cookie_path"
			type="text"
			label="COM_CONFIG_FIELD_COOKIE_PATH_LABEL"
			description="COM_CONFIG_FIELD_COOKIE_PATH_DESC"
			filter="string"
			size="40"
		/>

	</fieldset>

	<fieldset
		name="permissions"
		label="CONFIG_PERMISSION_SETTINGS_LABEL">

		<field
			name="rules"
			type="rules"
			label="FIELD_RULES_LABEL"
			translate_label="false"
			validate="rules"
			filter="rules"
			>
			<action
				name="core.login.site"
				title="JACTION_LOGIN_SITE"
				description="COM_CONFIG_ACTION_LOGIN_SITE_DESC"
			/>
			<action
				name="core.login.admin"
				title="JACTION_LOGIN_ADMIN"
				description="COM_CONFIG_ACTION_LOGIN_ADMIN_DESC"
			/>
			<action
				name="core.login.offline"
				title="JACTION_LOGIN_OFFLINE"
				description="COM_CONFIG_ACTION_LOGIN_OFFLINE_DESC"
			/>
			<action
				name="core.admin"
				title="JACTION_ADMIN_GLOBAL"
				description="COM_CONFIG_ACTION_ADMIN_DESC"
			/>
			<action
				name="core.options"
				title="JACTION_OPTIONS"
				description="COM_CONFIG_ACTION_OPTIONS_DESC"
			/>
			<action
				name="core.manage"
				title="JACTION_MANAGE"
				description="COM_CONFIG_ACTION_MANAGE_DESC"
			/>
			<action
				name="core.create"
				title="JACTION_CREATE"
				description="COM_CONFIG_ACTION_CREATE_DESC"
			/>
			<action
				name="core.delete"
				title="JACTION_DELETE"
				description="COM_CONFIG_ACTION_DELETE_DESC"
			/>
			<action
				name="core.edit"
				title="JACTION_EDIT"
				description="COM_CONFIG_ACTION_EDIT_DESC"
			/>
			<action
				name="core.edit.state"
				title="JACTION_EDITSTATE"
				description="COM_CONFIG_ACTION_EDITSTATE_DESC"
			/>
			<action
				name="core.edit.own"
				title="JACTION_EDITOWN"
				description="COM_CONFIG_ACTION_EDITOWN_DESC"
			/>
			<action
				name="core.edit.value"
				title="JACTION_EDITVALUE"
				description="COM_CONFIG_ACTION_EDITVALUE_DESC"
			/>
		</field>

	</fieldset>

	<fieldset
		name="filters"
		label="COM_CONFIG_TEXT_FILTERS"
		description="COM_CONFIG_TEXT_FILTERS_DESC">

		<field
			name="filters"
			type="filters"
			label="COM_CONFIG_TEXT_FILTERS"
			filter=""
		/>

	</fieldset>

	<fieldset>

		<field
			name="asset_id"
			type="hidden"
		/>

	</fieldset>
</form>
base.php000064400000002507151157625610006204 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Model
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;

/**
 * Joomla Platform Base Model Class
 *
 * @since       3.0.0
 * @deprecated  4.0 Use the default MVC library
 */
abstract class JModelBase implements JModel
{
	/**
	 * The model state.
	 *
	 * @var    Registry
	 * @since  3.0.0
	 */
	protected $state;

	/**
	 * Instantiate the model.
	 *
	 * @param   Registry  $state  The model state.
	 *
	 * @since   3.0.0
	 */
	public function __construct(Registry $state = null)
	{
		// Setup the model.
		$this->state = isset($state) ? $state : $this->loadState();
	}

	/**
	 * Get the model state.
	 *
	 * @return  Registry  The state object.
	 *
	 * @since   3.0.0
	 */
	public function getState()
	{
		return $this->state;
	}

	/**
	 * Set the model state.
	 *
	 * @param   Registry  $state  The state object.
	 *
	 * @return  void
	 *
	 * @since   3.0.0
	 */
	public function setState(Registry $state)
	{
		$this->state = $state;
	}

	/**
	 * Load the model state.
	 *
	 * @return  Registry  The state object.
	 *
	 * @since   3.0.0
	 */
	protected function loadState()
	{
		return new Registry;
	}
}
database.php000064400000002752151157625610007040 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Model
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;

/**
 * Joomla Platform Database Model Class
 *
 * @since       3.0.0
 * @deprecated  4.0 Use the default MVC library
 */
abstract class JModelDatabase extends JModelBase
{
	/**
	 * The database driver.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.0.0
	 */
	protected $db;

	/**
	 * Instantiate the model.
	 *
	 * @param   Registry         $state  The model state.
	 * @param   JDatabaseDriver  $db     The database adpater.
	 *
	 * @since   3.0.0
	 */
	public function __construct(Registry $state = null, JDatabaseDriver $db =
null)
	{
		parent::__construct($state);

		// Setup the model.
		$this->db = isset($db) ? $db : $this->loadDb();
	}

	/**
	 * Get the database driver.
	 *
	 * @return  JDatabaseDriver  The database driver.
	 *
	 * @since   3.0.0
	 */
	public function getDb()
	{
		return $this->db;
	}

	/**
	 * Set the database driver.
	 *
	 * @param   JDatabaseDriver  $db  The database driver.
	 *
	 * @return  void
	 *
	 * @since   3.0.0
	 */
	public function setDb(JDatabaseDriver $db)
	{
		$this->db = $db;
	}

	/**
	 * Load the database driver.
	 *
	 * @return  JDatabaseDriver  The database driver.
	 *
	 * @since   3.0.0
	 */
	protected function loadDb()
	{
		return JFactory::getDbo();
	}
}
model.php000064400000001355151157625610006372 0ustar00<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Model
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

use Joomla\Registry\Registry;

/**
 * Joomla Platform Model Interface
 *
 * @since       3.0.0
 * @deprecated  4.0 Use the default MVC library
 */
interface JModel
{
	/**
	 * Get the model state.
	 *
	 * @return  Registry  The state object.
	 *
	 * @since   3.0.0
	 */
	public function getState();

	/**
	 * Set the model state.
	 *
	 * @param   Registry  $state  The state object.
	 *
	 * @return  void
	 *
	 * @since   3.0.0
	 */
	public function setState(Registry $state);
}
behavior/access.php000064400000004330151160015660010316 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 * @note        This file has been modified by the Joomla! Project and no
longer reflects the original work of its author.
 */

// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class to filter front-end access to
items
 * based on the viewing access levels.
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelBehaviorAccess extends FOFModelBehavior
{
	/**
	 * This event runs after we have built the query used to fetch a record
	 * list in a model. It is used to apply automatic query filters.
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The model which calls this
event
	 *
	 * @return  void
	 */
	public function onAfterBuildQuery(&$model, &$query)
	{
		// This behavior only applies to the front-end.
		if (!FOFPlatform::getInstance()->isFrontend())
		{
			return;
		}

		// Get the name of the access field
		$table       = $model->getTable();
		$accessField = $table->getColumnAlias('access');

		// Make sure the field actually exists
		if (!in_array($accessField, $table->getKnownFields()))
		{
			return;
		}

		$model->applyAccessFiltering(null);
	}

	/**
	 * The event runs after FOFModel has called FOFTable and retrieved a
single
	 * item from the database. It is used to apply automatic filters.
	 *
	 * @param   FOFModel  &$model   The model which was called
	 * @param   FOFTable  &$record  The record loaded from the database
	 *
	 * @return  void
	 */
	public function onAfterGetItem(&$model, &$record)
	{
		if ($record instanceof FOFTable)
		{
			$fieldName = $record->getColumnAlias('access');

			// Make sure the field actually exists
			if (!in_array($fieldName, $record->getKnownFields()))
			{
				return;
			}

			// Get the user
			$user = FOFPlatform::getInstance()->getUser();

			// Filter by authorised access levels
			if (!in_array($record->$fieldName,
$user->getAuthorisedViewLevels()))
			{
				$record = null;
			}
		}
	}
}
behavior/emptynonzero.php000064400000001532151160015660011627
0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelBehaviorEmptynonzero extends FOFModelBehavior
{
	/**
	 * This event runs when we are building the query used to fetch a record
	 * list in a model
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The query being built
	 *
	 * @return  void
	 */
	public function onBeforeBuildQuery(&$model, &$query)
	{
		$model->setState('_emptynonzero', '1');
	}
}
behavior/enabled.php000064400000004401151160015660010446 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 * @note        This file has been modified by the Joomla! Project and no
longer reflects the original work of its author.
 */

// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class to filter front-end access to
items
 * that are enabled.
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelBehaviorEnabled extends FOFModelBehavior
{
	/**
	 * This event runs after we have built the query used to fetch a record
	 * list in a model. It is used to apply automatic query filters.
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The model which calls this
event
	 *
	 * @return  void
	 */
	public function onAfterBuildQuery(&$model, &$query)
	{
		// This behavior only applies to the front-end.
		if (!FOFPlatform::getInstance()->isFrontend())
		{
			return;
		}

		// Get the name of the enabled field
		$table = $model->getTable();
		$enabledField = $table->getColumnAlias('enabled');

		// Make sure the field actually exists
		if (!in_array($enabledField, $table->getKnownFields()))
		{
			return;
		}

		// Filter by enabled fields only
		$db = FOFPlatform::getInstance()->getDbo();

		// Alias
		$alias = $model->getTableAlias();
		$alias = $alias ? $db->qn($alias) . '.' : '';

		$query->where($alias . $db->qn($enabledField) . ' = ' .
$db->q(1));
	}

	/**
	 * The event runs after FOFModel has called FOFTable and retrieved a
single
	 * item from the database. It is used to apply automatic filters.
	 *
	 * @param   FOFModel  &$model   The model which was called
	 * @param   FOFTable  &$record  The record loaded from the database
	 *
	 * @return  void
	 */
	public function onAfterGetItem(&$model, &$record)
	{
		if ($record instanceof FOFTable)
		{
			$fieldName = $record->getColumnAlias('enabled');

			// Make sure the field actually exists
			if (!in_array($fieldName, $record->getKnownFields()))
			{
				return;
			}

			if ($record->$fieldName != 1)
			{
				$record = null;
			}
		}
	}
}
behavior/filters.php000064400000005145151160015660010532 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelBehaviorFilters extends FOFModelBehavior
{
	/**
	 * This event runs after we have built the query used to fetch a record
	 * list in a model. It is used to apply automatic query filters.
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The model which calls this
event
	 *
	 * @return  void
	 */
	public function onAfterBuildQuery(&$model, &$query)
	{
		$table = $model->getTable();
		$tableName = $table->getTableName();
		$tableKey = $table->getKeyName();
		$db = $model->getDBO();

		$filterzero = $model->getState('_emptynonzero', null);

		$fields = $model->getTableFields();
		$backlist = $model->blacklistFilters();

		foreach ($fields as $fieldname => $fieldtype)
		{
			if (in_array($fieldname, $backlist)) {
				continue;
			}
			$field = new stdClass;
			$field->name = $fieldname;
			$field->type = $fieldtype;
			$field->filterzero = $filterzero;

			$filterName = ($field->name == $tableKey) ? 'id' :
$field->name;
			$filterState = $model->getState($filterName, null);

			$field = FOFModelField::getField($field, array('dbo' =>
$db, 'table_alias' => $model->getTableAlias()));

			if ((is_array($filterState) && (
					array_key_exists('value', $filterState) ||
					array_key_exists('from', $filterState) ||
					array_key_exists('to', $filterState)
				)) || is_object($filterState))
			{
				$options = new JRegistry($filterState);
			}
			else
			{
				$options = new JRegistry;
				$options->set('value', $filterState);
			}

			$methods = $field->getSearchMethods();
			$method = $options->get('method',
$field->getDefaultSearchMethod());

			if (!in_array($method, $methods))
			{
				$method = 'exact';
			}

			switch ($method)
			{
				case 'between':
				case 'outside':
				case 'range' :
					$sql = $field->$method($options->get('from', null),
$options->get('to'));
					break;

				case 'interval':
				case 'modulo':
					$sql = $field->$method($options->get('value', null),
$options->get('interval'));
					break;

				case 'exact':
				case 'partial':
				case 'search':
				default:
					$sql = $field->$method($options->get('value', null));
					break;
			}

			if ($sql)
			{
				$query->where($sql);
			}
		}
	}
}
behavior/language.php000064400000010776151160015660010653 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 * @note        This file has been modified by the Joomla! Project and no
longer reflects the original work of its author.
 */

// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class to filter front-end access to
items
 * based on the language.
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelBehaviorLanguage extends FOFModelBehavior
{
	/**
	 * This event runs before we have built the query used to fetch a record
	 * list in a model. It is used to blacklist the language filter
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The model which calls this
event
	 *
	 * @return  void
	 */
	public function onBeforeBuildQuery(&$model, &$query)
	{
		if (FOFPlatform::getInstance()->isFrontend())
		{
			$model->blacklistFilters('language');
		}
	}

	/**
	 * This event runs after we have built the query used to fetch a record
	 * list in a model. It is used to apply automatic query filters.
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The model which calls this
event
	 *
	 * @return  void
	 */
	public function onAfterBuildQuery(&$model, &$query)
	{
		// This behavior only applies to the front-end.
		if (!FOFPlatform::getInstance()->isFrontend())
		{
			return;
		}

		// Get the name of the language field
		$table = $model->getTable();
		$languageField = $table->getColumnAlias('language');

		// Make sure the access field actually exists
		if (!in_array($languageField, $table->getKnownFields()))
		{
			return;
		}

		// Make sure it is a multilingual site and get a list of languages
		$app = JFactory::getApplication();
		$hasLanguageFilter = method_exists($app, 'getLanguageFilter');

		if ($hasLanguageFilter)
		{
			$hasLanguageFilter = $app->getLanguageFilter();
		}

		if (!$hasLanguageFilter)
		{
			return;
		}

		$lang_filter_plugin = JPluginHelper::getPlugin('system',
'languagefilter');
		$lang_filter_params = new JRegistry($lang_filter_plugin->params);

		$languages = array('*');

		if ($lang_filter_params->get('remove_default_prefix'))
		{
			// Get default site language
			$lg = FOFPlatform::getInstance()->getLanguage();
			$languages[] = $lg->getTag();
		}
		else
		{
			$languages[] =
JFactory::getApplication()->input->getCmd('language',
'*');
		}

		// Filter out double languages
		$languages = array_unique($languages);

		// And filter the query output by these languages
		$db = FOFPlatform::getInstance()->getDbo();

		// Alias
		$alias = $model->getTableAlias();
		$alias = $alias ? $db->qn($alias) . '.' : '';

		$languages = array_map(array($db, 'quote'), $languages);
		$query->where($alias . $db->qn($languageField) . ' IN ('
. implode(',', $languages) . ')');
	}

	/**
	 * The event runs after FOFModel has called FOFTable and retrieved a
single
	 * item from the database. It is used to apply automatic filters.
	 *
	 * @param   FOFModel  &$model   The model which was called
	 * @param   FOFTable  &$record  The record loaded from the database
	 *
	 * @return  void
	 */
	public function onAfterGetItem(&$model, &$record)
	{
		if ($record instanceof FOFTable)
		{
			$fieldName = $record->getColumnAlias('language');

			// Make sure the field actually exists
			if (!in_array($fieldName, $record->getKnownFields()))
			{
				return;
			}

			// Make sure it is a multilingual site and get a list of languages
			$app = JFactory::getApplication();
			$hasLanguageFilter = method_exists($app, 'getLanguageFilter');

			if ($hasLanguageFilter)
			{
				$hasLanguageFilter = $app->getLanguageFilter();
			}

			if (!$hasLanguageFilter)
			{
				return;
			}

			$lang_filter_plugin = JPluginHelper::getPlugin('system',
'languagefilter');
			$lang_filter_params = new JRegistry($lang_filter_plugin->params);

			$languages = array('*');

			if ($lang_filter_params->get('remove_default_prefix'))
			{
				// Get default site language
				$lg = FOFPlatform::getInstance()->getLanguage();
				$languages[] = $lg->getTag();
			}
			else
			{
				$languages[] =
JFactory::getApplication()->input->getCmd('language',
'*');
			}

			// Filter out double languages
			$languages = array_unique($languages);

			if (!in_array($record->$fieldName, $languages))
			{
				$record = null;
			}
		}
	}
}
behavior/private.php000064400000005055151160015660010534 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 * @note        This file has been modified by the Joomla! Project and no
longer reflects the original work of its author.
 */

// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class to filter front-end access to
items
 * created by the currently logged in user only.
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelBehaviorPrivate extends FOFModelBehavior
{
	/**
	 * This event runs after we have built the query used to fetch a record
	 * list in a model. It is used to apply automatic query filters.
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The model which calls this
event
	 *
	 * @return  void
	 */
	public function onAfterBuildQuery(&$model, &$query)
	{
		// This behavior only applies to the front-end.
		if (!FOFPlatform::getInstance()->isFrontend())
		{
			return;
		}

		// Get the name of the access field
		$table = $model->getTable();
		$createdField = $table->getColumnAlias('created_by');

		// Make sure the access field actually exists
		if (!in_array($createdField, $table->getKnownFields()))
		{
			return;
		}

		// Get the current user's id
		$user_id = FOFPlatform::getInstance()->getUser()->id;

		// And filter the query output by the user id
		$db    = FOFPlatform::getInstance()->getDbo();

		$alias = $model->getTableAlias();
		$alias = $alias ? $db->qn($alias) . '.' : '';

		$query->where($alias . $db->qn($createdField) . ' = ' .
$db->q($user_id));
	}

	/**
	 * The event runs after FOFModel has called FOFTable and retrieved a
single
	 * item from the database. It is used to apply automatic filters.
	 *
	 * @param   FOFModel  &$model   The model which was called
	 * @param   FOFTable  &$record  The record loaded from the database
	 *
	 * @return  void
	 */
	public function onAfterGetItem(&$model, &$record)
	{
		if ($record instanceof FOFTable)
		{
			$keyName = $record->getKeyName();
			if ($record->$keyName === null)
			{
				return;
			}

			$fieldName = $record->getColumnAlias('created_by');

			// Make sure the field actually exists
			if (!in_array($fieldName, $record->getKnownFields()))
			{
				return;
			}

			$user_id = FOFPlatform::getInstance()->getUser()->id;

			if ($record->$fieldName != $user_id)
			{
				$record = null;
			}
		}
	}
}
behavior.php000064400000010503151160015660007054 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class. It defines the events which
are
 * called by a Model.
 *
 * @codeCoverageIgnore
 * @package  FrameworkOnFramework
 * @since    2.1
 */
abstract class FOFModelBehavior extends FOFUtilsObservableEvent
{
	/**
	 * This event runs before saving data in the model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 * @param   array     &$data   The data to save
	 *
	 * @return  void
	 */
	public function onBeforeSave(&$model, &$data)
	{
	}

	/**
	 * This event runs before deleting a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onBeforeDelete(&$model)
	{
	}

	/**
	 * This event runs before copying a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onBeforeCopy(&$model)
	{
	}

	/**
	 * This event runs before publishing a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onBeforePublish(&$model)
	{
	}

	/**
	 * This event runs before registering a hit on a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onBeforeHit(&$model)
	{
	}

	/**
	 * This event runs before moving a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onBeforeMove(&$model)
	{
	}

	/**
	 * This event runs before changing the records' order in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onBeforeReorder(&$model)
	{
	}

	/**
	 * This event runs when we are building the query used to fetch a record
	 * list in a model
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The query being built
	 *
	 * @return  void
	 */
	public function onBeforeBuildQuery(&$model, &$query)
	{
	}

	/**
	 * This event runs after saving a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterSave(&$model)
	{
	}

	/**
	 * This event runs after deleting a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterDelete(&$model)
	{
	}

	/**
	 * This event runs after copying a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterCopy(&$model)
	{
	}

	/**
	 * This event runs after publishing a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterPublish(&$model)
	{
	}

	/**
	 * This event runs after registering a hit on a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterHit(&$model)
	{
	}

	/**
	 * This event runs after moving a record in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterMove(&$model)
	{
	}

	/**
	 * This event runs after reordering records in a model
	 *
	 * @param   FOFModel  &$model  The model which calls this event
	 *
	 * @return  void
	 */
	public function onAfterReorder(&$model)
	{
	}

	/**
	 * This event runs after we have built the query used to fetch a record
	 * list in a model
	 *
	 * @param   FOFModel        &$model  The model which calls this event
	 * @param   FOFDatabaseQuery  &$query  The query being built
	 *
	 * @return  void
	 */
	public function onAfterBuildQuery(&$model, &$query)
	{
	}

	/**
	 * This event runs after getting a single item
	 *
	 * @param   FOFModel  &$model   The model which calls this event
	 * @param   FOFTable  &$record  The record loaded by this model
	 *
	 * @return  void
	 */
	public function onAfterGetItem(&$model, &$record)
	{
	}
}
dispatcher/behavior.php000064400000001002151160015660011174
0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior dispatcher class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelDispatcherBehavior extends FOFUtilsObservableDispatcher
{
}
field/boolean.php000064400000001312151160015660007755 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelFieldBoolean extends FOFModelFieldNumber
{
	/**
	 * Is it a null or otherwise empty value?
	 *
	 * @param   mixed  $value  The value to test for emptiness
	 *
	 * @return  boolean
	 */
	public function isEmpty($value)
	{
		return is_null($value) || ($value === '');
	}
}
field/date.php000064400000011673151160015660007266 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelFieldDate extends FOFModelFieldText
{
	/**
	 * Returns the default search method for this field.
	 *
	 * @return  string
	 */
	public function getDefaultSearchMethod()
	{
		return 'exact';
	}

	/**
	 * Perform a between limits match. When $include is true
	 * the condition tested is:
	 * $from <= VALUE <= $to
	 * When $include is false the condition tested is:
	 * $from < VALUE < $to
	 *
	 * @param   mixed    $from     The lowest value to compare to
	 * @param   mixed    $to       The higherst value to compare to
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function between($from, $to, $include = true)
	{
		if ($this->isEmpty($from) || $this->isEmpty($to))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '((' . $this->getFieldName() . ' >' .
$extra . ' "' . $from . '") AND ';
		$sql .= '(' . $this->getFieldName() . ' <' .
$extra . ' "' . $to . '"))';

		return $sql;
	}

	/**
	 * Perform an outside limits match. When $include is true
	 * the condition tested is:
	 * (VALUE <= $from) || (VALUE >= $to)
	 * When $include is false the condition tested is:
	 * (VALUE < $from) || (VALUE > $to)
	 *
	 * @param   mixed    $from     The lowest value of the excluded range
	 * @param   mixed    $to       The higherst value of the excluded range
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function outside($from, $to, $include = false)
	{
		if ($this->isEmpty($from) || $this->isEmpty($to))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '((' . $this->getFieldName() . ' <' .
$extra . ' "' . $from . '") OR ';
		$sql .= '(' . $this->getFieldName() . ' >' .
$extra . ' "' . $to . '"))';

		return $sql;
	}

	/**
	 * Interval date search
	 *
	 * @param   string               $value     The value to search
	 * @param   string|array|object  $interval  The interval. Can be (+1 MONTH
or array('value' => 1, 'unit' =>
'MONTH', 'sign' => '+'))
	 * @param   boolean              $include   If the borders should be
included
	 *
	 * @return  string  the sql string
	 */
	public function interval($value, $interval, $include = true)
	{
		if ($this->isEmpty($value) || $this->isEmpty($interval))
		{
			return '';
		}

		$interval = $this->getInterval($interval);

		if ($interval['sign'] == '+')
		{
			$function = 'DATE_ADD';
		}
		else
		{
			$function = 'DATE_SUB';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '(' . $this->getFieldName() . ' >' .
$extra . ' ' . $function;
		$sql .= '(' . $this->getFieldName() . ', INTERVAL
' . $interval['value'] . ' ' .
$interval['unit'] . '))';

		return $sql;
	}

	/**
	 * Perform a between limits match. When $include is true
	 * the condition tested is:
	 * $from <= VALUE <= $to
	 * When $include is false the condition tested is:
	 * $from < VALUE < $to
	 *
	 * @param   mixed    $from     The lowest value to compare to
	 * @param   mixed    $to       The higherst value to compare to
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function range($from, $to, $include = true)
	{
		if ($this->isEmpty($from) && $this->isEmpty($to))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		if ($from)
			$sql[] = '(' . $this->getFieldName() . ' >' .
$extra . ' "' . $from . '")';
		if ($to)
			$sql[] = '(' . $this->getFieldName() . ' <' .
$extra . ' "' . $to . '")';

		$sql = '(' . implode(' AND ', $sql) . ')';

		return $sql;
	}

	/**
	 * Parses an interval –which may be given as a string, array or
object– into
	 * a standardised hash array that can then be used bu the interval()
method.
	 *
	 * @param   string|array|object  $interval  The interval expression to
parse
	 *
	 * @return  array  The parsed, hash array form of the interval
	 */
	protected function getInterval($interval)
	{
		if (is_string($interval))
		{
			if (strlen($interval) > 2)
			{
				$interval = explode(" ", $interval);
				$sign = ($interval[0] == '-') ? '-' :
'+';
				$value = (int) substr($interval[0], 1);

				$interval = array(
					'unit' => $interval[1],
					'value' => $value,
					'sign' => $sign
				);
			}
			else
			{
				$interval = array(
					'unit' => 'MONTH',
					'value' => 1,
					'sign' => '+'
				);
			}
		}
		else
		{
			$interval = (array) $interval;
		}

		return $interval;
	}
}
field/number.php000064400000012011151160015660007624 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelFieldNumber extends FOFModelField
{
	/**
	 * The partial match is mapped to an exact match
	 *
	 * @param   mixed  $value  The value to compare to
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function partial($value)
	{
		return $this->exact($value);
	}

	/**
	 * Perform a between limits match. When $include is true
	 * the condition tested is:
	 * $from <= VALUE <= $to
	 * When $include is false the condition tested is:
	 * $from < VALUE < $to
	 *
	 * @param   mixed    $from     The lowest value to compare to
	 * @param   mixed    $to       The higherst value to compare to
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function between($from, $to, $include = true)
	{
		if ($this->isEmpty($from) || $this->isEmpty($to))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '((' . $this->getFieldName() . ' >' .
$extra . ' ' . $from . ') AND ';
		$sql .= '(' . $this->getFieldName() . ' <' .
$extra . ' ' . $to . '))';

		return $sql;
	}

	/**
	 * Perform an outside limits match. When $include is true
	 * the condition tested is:
	 * (VALUE <= $from) || (VALUE >= $to)
	 * When $include is false the condition tested is:
	 * (VALUE < $from) || (VALUE > $to)
	 *
	 * @param   mixed    $from     The lowest value of the excluded range
	 * @param   mixed    $to       The higherst value of the excluded range
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function outside($from, $to, $include = false)
	{
		if ($this->isEmpty($from) || $this->isEmpty($to))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '((' . $this->getFieldName() . ' <' .
$extra . ' ' . $from . ') OR ';
		$sql .= '(' . $this->getFieldName() . ' >' .
$extra . ' ' . $to . '))';

		return $sql;
	}

	/**
	 * Perform an interval match. It's similar to a 'between'
match, but the
	 * from and to values are calculated based on $value and $interval:
	 * $value - $interval < VALUE < $value + $interval
	 *
	 * @param   integer|float  $value     The center value of the search space
	 * @param   integer|float  $interval  The width of the search space
	 * @param   boolean        $include   Should I include the boundaries in
the search?
	 *
	 * @return  string  The SQL where clause
	 */
	public function interval($value, $interval, $include = true)
	{
		if ($this->isEmpty($value))
		{
			return '';
		}

		$from = $value - $interval;
		$to = $value + $interval;

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '((' . $this->getFieldName() . ' >' .
$extra . ' ' . $from . ') AND ';
		$sql .= '(' . $this->getFieldName() . ' <' .
$extra . ' ' . $to . '))';

		return $sql;
	}

	/**
	 * Perform a range limits match. When $include is true
	 * the condition tested is:
	 * $from <= VALUE <= $to
	 * When $include is false the condition tested is:
	 * $from < VALUE < $to
	 *
	 * @param   mixed    $from     The lowest value to compare to
	 * @param   mixed    $to       The higherst value to compare to
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function range($from, $to, $include = true)
	{
		if ($this->isEmpty($from) && $this->isEmpty($to))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		if ($from)
			$sql[] = '(' . $this->getFieldName() . ' >' .
$extra . ' ' . $from . ')';
		if ($to)
			$sql[] = '(' . $this->getFieldName() . ' <' .
$extra . ' ' . $to . ')';

		$sql = '(' . implode(' AND ', $sql) . ')';

		return $sql;
	}

	/**
	 * Perform an interval match. It's similar to a 'between'
match, but the
	 * from and to values are calculated based on $value and $interval:
	 * $value - $interval < VALUE < $value + $interval
	 *
	 * @param   integer|float  $value     The starting value of the search
space
	 * @param   integer|float  $interval  The interval period of the search
space
	 * @param   boolean        $include   Should I include the boundaries in
the search?
	 *
	 * @return  string  The SQL where clause
	 */
	public function modulo($value, $interval, $include = true)
	{
		if ($this->isEmpty($value) || $this->isEmpty($interval))
		{
			return '';
		}

		$extra = '';

		if ($include)
		{
			$extra = '=';
		}

		$sql = '(' . $this->getFieldName() . ' >' .
$extra . ' ' . $value . ' AND ';
		$sql .= '(' . $this->getFieldName() . ' - ' .
$value . ') % ' . $interval . ' = 0)';

		return $sql;
	}
}
field/text.php000064400000006210151160015660007324 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
class FOFModelFieldText extends FOFModelField
{
	/**
	 * Constructor
	 *
	 * @param   FOFDatabaseDriver  $db     The database object
	 * @param   object           $field  The field informations as taken from
the db
	 */
	public function __construct($db, $field, $table_alias = false)
	{
		parent::__construct($db, $field, $table_alias);

		$this->null_value = '';
	}

	/**
	 * Returns the default search method for this field.
	 *
	 * @return  string
	 */
	public function getDefaultSearchMethod()
	{
		return 'partial';
	}

	/**
	 * Perform a partial match (search in string)
	 *
	 * @param   mixed  $value  The value to compare to
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function partial($value)
	{
		if ($this->isEmpty($value))
		{
			return '';
		}

		return '(' . $this->getFieldName() . ' LIKE ' .
$this->_db->quote('%' . $value . '%') .
')';
	}

	/**
	 * Perform an exact match (match string)
	 *
	 * @param   mixed  $value  The value to compare to
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function exact($value)
	{
		if ($this->isEmpty($value))
		{
			return '';
		}

		return '(' . $this->getFieldName() . ' LIKE ' .
$this->_db->quote($value) . ')';
	}

	/**
	 * Dummy method; this search makes no sense for text fields
	 *
	 * @param   mixed    $from     Ignored
	 * @param   mixed    $to       Ignored
	 * @param   boolean  $include  Ignored
	 *
	 * @return  string  Empty string
	 */
	public function between($from, $to, $include = true)
	{
		return '';
	}

	/**
	 * Dummy method; this search makes no sense for text fields
	 *
	 * @param   mixed    $from     Ignored
	 * @param   mixed    $to       Ignored
	 * @param   boolean  $include  Ignored
	 *
	 * @return  string  Empty string
	 */
	public function outside($from, $to, $include = false)
	{
		return '';
	}

	/**
	 * Dummy method; this search makes no sense for text fields
	 *
	 * @param   mixed    $value     Ignored
	 * @param   mixed    $interval  Ignored
	 * @param   boolean  $include   Ignored
	 *
	 * @return  string  Empty string
	 */
	public function interval($value, $interval, $include = true)
	{
		return '';
	}

	/**
	 * Dummy method; this search makes no sense for text fields
	 *
	 * @param   mixed    $from     Ignored
	 * @param   mixed    $to       Ignored
	 * @param   boolean  $include  Ignored
	 *
	 * @return  string  Empty string
	 */
	public function range($from, $to, $include = false)
	{
		return '';
	}

	/**
	 * Dummy method; this search makes no sense for text fields
	 *
	 * @param   mixed    $from     Ignored
	 * @param   mixed    $to       Ignored
	 * @param   boolean  $include  Ignored
	 *
	 * @return  string  Empty string
	 */
	public function modulo($from, $to, $include = false)
	{
		return '';
	}
}
field.php000064400000020264151160015660006345 0ustar00<?php
/**
 * @package     FrameworkOnFramework
 * @subpackage  model
 * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba
Ltd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

// Protect from unauthorized access
defined('FOF_INCLUDED') or die;

/**
 * FrameworkOnFramework model behavior class
 *
 * @package  FrameworkOnFramework
 * @since    2.1
 */
abstract class FOFModelField
{
	protected $_db = null;

	/**
	 * The column name of the table field
	 *
	 * @var string
	 */
	protected $name = '';

	/**
	 * The column type of the table field
	 *
	 * @var string
	 */
	protected $type = '';

	/**
	 * The alias of the table used for filtering
	 *
	 * @var string
	 */
	protected $table_alias = false;

	/**
	 * The null value for this type
	 *
	 * @var  mixed
	 */
	public $null_value = null;

	/**
	 * Constructor
	 *
	 * @param   FOFDatabaseDriver  $db           The database object
	 * @param   object           $field        The field informations as taken
from the db
	 * @param   string           $table_alias  The table alias to use when
filtering
	 */
	public function __construct($db, $field, $table_alias = false)
	{
		$this->_db = $db;

		$this->name = $field->name;
		$this->type = $field->type;
		$this->filterzero = $field->filterzero;
		$this->table_alias = $table_alias;
	}

	/**
	 * Is it a null or otherwise empty value?
	 *
	 * @param   mixed  $value  The value to test for emptiness
	 *
	 * @return  boolean
	 */
	public function isEmpty($value)
	{
		return (($value === $this->null_value) || empty($value))
			&& !($this->filterzero && $value === "0");
	}

	/**
	 * Returns the default search method for a field. This always returns
'exact'
	 * and you are supposed to override it in specialised classes. The
possible
	 * values are exact, partial, between and outside, unless something
	 * different is returned by getSearchMethods().
	 *
	 * @see  self::getSearchMethods()
	 *
	 * @return  string
	 */
	public function getDefaultSearchMethod()
	{
		return 'exact';
	}

	/**
	 * Return the search methods available for this field class,
	 *
	 * @return  array
	 */
	public function getSearchMethods()
	{
		$ignore = array('isEmpty', 'getField',
'getFieldType', '__construct',
'getDefaultSearchMethod', 'getSearchMethods');

		$class = new ReflectionClass(__CLASS__);
		$methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);

		$tmp = array();

		foreach ($methods as $method)
		{
			$tmp[] = $method->name;
		}

		$methods = $tmp;

		if ($methods = array_diff($methods, $ignore))
		{
			return $methods;
		}

		return array();
	}

	/**
	 * Perform an exact match (equality matching)
	 *
	 * @param   mixed  $value  The value to compare to
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function exact($value)
	{
		if ($this->isEmpty($value))
		{
			return '';
		}

		if (is_array($value))
		{
			$db    = FOFPlatform::getInstance()->getDbo();
			$value = array_map(array($db, 'quote'), $value);

			return '(' . $this->getFieldName() . ' IN (' .
implode(',', $value) . '))';
		}
		else
		{
			return $this->search($value, '=');
		}
	}

	/**
	 * Perform a partial match (usually: search in string)
	 *
	 * @param   mixed  $value  The value to compare to
	 *
	 * @return  string  The SQL where clause for this search
	 */
	abstract public function partial($value);

	/**
	 * Perform a between limits match (usually: search for a value between
	 * two numbers or a date between two preset dates). When $include is true
	 * the condition tested is:
	 * $from <= VALUE <= $to
	 * When $include is false the condition tested is:
	 * $from < VALUE < $to
	 *
	 * @param   mixed    $from     The lowest value to compare to
	 * @param   mixed    $to       The higherst value to compare to
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	abstract public function between($from, $to, $include = true);

	/**
	 * Perform an outside limits match (usually: search for a value outside an
	 * area or a date outside a preset period). When $include is true
	 * the condition tested is:
	 * (VALUE <= $from) || (VALUE >= $to)
	 * When $include is false the condition tested is:
	 * (VALUE < $from) || (VALUE > $to)
	 *
	 * @param   mixed    $from     The lowest value of the excluded range
	 * @param   mixed    $to       The higherst value of the excluded range
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	abstract public function outside($from, $to, $include = false);

	/**
	 * Perform an interval search (usually: a date interval check)
	 *
	 * @param   string               $from      The value to search
	 * @param   string|array|object  $interval  The interval
	 *
	 * @return  string  The SQL where clause for this search
	 */
	abstract public function interval($from, $interval);

	/**
	 * Perform a between limits match (usually: search for a value between
	 * two numbers or a date between two preset dates). When $include is true
	 * the condition tested is:
	 * $from <= VALUE <= $to
	 * When $include is false the condition tested is:
	 * $from < VALUE < $to
	 *
	 * @param   mixed    $from     The lowest value to compare to
	 * @param   mixed    $to       The higherst value to compare to
	 * @param   boolean  $include  Should we include the boundaries in the
search?
	 *
	 * @return  string  The SQL where clause for this search
	 */
	abstract public function range($from, $to, $include = true);

	/**
	 * Perform an modulo search
	 *
	 * @param   integer|float  $value     The starting value of the search
space
	 * @param   integer|float  $interval  The interval period of the search
space
	 * @param   boolean        $include   Should I include the boundaries in
the search?
	 *
	 * @return  string  The SQL where clause
	 */
	abstract public function modulo($from, $interval, $include = true);

	/**
	 * Return the SQL where clause for a search
	 *
	 * @param   mixed   $value     The value to search for
	 * @param   string  $operator  The operator to use
	 *
	 * @return  string  The SQL where clause for this search
	 */
	public function search($value, $operator = '=')
	{
		if ($this->isEmpty($value))
		{
			return '';
		}

		return '(' . $this->getFieldName() . ' ' .
$operator . ' ' . $this->_db->quote($value) .
')';
	}

	/**
	 * Get the field name with the given table alias
	 *
	 * @return  string 	The field name
	 */
	public function getFieldName()
	{
		$name = $this->_db->qn($this->name);

		if ($this->table_alias)
		{
			$name = $this->_db->qn($this->table_alias) . '.' .
$name;
		}

		return $name;
	}

	/**
	 * Creates a field Object based on the field column type
	 *
	 * @param   object  $field   The field informations
	 * @param   array   $config  The field configuration (like the db object
to use)
	 *
	 * @return  FOFModelField  The Field object
	 */
	public static function getField($field, $config = array())
	{
		$type = $field->type;

		$classType = self::getFieldType($type);

		$className = 'FOFModelField' . $classType;

		if (class_exists($className))
		{
			if (isset($config['dbo']))
			{
				$db = $config['dbo'];
			}
			else
			{
				$db = FOFPlatform::getInstance()->getDbo();
			}

			if (isset($config['table_alias']))
			{
				$table_alias = $config['table_alias'];
			}
			else
			{
				$table_alias = false;
			}

			$field = new $className($db, $field, $table_alias);

			return $field;
		}

		return false;
	}

	/**
	 * Get the classname based on the field Type
	 *
	 * @param   string  $type  The type of the field
	 *
	 * @return  string  the class suffix
	 */
	public static function getFieldType($type)
	{
		switch ($type)
		{
			case 'varchar':
			case 'text':
			case 'smalltext':
			case 'longtext':
			case 'char':
			case 'mediumtext':
			case 'character varying':
			case 'nvarchar':
			case 'nchar':
				$type = 'Text';
				break;

			case 'date':
			case 'datetime':
			case 'time':
			case 'year':
			case 'timestamp':
			case 'timestamp without time zone':
			case 'timestamp with time zone':
				$type = 'Date';
				break;

			case 'tinyint':
			case 'smallint':
				$type = 'Boolean';
				break;

			default:
				$type = 'Number';
				break;
		}

		return $type;
	}
}