Your IP : 216.73.216.43


Current Path : /home/cbequiperp/www/administrator/components/com_flexicontent/models/
Upload File :
Current File : /home/cbequiperp/www/administrator/components/com_flexicontent/models/field.php

<?php
/**
 * @package         FLEXIcontent
 * @version         3.3
 *
 * @author          Emmanuel Danan, Georgios Papadakis, Yannick Berges, others, see contributor page
 * @link            https://flexicontent.org
 * @copyright       Copyright © 2018, FLEXIcontent team, All Rights Reserved
 * @license         http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 */

defined('_JEXEC') or die('Restricted access');

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

require_once('base/base.php');

/**
 * FLEXIcontent Component Field Model
 *
 */
class FlexicontentModelField extends FCModelAdmin
{
	/**
	 * Record name, (parent class property), this is used for: naming session data, XML file of class, etc
	 *
	 * @var string
	 */
	protected $name = 'field';

	/**
	 * Record database table
	 *
	 * @var string
	 */
	var $records_dbtbl = 'flexicontent_fields';

	/**
	 * Record jtable name
	 *
	 * @var string
	 */
	var $records_jtable = 'flexicontent_fields';

	/**
	 * Column names
	 */
	var $state_col   = 'published';
	var $name_col    = 'label';
	var $parent_col  = null;//'parent_id';

	/**
	 * Record primary key
	 *
	 * @var int
	 */
	var $_id = null;

	/**
	 * Record data
	 *
	 * @var object
	 */
	var $_record = null;

	/**
	 * Events context to use during model FORM events and diplay PREPARE events triggering
	 *
	 * @var object
	 */
	var $events_context = null;

	/**
	 * Flag to indicate adding new records with next available ordering (at the end),
	 * this is ignored if this record DB model does not have 'ordering'
	 *
	 * @var boolean
	 */
	var $useLastOrdering = true;

	/**
	 * Plugin group used to trigger events
	 *
	 * @var boolean
	 */
	var $plugins_group = null;

	/**
	 * Records real extension
	 *
	 * @var string
	 */
	var $extension_proxy = null;

	/**
	 * Use language associations
	 *
	 * @var string
	 */
	var $associations_context = false;

	/**
	 * Various record specific properties
	 *
	 */
	protected $forced_field_type = null;

	/**
	 * Constructor
	 *
	 * @since 1.0
	 */
	public function __construct($config = array())
	{
		parent::__construct($config);

		$jinput = JFactory::getApplication()->input;
		$filter = JFilterInput::getInstance();

		$data = $jinput->post->get('jform', array(), 'array');

		// Force new field_type, so that type-specific parameters will be validated according to the new field type
		if (isset($data['field_type']))
		{
			$this->setFieldType($data['field_type']);
		}

		$this->canManage    = FlexicontentHelperPerm::getPerm()->CanFields;
		$this->canCreate    = FlexicontentHelperPerm::getPerm()->CanAddField;
	}


	/**
	 * Legacy method to get the record
	 *
	 * @return	object
	 *
	 * @since	1.0
	 */
	public function getField($pk = null)
	{
		return parent::getRecord($pk);
	}


	/**
	 * Method to initialise the record data
	 *
	 * @param   object      $record    The record being initialized
	 * @param   boolean     $initOnly  If true then only a new record will be initialized without running the _afterLoad() method
	 *
	 * @return	boolean	True on success
	 *
	 * @since	1.5
	 */
	protected function _initRecord(&$record = null, $initOnly = false)
	{
		parent::_initRecord($record, $initOnly);

		// Set some new record specific properties, note most properties already have proper values
		// Either the DB default values (set by getTable() method) or the values set by _afterLoad() method
		$record->id							= 0;
		$record->field_type			= 'text';
		$record->name						= null;  //$this->getName() . ($this->_getLastId() + 1);
		$record->label					= null;
		$record->description		= null;
		$record->isfilter				= 0;
		$record->isadvfilter   	= 0;
		$record->iscore					= 0;
		$record->issearch				= 1;
		$record->isadvsearch		= 0;
		$record->untranslatable	= 0;
		$record->formhidden			= 0;
		$record->valueseditable	= 0;
		$record->edithelp				= 2;
		$record->positions			= array();
		$record->published			= 1;
		$record->attribs				= null;
		$record->access					= 1;
		$record->checked_out		= 0;
		$record->checked_out_time	= '';

		$this->_record = $record;

		return true;
	}


