cms/administrator/components/com_fields/src/Model/FieldModel.php

1226 lines
30 KiB
PHP

<?php
/**
* @package Joomla.Administrator
* @subpackage com_fields
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Fields\Administrator\Model;
\defined('_JEXEC') or die;
use Joomla\CMS\Categories\CategoryServiceInterface;
use Joomla\CMS\Categories\SectionNotFoundException;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\Path;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Table\Table;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
use Joomla\Utilities\ArrayHelper;
/**
* Field Model
*
* @since 3.7.0
*/
class FieldModel extends AdminModel
{
/**
* @var null|string
*
* @since 3.7.0
*/
public $typeAlias = null;
/**
* @var string
*
* @since 3.7.0
*/
protected $text_prefix = 'COM_FIELDS';
/**
* Batch copy/move command. If set to false,
* the batch copy/move command is not supported
*
* @var string
* @since 3.4
*/
protected $batch_copymove = 'group_id';
/**
* Allowed batch commands
*
* @var array
*/
protected $batch_commands = array(
'assetgroup_id' => 'batchAccess',
'language_id' => 'batchLanguage'
);
/**
* @var array
*
* @since 3.7.0
*/
private $valueCache = array();
/**
* Constructor
*
* @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request).
* @param MVCFactoryInterface $factory The factory.
*
* @since 3.7.0
* @throws \Exception
*/
public function __construct($config = array(), MVCFactoryInterface $factory = null)
{
parent::__construct($config, $factory);
$this->typeAlias = Factory::getApplication()->input->getCmd('context', 'com_content.article') . '.field';
}
/**
* Method to save the form data.
*
* @param array $data The form data.
*
* @return boolean True on success, False on error.
*
* @since 3.7.0
*/
public function save($data)
{
$field = null;
if (isset($data['id']) && $data['id'])
{
$field = $this->getItem($data['id']);
}
if (!isset($data['label']) && isset($data['params']['label']))
{
$data['label'] = $data['params']['label'];
unset($data['params']['label']);
}
// Alter the title for save as copy
$input = Factory::getApplication()->input;
if ($input->get('task') == 'save2copy')
{
$origTable = clone $this->getTable();
$origTable->load($input->getInt('id'));
if ($data['title'] == $origTable->title)
{
list($title, $name) = $this->generateNewTitle($data['group_id'], $data['name'], $data['title']);
$data['title'] = $title;
$data['label'] = $title;
$data['name'] = $name;
}
else
{
if ($data['name'] == $origTable->name)
{
$data['name'] = '';
}
}
$data['state'] = 0;
}
// Load the fields plugins, perhaps they want to do something
PluginHelper::importPlugin('fields');
$message = $this->checkDefaultValue($data);
if ($message !== true)
{
$this->setError($message);
return false;
}
if (!parent::save($data))
{
return false;
}
// Save the assigned categories into #__fields_categories
$db = $this->getDbo();
$id = (int) $this->getState('field.id');
$cats = isset($data['assigned_cat_ids']) ? (array) $data['assigned_cat_ids'] : array();
$cats = ArrayHelper::toInteger($cats);
$assignedCatIds = array();
foreach ($cats as $cat)
{
// If we have found the 'JNONE' category, remove all other from the result and break.
if ($cat == '-1')
{
$assignedCatIds = array('-1');
break;
}
if ($cat)
{
$assignedCatIds[] = $cat;
}
}
// First delete all assigned categories
$query = $db->getQuery(true);
$query->delete('#__fields_categories')
->where($db->quoteName('field_id') . ' = :fieldid')
->bind(':fieldid', $id, ParameterType::INTEGER);
$db->setQuery($query);
$db->execute();
// Inset new assigned categories
$tupel = new \stdClass;
$tupel->field_id = $id;
foreach ($assignedCatIds as $catId)
{
$tupel->category_id = $catId;
$db->insertObject('#__fields_categories', $tupel);
}
/**
* If the options have changed, delete the values. This should only apply for list, checkboxes and radio
* custom field types, because when their options are being changed, their values might get invalid, because
* e.g. there is a value selected from a list, which is not part of the list anymore. Hence we need to delete
* all values that are not part of the options anymore. Note: The only field types with fieldparams+options
* are those above listed plus the subfields type. And we do explicitly not want the values to be deleted
* when the options of a subfields field are getting changed.
*/
if ($field && in_array($field->type, array('list', 'checkboxes', 'radio'), true)
&& isset($data['fieldparams']['options']) && isset($field->fieldparams['options']))
{
$oldParams = $this->getParams($field->fieldparams['options']);
$newParams = $this->getParams($data['fieldparams']['options']);
if (is_object($oldParams) && is_object($newParams) && $oldParams != $newParams)
{
// Get new values.
$names = array_column((array) $newParams, 'value');
$fieldId = (int) $field->id;
$query = $db->getQuery(true);
$query->delete($db->quoteName('#__fields_values'))
->where($db->quoteName('field_id') . ' = :fieldid')
->bind(':fieldid', $fieldId, ParameterType::INTEGER);
// If new values are set, delete only old values. Otherwise delete all values.
if ($names)
{
$query->whereNotIn($db->quoteName('value'), $names, ParameterType::STRING);
}
$db->setQuery($query);
$db->execute();
}
}
FieldsHelper::clearFieldsCache();
return true;
}
/**
* Checks if the default value is valid for the given data. If a string is returned then
* it can be assumed that the default value is invalid.
*
* @param array $data The data.
*
* @return true|string true if valid, a string containing the exception message when not.
*
* @since 3.7.0
*/
private function checkDefaultValue($data)
{
// Empty default values are correct
if (empty($data['default_value']) && $data['default_value'] !== '0')
{
return true;
}
$types = FieldsHelper::getFieldTypes();
// Check if type exists
if (!array_key_exists($data['type'], $types))
{
return true;
}
$path = $types[$data['type']]['rules'];
// Add the path for the rules of the plugin when available
if ($path)
{
// Add the lookup path for the rule
FormHelper::addRulePath($path);
}
// Create the fields object
$obj = (object) $data;
$obj->params = new Registry($obj->params);
$obj->fieldparams = new Registry(!empty($obj->fieldparams) ? $obj->fieldparams : array());
// Prepare the dom
$dom = new \DOMDocument;
$node = $dom->appendChild(new \DOMElement('form'));
// Trigger the event to create the field dom node
Factory::getApplication()->triggerEvent('onCustomFieldsPrepareDom', array($obj, $node, new Form($data['context'])));
// Check if a node is created
if (!$node->firstChild)
{
return true;
}
// Define the type either from the field or from the data
$type = $node->firstChild->getAttribute('validate') ? : $data['type'];
// Load the rule
$rule = FormHelper::loadRuleType($type);
// When no rule exists, we allow the default value
if (!$rule)
{
return true;
}
try
{
// Perform the check
$result = $rule->test(simplexml_import_dom($node->firstChild), $data['default_value']);
// Check if the test succeeded
return $result === true ? : Text::_('COM_FIELDS_FIELD_INVALID_DEFAULT_VALUE');
}
catch (\UnexpectedValueException $e)
{
return $e->getMessage();
}
}
/**
* Converts the unknown params into an object.
*
* @param mixed $params The params.
*
* @return \stdClass Object on success, false on failure.
*
* @since 3.7.0
*/
private function getParams($params)
{
if (is_string($params))
{
$params = json_decode($params);
}
if (is_array($params))
{
$params = (object) $params;
}
return $params;
}
/**
* Method to get a single record.
*
* @param integer $pk The id of the primary key.
*
* @return mixed Object on success, false on failure.
*
* @since 3.7.0
*/
public function getItem($pk = null)
{
$result = parent::getItem($pk);
if ($result)
{
// Prime required properties.
if (empty($result->id))
{
$result->context = Factory::getApplication()->input->getCmd('context', $this->getState('field.context'));
}
if (property_exists($result, 'fieldparams') && $result->fieldparams !== null)
{
$registry = new Registry;
if ($result->fieldparams)
{
$registry->loadString($result->fieldparams);
}
$result->fieldparams = $registry->toArray();
}
$db = $this->getDbo();
$query = $db->getQuery(true);
$fieldId = (int) $result->id;
$query->select($db->quoteName('category_id'))
->from($db->quoteName('#__fields_categories'))
->where($db->quoteName('field_id') . ' = :fieldid')
->bind(':fieldid', $fieldId, ParameterType::INTEGER);
$db->setQuery($query);
$result->assigned_cat_ids = $db->loadColumn() ?: array(0);
}
return $result;
}
/**
* Method to get a table object, load it if necessary.
*
* @param string $name The table name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $options Configuration array for model. Optional.
*
* @return Table A JTable object
*
* @since 3.7.0
* @throws \Exception
*/
public function getTable($name = 'Field', $prefix = 'Administrator', $options = array())
{
// Default to text type
$table = parent::getTable($name, $prefix, $options);
$table->type = 'text';
return $table;
}
/**
* Method to change the title & name.
*
* @param integer $categoryId The id of the category.
* @param string $name The name.
* @param string $title The title.
*
* @return array Contains the modified title and name.
*
* @since 3.7.0
*/
protected function generateNewTitle($categoryId, $name, $title)
{
// Alter the title & name
$table = $this->getTable();
while ($table->load(array('name' => $name)))
{
$title = StringHelper::increment($title);
$name = StringHelper::increment($name, 'dash');
}
return array(
$title,
$name,
);
}
/**
* Method to delete one or more records.
*
* @param array $pks An array of record primary keys.
*
* @return boolean True if successful, false if an error occurs.
*
* @since 3.7.0
*/
public function delete(&$pks)
{
$success = parent::delete($pks);
if ($success)
{
$pks = (array) $pks;
$pks = ArrayHelper::toInteger($pks);
$pks = array_filter($pks);
if (!empty($pks))
{
// Delete Values
$query = $this->getDbo()->getQuery(true);
$query->delete($query->quoteName('#__fields_values'))
->whereIn($query->quoteName('field_id'), $pks);
$this->getDbo()->setQuery($query)->execute();
// Delete Assigned Categories
$query = $this->getDbo()->getQuery(true);
$query->delete($query->quoteName('#__fields_categories'))
->whereIn($query->quoteName('field_id'), $pks);
$this->getDbo()->setQuery($query)->execute();
}
}
return $success;
}
/**
* Abstract method for getting the form from the model.
*
* @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.7.0
*/
public function getForm($data = array(), $loadData = true)
{
$context = $this->getState('field.context');
$jinput = Factory::getApplication()->input;
// A workaround to get the context into the model for save requests.
if (empty($context) && isset($data['context']))
{
$context = $data['context'];
$parts = FieldsHelper::extract($context);
$this->setState('field.context', $context);
if ($parts)
{
$this->setState('field.component', $parts[0]);
$this->setState('field.section', $parts[1]);
}
}
if (isset($data['type']))
{
// This is needed that the plugins can determine the type
$this->setState('field.type', $data['type']);
}
// Load the fields plugin that they can add additional parameters to the form
PluginHelper::importPlugin('fields');
// Get the form.
$form = $this->loadForm(
'com_fields.field.' . $context, 'field',
array(
'control' => 'jform',
'load_data' => true,
)
);
if (empty($form))
{
return false;
}
// Modify the form based on Edit State access controls.
if (empty($data['context']))
{
$data['context'] = $context;
}
$fieldId = $jinput->get('id');
$assetKey = $this->state->get('field.component') . '.field.' . $fieldId;
if (!Factory::getUser()->authorise('core.edit.state', $assetKey))
{
// Disable fields for display.
$form->setFieldAttribute('ordering', 'disabled', 'true');
$form->setFieldAttribute('state', 'disabled', 'true');
// Disable fields while saving. The controller has already verified this is a record you can edit.
$form->setFieldAttribute('ordering', 'filter', 'unset');
$form->setFieldAttribute('state', 'filter', 'unset');
}
return $form;
}
/**
* Setting the value for the given field id, context and item id.
*
* @param string $fieldId The field ID.
* @param string $itemId The ID of the item.
* @param string $value The value.
*
* @return boolean
*
* @since 3.7.0
*/
public function setFieldValue($fieldId, $itemId, $value)
{
$field = $this->getItem($fieldId);
$params = $field->params;
if (is_array($params))
{
$params = new Registry($params);
}
// Don't save the value when the user is not authorized to change it
if (!$field || !FieldsHelper::canEditFieldValue($field))
{
return false;
}
$needsDelete = false;
$needsInsert = false;
$needsUpdate = false;
$oldValue = $this->getFieldValue($fieldId, $itemId);
$value = (array) $value;
if ($oldValue === null)
{
// No records available, doing normal insert
$needsInsert = true;
}
elseif (count($value) == 1 && count((array) $oldValue) == 1)
{
// Only a single row value update can be done when not empty
$needsUpdate = is_array($value[0]) ? count($value[0]) : strlen($value[0]);
$needsDelete = !$needsUpdate;
}
else
{
// Multiple values, we need to purge the data and do a new
// insert
$needsDelete = true;
$needsInsert = true;
}
if ($needsDelete)
{
$fieldId = (int) $fieldId;
// Deleting the existing record as it is a reset
$query = $this->getDbo()->getQuery(true);
$query->delete($query->quoteName('#__fields_values'))
->where($query->quoteName('field_id') . ' = :fieldid')
->where($query->quoteName('item_id') . ' = :itemid')
->bind(':fieldid', $fieldId, ParameterType::INTEGER)
->bind(':itemid', $itemId);
$this->getDbo()->setQuery($query)->execute();
}
if ($needsInsert)
{
$newObj = new \stdClass;
$newObj->field_id = (int) $fieldId;
$newObj->item_id = $itemId;
foreach ($value as $v)
{
$newObj->value = $v;
$this->getDbo()->insertObject('#__fields_values', $newObj);
}
}
if ($needsUpdate)
{
$updateObj = new \stdClass;
$updateObj->field_id = (int) $fieldId;
$updateObj->item_id = $itemId;
$updateObj->value = reset($value);
$this->getDbo()->updateObject('#__fields_values', $updateObj, array('field_id', 'item_id'));
}
$this->valueCache = array();
FieldsHelper::clearFieldsCache();
return true;
}
/**
* Returning the value for the given field id, context and item id.
*
* @param string $fieldId The field ID.
* @param string $itemId The ID of the item.
*
* @return NULL|string
*
* @since 3.7.0
*/
public function getFieldValue($fieldId, $itemId)
{
$values = $this->getFieldValues(array($fieldId), $itemId);
if (array_key_exists($fieldId, $values))
{
return $values[$fieldId];
}
return null;
}
/**
* Returning the values for the given field ids, context and item id.
*
* @param array $fieldIds The field Ids.
* @param string $itemId The ID of the item.
*
* @return NULL|array
*
* @since 3.7.0
*/
public function getFieldValues(array $fieldIds, $itemId)
{
if (!$fieldIds)
{
return array();
}
// Create a unique key for the cache
$key = md5(serialize($fieldIds) . $itemId);
// Fill the cache when it doesn't exist
if (!array_key_exists($key, $this->valueCache))
{
// Create the query
$query = $this->getDbo()->getQuery(true);
$query->select($query->quoteName(['field_id', 'value']))
->from($query->quoteName('#__fields_values'))
->whereIn($query->quoteName('field_id'), ArrayHelper::toInteger($fieldIds))
->where($query->quoteName('item_id') . ' = :itemid')
->bind(':itemid', $itemId);
// Fetch the row from the database
$rows = $this->getDbo()->setQuery($query)->loadObjectList();
$data = array();
// Fill the data container from the database rows
foreach ($rows as $row)
{
// If there are multiple values for a field, create an array
if (array_key_exists($row->field_id, $data))
{
// Transform it to an array
if (!is_array($data[$row->field_id]))
{
$data[$row->field_id] = array($data[$row->field_id]);
}
// Set the value in the array
$data[$row->field_id][] = $row->value;
// Go to the next row, otherwise the value gets overwritten in the data container
continue;
}
// Set the value
$data[$row->field_id] = $row->value;
}
// Assign it to the internal cache
$this->valueCache[$key] = $data;
}
// Return the value from the cache
return $this->valueCache[$key];
}
/**
* Cleaning up the values for the given item on the context.
*
* @param string $context The context.
* @param string $itemId The Item ID.
*
* @return void
*
* @since 3.7.0
*/
public function cleanupValues($context, $itemId)
{
// Delete with inner join is not possible so we need to do a subquery
$fieldsQuery = $this->getDbo()->getQuery(true);
$fieldsQuery->select($fieldsQuery->quoteName('id'))
->from($fieldsQuery->quoteName('#__fields'))
->where($fieldsQuery->quoteName('context') . ' = :context');
$query = $this->getDbo()->getQuery(true);
$query->delete($query->quoteName('#__fields_values'))
->where($query->quoteName('field_id') . ' IN (' . $fieldsQuery . ')')
->where($query->quoteName('item_id') . ' = :itemid')
->bind(':itemid', $itemId)
->bind(':context', $context);
$this->getDbo()->setQuery($query)->execute();
}
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to delete the record. Defaults to the permission for the component.
*
* @since 3.7.0
*/
protected function canDelete($record)
{
if (empty($record->id) || $record->state != -2)
{
return false;
}
$parts = FieldsHelper::extract($record->context);
return Factory::getUser()->authorise('core.delete', $parts[0] . '.field.' . (int) $record->id);
}
/**
* Method to test whether a record can have its state changed.
*
* @param object $record A record object.
*
* @return boolean True if allowed to change the state of the record. Defaults to the permission for the
* component.
*
* @since 3.7.0
*/
protected function canEditState($record)
{
$user = Factory::getUser();
$parts = FieldsHelper::extract($record->context);
// Check for existing field.
if (!empty($record->id))
{
return $user->authorise('core.edit.state', $parts[0] . '.field.' . (int) $record->id);
}
return $user->authorise('core.edit.state', $parts[0]);
}
/**
* Stock method to auto-populate the model state.
*
* @return void
*
* @since 3.7.0
*/
protected function populateState()
{
$app = Factory::getApplication();
// Load the User state.
$pk = $app->input->getInt('id');
$this->setState($this->getName() . '.id', $pk);
$context = $app->input->get('context', 'com_content.article');
$this->setState('field.context', $context);
$parts = FieldsHelper::extract($context);
// Extract the component name
$this->setState('field.component', $parts[0]);
// Extract the optional section name
$this->setState('field.section', (count($parts) > 1) ? $parts[1] : null);
// Load the parameters.
$params = ComponentHelper::getParams('com_fields');
$this->setState('params', $params);
}
/**
* A protected method to get a set of ordering conditions.
*
* @param JTable $table A JTable object.
*
* @return array An array of conditions to add to ordering queries.
*
* @since 3.7.0
*/
protected function getReorderConditions($table)
{
return [
$this->_db->quoteName('context') . ' = ' . $this->_db->quote($table->context),
];
}
/**
* Method to get the data that should be injected in the form.
*
* @return array The default data is an empty array.
*
* @since 3.7.0
*/
protected function loadFormData()
{
// Check the session for previously entered form data.
$app = Factory::getApplication();
$data = $app->getUserState('com_fields.edit.field.data', array());
if (empty($data))
{
$data = $this->getItem();
// Pre-select some filters (Status, Language, Access) in edit form
// if those have been selected in Category Manager
if (!$data->id)
{
// Check for which context the Category Manager is used and
// get selected fields
$filters = (array) $app->getUserState('com_fields.fields.filter');
$data->set('state', $app->input->getInt('state', ((isset($filters['state']) && $filters['state'] !== '') ? $filters['state'] : null)));
$data->set('language', $app->input->getString('language', (!empty($filters['language']) ? $filters['language'] : null)));
$data->set('group_id', $app->input->getString('group_id', (!empty($filters['group_id']) ? $filters['group_id'] : null)));
$data->set(
'access',
$app->input->getInt('access', (!empty($filters['access']) ? $filters['access'] : $app->get('access')))
);
// Set the type if available from the request
$data->set('type', $app->input->getWord('type', $this->state->get('field.type', $data->get('type'))));
}
if ($data->label && !isset($data->params['label']))
{
$data->params['label'] = $data->label;
}
}
$this->preprocessData('com_fields.field', $data);
return $data;
}
/**
* Method to validate the form data.
*
* @param JForm $form The form to validate against.
* @param array $data The data to validate.
* @param string $group The name of the field group to validate.
*
* @return array|boolean Array of filtered data if valid, false otherwise.
*
* @see JFormRule
* @see JFilterInput
* @since 3.9.23
*/
public function validate($form, $data, $group = null)
{
if (!JFactory::getUser()->authorise('core.admin', 'com_fields'))
{
if (isset($data['rules']))
{
unset($data['rules']);
}
}
return parent::validate($form, $data, $group);
}
/**
* Method to allow derived classes to preprocess the form.
*
* @param \JForm $form A JForm object.
* @param mixed $data The data expected for the form.
* @param string $group The name of the plugin group to import (defaults to "content").
*
* @return void
*
* @see \Joomla\CMS\Form\FormField
* @since 3.7.0
* @throws \Exception if there is an error in the form event.
*/
protected function preprocessForm(Form $form, $data, $group = 'content')
{
$component = $this->state->get('field.component');
$section = $this->state->get('field.section');
$dataObject = $data;
if (is_array($dataObject))
{
$dataObject = (object) $dataObject;
}
if (isset($dataObject->type))
{
$form->setFieldAttribute('type', 'component', $component);
// Not allowed to change the type of an existing record
if ($dataObject->id)
{
$form->setFieldAttribute('type', 'readonly', 'true');
}
// Allow to override the default value label and description through the plugin
$key = 'PLG_FIELDS_' . strtoupper($dataObject->type) . '_DEFAULT_VALUE_LABEL';
if (Factory::getLanguage()->hasKey($key))
{
$form->setFieldAttribute('default_value', 'label', $key);
}
$key = 'PLG_FIELDS_' . strtoupper($dataObject->type) . '_DEFAULT_VALUE_DESC';
if (Factory::getLanguage()->hasKey($key))
{
$form->setFieldAttribute('default_value', 'description', $key);
}
// Remove placeholder field on list fields
if ($dataObject->type == 'list')
{
$form->removeField('hint', 'params');
}
}
// Get the categories for this component (and optionally this section, if available)
$cat = (
function () use ($component, $section) {
// Get the CategoryService for this component
$componentObject = $this->bootComponent($component);
if (!$componentObject instanceof CategoryServiceInterface)
{
// No CategoryService -> no categories
return null;
}
$cat = null;
// Try to get the categories for this component and section
try
{
$cat = $componentObject->getCategory([], $section ?: '');
}
catch (SectionNotFoundException $e)
{
// Not found for component and section -> Now try once more without the section, so only component
try
{
$cat = $componentObject->getCategory();
}
catch (SectionNotFoundException $e)
{
// If we haven't found it now, return (no categories available for this component)
return null;
}
}
// So we found categories for at least the component, return them
return $cat;
}
)();
// If we found categories, and if the root category has children, set them in the form
if ($cat && $cat->get('root')->hasChildren())
{
$form->setFieldAttribute('assigned_cat_ids', 'extension', $cat->getExtension());
}
else
{
// Else remove the field from the form
$form->removeField('assigned_cat_ids');
}
$form->setFieldAttribute('type', 'component', $component);
$form->setFieldAttribute('group_id', 'context', $this->state->get('field.context'));
$form->setFieldAttribute('rules', 'component', $component);
// Looking in the component forms folder for a specific section forms file
$path = Path::clean(JPATH_ADMINISTRATOR . '/components/' . $component . '/forms/fields/' . $section . '.xml');
if (!file_exists($path))
{
// Looking in the component models/forms folder for a specific section forms file
$path = Path::clean(JPATH_ADMINISTRATOR . '/components/' . $component . '/models/forms/fields/' . $section . '.xml');
}
if (file_exists($path))
{
$lang = Factory::getLanguage();
$lang->load($component, JPATH_BASE);
$lang->load($component, JPATH_BASE . '/components/' . $component);
if (!$form->loadFile($path, false))
{
throw new \Exception(Text::_('JERROR_LOADFILE_FAILED'));
}
}
// Trigger the default form events.
parent::preprocessForm($form, $data, $group);
}
/**
* Clean the cache
*
* @param string $group The cache group
* @param integer $clientId The ID of the client
*
* @return void
*
* @since 3.7.0
*/
protected function cleanCache($group = null, $clientId = 0)
{
$context = Factory::getApplication()->input->get('context');
switch ($context)
{
case 'com_content':
parent::cleanCache('com_content');
parent::cleanCache('mod_articles_archive');
parent::cleanCache('mod_articles_categories');
parent::cleanCache('mod_articles_category');
parent::cleanCache('mod_articles_latest');
parent::cleanCache('mod_articles_news');
parent::cleanCache('mod_articles_popular');
break;
default:
parent::cleanCache($context);
break;
}
}
/**
* Batch copy fields to a new group.
*
* @param integer $value The new value matching a fields group.
* @param array $pks An array of row IDs.
* @param array $contexts An array of item contexts.
*
* @return array|boolean new IDs if successful, false otherwise and internal error is set.
*
* @since 3.7.0
*/
protected function batchCopy($value, $pks, $contexts)
{
// Set the variables
$user = Factory::getUser();
$table = $this->getTable();
$newIds = array();
$component = $this->state->get('filter.component');
$value = (int) $value;
foreach ($pks as $pk)
{
if ($user->authorise('core.create', $component . '.fieldgroup.' . $value))
{
$table->reset();
$table->load($pk);
$table->group_id = $value;
// Reset the ID because we are making a copy
$table->id = 0;
// Unpublish the new field
$table->state = 0;
if (!$table->store())
{
$this->setError($table->getError());
return false;
}
// Get the new item ID
$newId = $table->get('id');
// Add the new ID to the array
$newIds[$pk] = $newId;
}
else
{
$this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
return false;
}
}
// Clean the cache
$this->cleanCache();
return $newIds;
}
/**
* Batch move fields to a new group.
*
* @param integer $value The new value matching a fields group.
* @param array $pks An array of row IDs.
* @param array $contexts An array of item contexts.
*
* @return boolean True if successful, false otherwise and internal error is set.
*
* @since 3.7.0
*/
protected function batchMove($value, $pks, $contexts)
{
// Set the variables
$user = Factory::getUser();
$table = $this->getTable();
$context = explode('.', Factory::getApplication()->getUserState('com_fields.fields.context'));
$value = (int) $value;
foreach ($pks as $pk)
{
if ($user->authorise('core.edit', $context[0] . '.fieldgroup.' . $value))
{
$table->reset();
$table->load($pk);
$table->group_id = $value;
if (!$table->store())
{
$this->setError($table->getError());
return false;
}
}
else
{
$this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
return false;
}
}
// Clean the cache
$this->cleanCache();
return true;
}
}