	/**
	 * Method to set a new field type. The type will be validated if it exists during JForm preprocessing
	 *
	 * @param   string  $field_type  The forced field type
	 *
	 * @since   3.3.0
	 */
	public function setFieldType($field_type)
	{
		$this->forced_field_type = JFilterInput::getInstance()->clean($field_type, 'CMD');
	}


	/**
	 * Method to preprocess the form.
	 *
	 * @param   JForm   $form   A JForm object.
	 * @param   mixed   $data   The data expected for the form.
	 * @param   string  $plugins_group  The name of the plugin group to import and trigger
	 *
	 * @return  void
	 *
	 * @see     JFormField
	 * @since   1.6
	 * @throws  Exception if there is an error in the form event.
	 */
	protected function preprocessForm(JForm $form, $data, $plugins_group = null)
	{
		$data_obj = $data && is_array($data) ? (object) $data : $data;

		jimport('joomla.filesystem.file');
		jimport('joomla.filesystem.folder');

		// Initialise variables.
		$client = JApplicationHelper::getClientInfo(0);


		/**
		 * Get plugin name from field type
		 * Use overridden field type if this was set, e.g. switching current to a new field type
		 */
		$plugin_name = $data_obj
			? (!empty($data_obj->iscore) ? 'core' : $data_obj->field_type)
			: 'text';
		$plugin_name = $this->forced_field_type ?: $plugin_name;


		/**
		 * Try to load plugin file: /plugins/folder/element/element.xml
		 */
		$plugin_path = JPath::clean(JPATH_PLUGINS . DS . 'flexicontent_fields' . DS . $plugin_name . DS . $plugin_name . '.xml');

		if (!JFile::exists($plugin_path))
		{
			throw new Exception('Error field XML file for field type: - ' . $plugin_name . '- was not found');
		}


		/**
		 * Set new field_type, this is needed e.g. after for form reload due to some error
		 */

		if (empty($this->_record->iscore))
		{
			$this->_record->field_type = $plugin_name;
		}

		if ($data_obj && empty($data_obj->iscore))
		{
			$data_obj->field_type = $plugin_name;
		}


		/**
		 * Do not allow changing some properties
		 */

		if (!empty($this->_record->iscore))
		{
			$form->setFieldAttribute('name', 'readonly', 'true');
			$form->setFieldAttribute('name', 'filter', 'unset');
		}

		$form->setFieldAttribute('iscore', 'readonly', 'true');
		$form->setFieldAttribute('iscore', 'filter', 'unset');

		if ($this->_record->id > 0 && $this->_record->id < 7)
		{
			$form->setFieldAttribute('published', 'readonly', 'true');
			$form->setFieldAttribute('published', 'filter', 'unset');
		}


		// ***
		// *** Load extra XML files into the JForm, these will be used e.g. during validation
		// ***

		// We will load the form's XML file into a string to be able to manipulate it, before it is loaded by the JForm
		$xml_string = str_replace(' type="radio"', ' type="fcradio"', file_get_contents($plugin_path));
		$xml = simplexml_load_string($xml_string);  //simplexml_load_file($plugin_path);
		if (!$xml)
		{
			throw new Exception(JText::_('JERROR_LOADFILE_FAILED'));
		}

		// Load XML file into the form
		$form->load($xml, false, '//config');


		// ***
		// *** Get the help data from the XML file if present.
		// ***

		$docs = $xml->xpath('/extension/documentation');
		if (!empty($docs))
		{
			$this->helpTitle = trim((string) $docs[0]['title']);
			$this->helpURL   = trim((string) $docs[0]['url']);
			$this->helpModal = (int) $docs[0]['modal'];
		}

		// Trigger the default form events.
		$plugins_group = $plugins_group ?: $this->plugins_group;
		parent::preprocessForm($form, $data, $plugins_group);
	}


	/**
	 * Method to change the title & alias.
	 *
	 * @param   integer  $parent_id  If applicable, the id of the parent (e.g. assigned category)
	 * @param   string   $alias      The alias / name.
	 * @param   string   $title      The title / label.
	 *
	 * @return  array    Contains the modified title and alias / name.
	 *
	 * @since   1.7
	 */
	protected function generateNewTitle($parent_id, $alias, $title)
	{
		// Alter the title & alias
		$table = $this->getTable();

		while ($table->load(array('name' => $alias, 'label' => $title)))
		{
			$title = StringHelper::increment($title);
			$alias = StringHelper::increment($alias, 'dash');
		}

		return array($title, $alias);
	}


	/**
	 * Method to check if the user can edit the record
	 *
	 * @return	boolean	True on success
	 *
	 * @since	3.2.0
	 */
	public function canEdit($record = null, $user = null)
	{
		if ($user)
		{
			throw new Exception(__FUNCTION__ . '(): Error model does not support checking ACL of specific user', 500);
		}

		$record  = $record ?: $this->_record;
		$user    = $user ?: JFactory::getUser();

		return !$record || !$record->id
			? $this->canCreate
			: $user->authorise('flexicontent.editfield', 'com_flexicontent.field.' . $record->id);
	}


	/**
	 * Method to check if the user can edit record 's state
	 *
	 * @return	boolean	True on success
	 *
	 * @since	3.2.0
	 */
	public function canEditState($record = null, $user = null)
	{
		if ($user)
		{
			throw new Exception(__FUNCTION__ . '(): Error model does not support checking ACL of specific user', 500);
		}

		$record  = $record ?: $this->_record;
		$user    = $user ?: JFactory::getUser();

		return $record->id < 7
			?	false
			: $user->authorise('flexicontent.publishfield', 'com_flexicontent.field.' . $record->id);
	}


	/**
	 * Method to check if the user can delete the record
	 *
	 * @return	boolean	True on success
	 *
	 * @since	3.2.0
	 */
	public function canDelete($record = null)
	{
		$record  = $record ?: $this->_record;
		$user    = JFactory::getUser();

		return $record->id < 7
			?	false
			: $user->authorise('flexicontent.deletefield', 'com_flexicontent.field.' . $record->id);
	}


	/**
	 * Method to do some record / data preprocessing before call JTable::bind()
	 *
	 * Note. Typically called inside this MODEL 's store()
	 *
	 * @param   object     $record   The record object
	 * @param   array      $data     The new data array
	 *
	 * @since	3.2.0
	 */
	protected function _prepareBind($record, & $data)
	{
		/**
		 * Support for 'dirty' field properties
		 */
		if ($data['id'])
		{
			if ($record->issearch==-1 || $record->issearch==2) unset($data['issearch']);  // Already dirty
			elseif (@ $data['issearch']==0 && $record->issearch==1) $data['issearch'] = -1; // Becomes dirty OFF
			elseif (@ $data['issearch']==1 && $record->issearch==0) $data['issearch'] = 2;  // Becomes dirty ON

			if ($record->isadvsearch==-1 || $record->isadvsearch==2) unset($data['isadvsearch']);  // Already dirty
			elseif (@ $data['isadvsearch']==0 && $record->isadvsearch==1) $data['isadvsearch'] = -1; // Becomes dirty OFF
			elseif (@ $data['isadvsearch']==1 && $record->isadvsearch==0) $data['isadvsearch'] = 2;  // Becomes dirty ON

			if ($record->isadvfilter==-1 || $record->isadvfilter==2) unset($data['isadvfilter']);  // Already dirty
			elseif (@ $data['isadvfilter']==0 && $record->isadvfilter==1) $data['isadvfilter'] = -1; // Becomes dirty OFF
			elseif (@ $data['isadvfilter']==1 && $record->isadvfilter==0) $data['isadvfilter'] = 2;  // Becomes dirty ON

			// FORCE dirty OFF, if field is being unpublished -and- is not already normal OFF
			if (isset($data['published']) && $data['published']==0 && $record->published==1)
			{
				if ($record->issearch!=0) $data['issearch'] = -1;
				if ($record->isadvsearch!=0) $data['isadvsearch'] = -1;
				if ($record->isadvfilter!=0) $data['isadvfilter'] = -1;
			}
		}

		/**
		 * Positions are always posted, otherwise they must be cleared
		 */
		if (!isset($data['positions']))
		{
			$data['positions'] = '';
		}

		// Call parent class bind preparation
		parent::_prepareBind($record, $data);
	}


	/**
	 * Method to do some work after record has been stored
	 *
	 * Note. Typically called inside this MODEL 's store()
	 *
	 * @param   object     $record   The record object
	 * @param   array      $data     The new data array
	 *
	 * @since	3.2.0
	 */
	protected function _afterStore($record, & $data)
	{
		parent::_afterStore($record, $data);

		// Assign (a) chosen types to custom field or (b) all types if field is core
		$types = ! empty($data['tid'])
			? $data['tid']
			: array();

		$this->_assignTypesToField($types);
	}


	/**
	 * Method to do some work after record has been loaded via JTable::load()
	 *
	 * Note. Typically called inside this MODEL 's store()
	 *
	 * @param	object   $record   The record object
	 *
	 * @since	3.2.0
	 */
	protected function _afterLoad($record)
	{
		parent::_afterLoad($record);

		// Record was not found / not created, nothing to do
		if (!$record)
		{
			return;
		}

		// Convert field positions to an array
		if (!is_array($record->positions))
		{
			$record->positions = explode("\n", $record->positions);
		}

		// Load type assigments (an array of type IDs)
		$record->tid = $this->getFieldType($record->id);
	}


	/**
	 * START OF MODEL SPECIFIC METHODS
	 */


	/**
	 * Method to assign types to a field
	 *
	 * @return  boolean    True on success
	 *
	 * @since	1.0
	 */
	protected function _assignTypesToField($types)
	{
		$field = $this->_record;

		/**
		 * Override 'types' for core fields, since the core field must be assigned to all types
		 * but alllow core fields 'voting', 'favourites, to selectively assigned to types
		 */
		if ($field->iscore && !in_array($field->field_type, array('voting', 'favourites'), true))
		{
			$query = $this->_db->getQuery(true)
				->select('id')
				->from('#__flexicontent_types');

			$types = $this->_db->setQuery($query)->loadColumn();
		}

		/**
		 * Store field to types relations
		 * Try to avoid unneeded deletion and insertions
		 */

		// First, delete existing types assignments no longer used by the field
		$query = $this->_db->getQuery(true)
			->delete('#__flexicontent_fields_type_relations')
			->where('field_id = ' . (int) $field->id);

		if (!empty($types))
		{
			$query->where('type_id NOT IN (' . implode(', ', $types) . ')');
		}

		$this->_db->setQuery($query)->execute();

		// Second, find type assignments of the field that did not changed
		$query = $this->_db->getQuery(true)
			->select('type_id')
			->from('#__flexicontent_fields_type_relations')
			->where('field_id = ' . (int) $field->id);

		$used = $this->_db->setQuery($query)->loadColumn();

		// Third, insert only the new records
		foreach ($types as $type)
		{
			if (!in_array($type, $used))
			{
				// Get last position of each field in each type
				$query = $this->_db->getQuery(true)
					->select('MAX(ordering) as ordering')
					->from('#__flexicontent_fields_type_relations')
					->where('type_id = ' . (int) $type);

				$ordering = $this->_db->setQuery($query)->loadResult();

				// Insert new type assignment using the next available ordering
				$ordering += 1;

				$query = $this->_db->getQuery(true)
					->insert('#__flexicontent_fields_type_relations')
					->columns(array(
						$this->_db->quoteName('field_id'),
						$this->_db->quoteName('type_id'),
						$this->_db->quoteName('ordering')
					))
					->values(
						(int) $field->id . ' , ' .
						(int) $type . ' , ' .
						(int) $ordering
					);

				$this->_db->setQuery($query)->execute();
			}
		}
	}


	/**
	 * Method to get types list
	 *
	 * @return array
	 *
	 * @since 1.5
	 */
	public function getTypeslist ( $type_ids=false, $check_perms = false, $published=false )
	{
		return flexicontent_html::getTypesList( $type_ids, $check_perms, $published);
	}


	/**
	 * Method to the Field Type for a given or for current field ID
	 *
	 * @return array
	 *
	 * @since 3.2
	 */
	public function getFieldType($pk = 0)
	{
		$pk = $pk ?: (int) $this->_id;

		if (!$pk)
		{
			return array();
		}

		$query = $this->_db->getQuery(true)
			->select('DISTINCT type_id')
			->from('#__flexicontent_fields_type_relations')
			->where('field_id = ' . (int) $pk);

		return $this->_db->setQuery($query)->loadColumn();
	}
}