| Current Path : /home/digilove/public_html/41423/ |
| Current File : //home/digilove/public_html/41423/Form.php.tar |
home/digilove/public_html/libraries/regularlabs/src/Form.php 0000644 00000050201 15234627163 0020271 0 ustar 00 <?php
/**
* @package Regular Labs Library
* @version 23.7.24631
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2023 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
namespace RegularLabs\Library;
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper as JHtml;
use Joomla\CMS\Language\Text as JText;
use Joomla\CMS\Plugin\PluginHelper as JPluginHelper;
use RegularLabs\Library\ParametersNew as Parameters;
class Form
{
public static function getAddToLoadAjaxListScript($field, $name, $value, $id, $attributes = [], $simple = false)
{
$attributes['field'] = $field;
$attributes['name'] = $name;
$attributes['value'] = $value;
$attributes['id'] = $id;
$url = 'index.php?option=com_ajax&plugin=regularlabs&format=raw'
. '&' . Uri::createCompressedAttributes(json_encode($attributes));
$remove_spinner = "$('#" . $id . "_spinner').remove();";
$replace_field = "$('#" . $id . "').replaceWith(data);";
$init_chosen = 'document.getElementById("' . $id . '") && document.getElementById("' . $id . '").nodeName == "SELECT" && $("#' . $id . '").chosen();';
$success = $replace_field;
if ($simple)
{
$success .= $init_chosen;
}
else
{
Document::script('regularlabs/multiselect.min.js');
Document::stylesheet('regularlabs/multiselect.min.css');
$success .= "if(data.indexOf('rl_multiselect') > -1)\{RegularLabsMultiSelect.init($('#" . $id . "'));\} else { " . $init_chosen . "}";
}
// $success .= "console.log('#" . $id . "');";
// $success .= "console.log(data);";
$error = $remove_spinner;
$success = "if(data)\{" . $success . "\}" . $remove_spinner;
$script = "jQuery(document).ready(function() {"
. "RegularLabsScripts.addToLoadAjaxList("
. "'" . addslashes($url) . "',"
. "'" . addslashes($success) . "',"
. "'" . addslashes($error) . "'"
. ")"
. "});";
return '<script>' . $script . '</script>';
}
public static function getOptionsCount($options)
{
$count = 0;
foreach ($options as $option)
{
$count++;
if ( ! empty($option->links))
{
$count += self::getOptionsCount($option->links);
}
}
return $count;
}
/**
* Prepare the string for a select form field item
*
* @param string $string
* @param int $published
* @param string $type
* @param int $remove_first
*
* @return string
*/
public static function prepareSelectItem($string, $published = 1, $type = '', $remove_first = 0)
{
if (empty($string))
{
return '';
}
$string = str_replace([' ', ' '], ' ', $string);
$string = RegEx::replace('- ', ' ', $string);
for ($i = 0; $remove_first > $i; $i++)
{
$string = RegEx::replace('^ ', '', $string, '');
}
if (RegEx::match('^( *)(.*)$', $string, $match, ''))
{
[$string, $pre, $name] = $match;
$pre = str_replace(' ', ' · ', $pre);
$pre = RegEx::replace('(( · )*) · ', '\1 » ', $pre);
$pre = str_replace(' ', ' ', $pre);
$string = $pre . $name;
}
switch (true)
{
case ($type == 'separator'):
$string = '[[:font-weight:normal;font-style:italic;color:grey;:]]' . $string;
break;
case ($published == -2):
$string = '[[:font-style:italic;color:grey;:]]' . $string . ' [' . JText::_('JTRASHED') . ']';
break;
case ($published == 0):
$string = '[[:font-style:italic;color:grey;:]]' . $string . ' [' . JText::_('JUNPUBLISHED') . ']';
break;
case ($published == 2):
$string = '[[:font-style:italic;:]]' . $string . ' [' . JText::_('JARCHIVED') . ']';
break;
}
return $string;
}
/**
* Render a full select list
*
* @param array $options
* @param string $name
* @param string $value
* @param string $id
* @param int $size
* @param bool $multiple
* @param bool $simple
* @param bool $readonly
* @param bool $ignore_max_count
*
* @return string
*/
public static function selectList(&$options, $name, $value, $id, $size = 0, $multiple = false, $simple = false, $readonly = false, $ignore_max_count = false)
{
if (empty($options))
{
return '<fieldset class="radio">' . JText::_('RL_NO_ITEMS_FOUND') . '</fieldset>';
}
if ( ! $multiple)
{
$simple = true;
}
$params = Parameters::getPlugin('regularlabs');
$value = ArrayHelper::toArray($value);
$value = ArrayHelper::clean($value);
if (count($value) === 1 && strpos($value[0], ',') !== false)
{
$value = ArrayHelper::toArray($value[0]);
}
$count = 0;
if ($options != -1)
{
foreach ($options as $option)
{
$count++;
if (isset($option->links))
{
$count += count($option->links);
}
if ( ! $ignore_max_count && $count > $params->max_list_count)
{
break;
}
}
}
if ($options == -1 || ( ! $ignore_max_count && $count > $params->max_list_count))
{
if (is_array($value))
{
$value = implode(',', $value);
}
if ( ! $value)
{
$input = '<textarea name="' . $name . '" id="' . $id . '" cols="40" rows="5">' . $value . '</textarea>';
}
else
{
$input = '<input type="text" name="' . $name . '" id="' . $id . '" value="' . $value . '" size="60">';
}
$plugin = JPluginHelper::getPlugin('system', 'regularlabs');
$url = ! empty($plugin->id)
? 'index.php?option=com_plugins&task=plugin.edit&extension_id=' . $plugin->id
: 'index.php?option=com_plugins&filter_folder=&filter_search=Regular%20Labs%20Library';
$label = JText::_('RL_ITEM_IDS');
$text = JText::_('RL_MAX_LIST_COUNT_INCREASE');
$tooltip = JText::_('RL_MAX_LIST_COUNT_INCREASE_DESC,' . $params->max_list_count . ',RL_MAX_LIST_COUNT');
$link = '<a href="' . $url . '" target="_blank" id="' . $id . '_msg"'
. ' class="hasPopover" title="' . $text . '" data-content="' . htmlentities($tooltip) . '">'
. '<span class="icon icon-cog"></span>'
. $text
. '</a>';
$script = 'jQuery("#' . $id . '_msg").popover({"html": true,"trigger": "hover focus","container": "body"})';
return '<fieldset class="radio">'
. '<label for="' . $id . '">' . $label . ':</label>'
. $input
. '<br><small>' . $link . '</small>'
. '</fieldset>'
. '<script>' . $script . '</script>';
}
if ($simple)
{
$first_level = $options[0]->level ?? 0;
foreach ($options as &$option)
{
if ( ! isset($option->level))
{
continue;
}
$repeat = ($option->level - $first_level > 0) ? $option->level - $first_level : 0;
if ( ! $repeat)
{
continue;
}
//$option->text = str_repeat(' - ', $repeat) . $option->text;
$option->text = '[[:padding-left: ' . (5 + ($repeat * 15)) . 'px;:]]' . $option->text;
}
}
if ( ! $multiple)
{
$attr = 'class="inputbox"';
if ($readonly)
{
$attr .= ' readonly="readonly"';
}
if (is_array(reset($options)) && isset(reset($options)['items']))
{
return JHtml::_(
'select.groupedlist', $options, $name,
[
'id' => $id,
'group.id' => 'id',
'list.attr' => $attr,
'list.select' => $value,
]
);
}
$html = JHtml::_('select.genericlist', $options, $name, $attr, 'value', 'text', $value, $id);
return self::handlePreparedStyles($html);
}
$size = (int) $size ?: 300;
if ($simple)
{
$attr = 'style="width: ' . $size . 'px" multiple="multiple"';
if ($readonly)
{
$attr .= ' readonly="readonly"';
}
if (substr($name, -2) !== '[]')
{
$name .= '[]';
}
if (is_array(reset($options)) && isset(reset($options)['items']))
{
return JHtml::_(
'select.groupedlist', $options, $name,
[
'id' => $id,
'group.id' => 'id',
'list.attr' => trim($attr),
'list.select' => $value,
]
);
}
$html = JHtml::_('select.genericlist', $options, $name, trim($attr), 'value', 'text', $value, $id);
return self::handlePreparedStyles($html);
}
Language::load('com_modules', JPATH_ADMINISTRATOR);
Document::script('regularlabs/multiselect.min.js');
Document::stylesheet('regularlabs/multiselect.min.css');
$count_total = self::getOptionsCount($options);
$count_selected = count($value);
$has_nested = $count_total > count($options);
$html = [];
$html[] = '<div class="well well-small rl_multiselect" id="' . $id . '">';
$html[] = '<div class="form-inline rl_multiselect-controls">';
$html[] = '<span class="small">' . JText::_('JSELECT') . ':
<a class="rl_multiselect-checkall" href="javascript:;">' . JText::_('JALL') . '</a>
<span class="ghosted">[' . $count_total . ']</span>,
<a class="rl_multiselect-uncheckall" href="javascript:;">' . JText::_('JNONE') . '</a>,
<a class="rl_multiselect-toggleall" href="javascript:;">' . JText::_('RL_TOGGLE') . '</a>
</span>';
$html[] = '<span> | </span>';
if ($has_nested)
{
$html[] = '<span class="small">' . JText::_('RL_EXPAND') . ':
<a class="rl_multiselect-expandall" href="javascript:;">' . JText::_('JALL') . '</a>,
<a class="rl_multiselect-collapseall" href="javascript:;">' . JText::_('JNONE') . '</a>
</span>';
$html[] = '<span> | </span>';
}
$html[] = '<span class="small">' . JText::_('JSHOW') . ':
<a class="rl_multiselect-showall" href="javascript:;">' . JText::_('JALL') . '</a>
<span class="ghosted">[' . $count_total . ']</span>,
<a class="rl_multiselect-showselected" href="javascript:;">' . JText::_('RL_SELECTED') . '</a>
<span class="ghosted">[<span class="rl_multiselect-count-selected">' . $count_selected . '</span>]</span>
</span>';
$html[] = '<span class="rl_multiselect-maxmin">
<span> | </span>
<span class="small">
<a class="rl_multiselect-maximize" href="javascript:;">' . JText::_('RL_MAXIMIZE') . '</a>
<a class="rl_multiselect-minimize" style="display:none;" href="javascript:;">' . JText::_('RL_MINIMIZE') . '</a>
</span>
</span>';
$html[] = '<input type="text" name="rl_multiselect-filter" class="rl_multiselect-filter input-medium search-query pull-right" size="16"
autocomplete="off" placeholder="' . JText::_('JSEARCH_FILTER') . '" aria-invalid="false" tabindex="-1">';
$html[] = '</div>';
$html[] = '<hr class="hr-condensed">';
$o = [];
foreach ($options as $option)
{
$option->level ??= 0;
$o[] = $option;
if (isset($option->links))
{
foreach ($option->links as $link)
{
$link->level = $option->level + ($link->level ?? 1);
$o[] = $link;
}
}
}
$html[] = '<ul class="rl_multiselect-ul" style="max-height:300px;min-width:' . $size . 'px;overflow-x: hidden;">';
$prevlevel = 0;
foreach ($o as $i => $option)
{
if ($prevlevel < $option->level)
{
// correct wrong level indentations
$option->level = $prevlevel + 1;
$html[] = '<ul class="rl_multiselect-sub">';
}
else if ($prevlevel > $option->level)
{
$html[] = str_repeat('</li></ul>', $prevlevel - $option->level);
}
else if ($i)
{
$html[] = '</li>';
}
$labelclass = trim('pull-left ' . ($option->labelclass ?? ''));
$html[] = '<li>';
$item = '<div class="' . trim('rl_multiselect-item pull-left ' . ($option->class ?? '')) . '">';
if (isset($option->title))
{
$labelclass .= ' nav-header';
}
if (isset($option->title) && ( ! isset($option->value) || ! $option->value))
{
$item .= '<label class="' . $labelclass . '">' . $option->title . '</label>';
}
else
{
$selected = in_array($option->value, $value) ? ' checked="checked"' : '';
$disabled = (isset($option->disable) && $option->disable) ? ' disabled="disabled"' : '';
if (empty($option->hide_select))
{
$item .= '<input type="checkbox" class="pull-left" name="' . $name . '" id="' . $id . $option->value . '" value="' . $option->value . '"' . $selected . $disabled . '>';
}
$item .= '<label for="' . $id . $option->value . '" class="' . $labelclass . '">' . $option->text . '</label>';
}
$item .= '</div>';
$html[] = $item;
if ( ! isset($o[$i + 1]) && $option->level > 0)
{
$html[] = str_repeat('</li></ul>', (int) $option->level);
}
$prevlevel = $option->level;
}
$html[] = '</ul>';
$html[] = '
<div style="display:none;" class="rl_multiselect-menu-block">
<div class="pull-left nav-hover rl_multiselect-menu">
<div class="btn-group">
<a href="#" data-toggle="dropdown" class="dropdown-toggle btn btn-micro">
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li class="nav-header">' . JText::_('COM_MODULES_SUBITEMS') . '</li>
<li class="divider"></li>
<li class=""><a class="checkall" href="javascript:;"><span class="icon-checkbox"></span> ' . JText::_('JSELECT') . '</a>
</li>
<li><a class="uncheckall" href="javascript:;"><span class="icon-checkbox-unchecked"></span> ' . JText::_('COM_MODULES_DESELECT') . '</a>
</li>
<div class="rl_multiselect-menu-expand">
<li class="divider"></li>
<li><a class="expandall" href="javascript:;"><span class="icon-plus"></span> ' . JText::_('RL_EXPAND') . '</a></li>
<li><a class="collapseall" href="javascript:;"><span class="icon-minus"></span> ' . JText::_('RL_COLLAPSE') . '</a></li>
</div>
</ul>
</div>
</div>
</div>';
$html[] = '</div>';
$html = implode('', $html);
return self::handlePreparedStyles($html);
}
/**
* Render a select list loaded via Ajax
*
* @param string $field
* @param string $name
* @param string $value
* @param string $id
* @param array $attributes
* @param bool $simple
*
* @return string
*/
public static function selectListAjax($field, $name, $value, $id, $attributes = [], $simple = false)
{
JHtml::_('jquery.framework');
$script = self::getAddToLoadAjaxListScript($field, $name, $value, $id, $attributes, $simple);
if (is_array($value))
{
$value = implode(',', $value);
}
Document::script('regularlabs/script.min.js');
Document::stylesheet('regularlabs/style.min.css');
$input = '<textarea name="' . $name . '" id="' . $id . '" cols="40" rows="5">' . $value . '</textarea>'
. '<div id="' . $id . '_spinner" class="rl_spinner"></div>';
return $input . $script;
}
/**
* Render a simple select list
*
* @param array $options
* @param $string $name
* @param string $value
* @param string $id
* @param int $size
* @param bool $multiple
* @param bool $readonly
* @param bool $ignore_max_count
*
* @return string
*/
public static function selectListSimple(&$options, $name, $value, $id, $size = 0, $multiple = false, $readonly = false, $ignore_max_count = false)
{
return self::selectlist($options, $name, $value, $id, $size, $multiple, true, $readonly, $ignore_max_count);
}
/**
* Render a simple select list loaded via Ajax
*
* @param string $field
* @param string $name
* @param string $value
* @param string $id
* @param array $attributes
*
* @return string
*/
public static function selectListSimpleAjax($field, $name, $value, $id, $attributes = [])
{
return self::selectListAjax($field, $name, $value, $id, $attributes, true);
}
/**
* Replace style placeholders with actual style attributes
*
* @param string $string
*
* @return string
*/
private static function handlePreparedStyles($string)
{
// No placeholders found
if (strpos($string, '[[:') === false)
{
return $string;
}
// Doing following replacement in 3 steps to prevent the Regular Expressions engine from exploding
// Replace style tags right after the html tags
$string = RegEx::replace(
';?:\]\]\s*\[\[:',
';',
$string
);
$string = RegEx::replace(
'>\s*\[\[\:(.*?)\:\]\]',
' style="\1">',
$string
);
// No more placeholders found
if (strpos($string, '[[:') === false)
{
return $string;
}
// Replace style tags prepended with a minus and any amount of whitespace: '- '
$string = RegEx::replace(
'>((?:-\s*)+)\[\[\:(.*?)\:\]\]',
' style="\2">\1',
$string
);
// No more placeholders found
if (strpos($string, '[[:') === false)
{
return $string;
}
// Replace style tags prepended with whitespace, a minus and any amount of whitespace: ' - '
$string = RegEx::replace(
'>((?:\s+-\s*)+)\[\[\:(.*?)\:\]\]',
' style="\2">\1',
$string
);
return $string;
}
}
home/digilove/public_html/110/libraries/fof30/Form/Form.php 0000644 00000071360 15235524365 0017332 0 ustar 00 <?php
/**
* @package FOF
* @copyright Copyright (c)2010-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 2 or later
*/
namespace FOF30\Form;
use FOF30\Container\Container;
use FOF30\Form\Header\HeaderBase;
use FOF30\Model\DataModel;
use FOF30\View\DataView\DataViewInterface;
use JFactory;
use JForm;
use Joomla\Registry\Registry;
use JText;
use SimpleXMLElement;
defined('_JEXEC') or die;
/**
* Form is an extension to JForm which support not only edit views but also
* browse (record list) and read (single record display) views based on XML
* forms.
*
* @package FrameworkOnFramework
* @since 2.0
*
* @deprecated 3.1 Support for XML forms will be removed in FOF 4
*/
class Form extends JForm
{
/**
* The model attached to this view
*
* @var DataModel
*/
protected $model;
/**
* The view used to render this form
*
* @var DataViewInterface
*/
protected $view;
/**
* The Container this form belongs to
*
* @var \FOF30\Container\Container
*/
protected $container;
/**
* Map of entity objects for re-use.
* Prototypes for all fields and rules are here.
*
* Array's structure:
* <code>
* entities:
* {ENTITY_NAME}:
* {KEY}: {OBJECT}
* </code>
*
* @var array
*/
protected $entities = array();
/**
* Method to instantiate the form object.
*
* @param Container $container The component Container where this form belongs to
* @param string $name The name of the form.
* @param array $options An array of form options.
*/
public function __construct(Container $container, $name, array $options = array())
{
parent::__construct($name, $options);
$this->container = $container;
}
/**
* Returns the value of an attribute of the form itself
*
* @param string $attribute The name of the attribute
* @param mixed $default Optional default value to return
*
* @return mixed
*
* @since 2.0
*/
public function getAttribute($attribute, $default = null)
{
$value = $this->xml->attributes()->$attribute;
if (is_null($value))
{
return $default;
}
else
{
return (string)$value;
}
}
/**
* Loads the CSS files defined in the form, based on its cssfiles attribute
*
* @return void
*
* @since 2.0
*/
public function loadCSSFiles()
{
// Support for CSS files
$cssfiles = $this->getAttribute('cssfiles');
if (!empty($cssfiles))
{
$cssfiles = explode(',', $cssfiles);
foreach ($cssfiles as $cssfile)
{
$this->getView()->addCssFile(trim($cssfile));
}
}
// Support for LESS files
$lessfiles = $this->getAttribute('lessfiles');
if (!empty($lessfiles))
{
$lessfiles = explode(',', $lessfiles);
foreach ($lessfiles as $def)
{
$parts = explode('||', $def, 2);
$lessfile = $parts[0];
$alt = (count($parts) > 1) ? trim($parts[1]) : null;
$this->getView()->addLess(trim($lessfile), $alt);
}
}
}
/**
* Loads the Javascript files defined in the form, based on its jsfiles attribute
*
* @return void
*
* @since 2.0
*/
public function loadJSFiles()
{
$jsfiles = $this->getAttribute('jsfiles');
if (empty($jsfiles))
{
return;
}
$jsfiles = explode(',', $jsfiles);
foreach ($jsfiles as $jsfile)
{
$this->getView()->addJavascriptFile(trim($jsfile));
}
}
/**
* Returns a reference to the protected $data object, allowing direct
* access to and manipulation of the form's data.
*
* @return \JRegistry|Registry The form's data registry
*
* @since 2.0
*/
public function &getData()
{
return $this->data;
}
/**
* Method to load the form description from an XML file.
*
* The reset option works on a group basis. If the XML file references
* groups that have already been created they will be replaced with the
* fields in the new XML file unless the $reset parameter has been set
* to false.
*
* @param string $file The filesystem path of an XML file.
* @param bool $reset Flag to toggle whether form fields should be replaced if a field
* already exists with the same group/name.
* @param bool $xpath An optional xpath to search for the fields.
*
* @return boolean True on success, false otherwise.
*/
public function loadFile($file, $reset = true, $xpath = false)
{
// Check to see if the path is an absolute path.
if (!is_file($file))
{
return false;
}
// Attempt to load the XML file.
$xml = simplexml_load_file($file);
return $this->load($xml, $reset, $xpath);
}
/**
* Attaches a DataModel to this form
*
* @param DataModel &$model The model to attach to the form
*
* @return void
*/
public function setModel(DataModel &$model)
{
$this->model = $model;
}
/**
* Returns the DataModel attached to this form
*
* @return DataModel
*/
public function &getModel()
{
return $this->model;
}
/**
* Attaches a DataViewInterface to this form
*
* @param DataViewInterface &$view The view to attach to the form
*
* @return void
*/
public function setView(DataViewInterface &$view)
{
$this->view = $view;
}
/**
* Returns the DataViewInterface attached to this form
*
* @return DataViewInterface
*/
public function &getView()
{
return $this->view;
}
/**
* Method to get an array of FormHeader objects in the headerset.
*
* @return array The array of HeaderInterface objects in the headerset.
*
* @since 2.0
*/
public function getHeaderset()
{
$fields = array();
$elements = $this->findHeadersByGroup();
// If no field elements were found return empty.
if (empty($elements))
{
return $fields;
}
// Build the result array from the found field elements.
/** @var \SimpleXMLElement $element */
foreach ($elements as $element)
{
// Get the field groups for the element.
$attrs = $element->xpath('ancestor::headerset[@name]/@name');
$groups = array_map('strval', $attrs ? $attrs : array());
$group = implode('.', $groups);
// If the field is successfully loaded add it to the result array.
/** @var HeaderBase $field */
if ($field = $this->loadHeader($element, $group))
{
$fields[$field->id] = $field;
}
}
return $fields;
}
/**
* Method to get an array of <header /> elements from the form XML document which are
* in a control group by name.
*
* @param mixed $group The optional dot-separated form group path on which to find the fields.
* Null will return all fields. False will return fields not in a group.
* @param boolean $nested True to also include fields in nested groups that are inside of the
* group for which to find fields.
*
* @return \SimpleXMLElement|bool Boolean false on error or array of SimpleXMLElement objects.
*
* @since 2.0
*/
protected function &findHeadersByGroup($group = null, $nested = false)
{
$false = false;
$fields = array();
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof \SimpleXMLElement))
{
return $false;
}
// Get only fields in a specific group?
if ($group)
{
// Get the fields elements for a given group.
$elements = &$this->findHeader($group);
// Get all of the field elements for the fields elements.
/** @var \SimpleXMLElement $element */
foreach ($elements as $element)
{
// If there are field elements add them to the return result.
if ($tmp = $element->xpath('descendant::header'))
{
// If we also want fields in nested groups then just merge the arrays.
if ($nested)
{
$fields = array_merge($fields, $tmp);
}
// If we want to exclude nested groups then we need to check each field.
else
{
$groupNames = explode('.', $group);
foreach ($tmp as $field)
{
// Get the names of the groups that the field is in.
$attrs = $field->xpath('ancestor::headers[@name]/@name');
$names = array_map('strval', $attrs ? $attrs : array());
// If the field is in the specific group then add it to the return list.
if ($names == (array)$groupNames)
{
$fields = array_merge($fields, array($field));
}
}
}
}
}
}
elseif ($group === false)
{
// Get only field elements not in a group.
$fields = $this->xml->xpath('descendant::headers[not(@name)]/header | descendant::headers[not(@name)]/headerset/header ');
}
else
{
// Get an array of all the <header /> elements.
$fields = $this->xml->xpath('//header');
}
return $fields;
}
/**
* Method to get a header field represented as a HeaderInterface object.
*
* @param string $name The name of the header field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The optional value to use as the default for the field. (DEPRECATED)
*
* @return HeaderInterface|bool The HeaderInterface object for the field or boolean false on error.
*
* @since 2.0
*/
public function getHeader($name, $group = null, $value = null)
{
// Make sure there is a valid Form XML document.
if (!($this->xml instanceof \SimpleXMLElement))
{
return false;
}
// Attempt to find the field by name and group.
$element = $this->findHeader($name, $group);
// If the field element was not found return false.
if (!$element)
{
return false;
}
return $this->loadHeader($element, $group);
}
/**
* Method to get a header field represented as an XML element object.
*
* @param string $name The name of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
*
* @return mixed The XML element object for the field or boolean false on error.
*
* @since 2.0
*/
protected function findHeader($name, $group = null)
{
$element = false;
$fields = array();
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof \SimpleXMLElement))
{
return false;
}
// Let's get the appropriate field element based on the method arguments.
if ($group)
{
// Get the fields elements for a given group.
$elements = &$this->findGroup($group);
// Get all of the field elements with the correct name for the fields elements.
/** @var \SimpleXMLElement $element */
foreach ($elements as $element)
{
// If there are matching field elements add them to the fields array.
if ($tmp = $element->xpath('descendant::header[@name="' . $name . '"]'))
{
$fields = array_merge($fields, $tmp);
}
}
// Make sure something was found.
if (!$fields)
{
return false;
}
// Use the first correct match in the given group.
$groupNames = explode('.', $group);
/** @var \SimpleXMLElement $field */
foreach ($fields as &$field)
{
// Get the group names as strings for ancestor fields elements.
$attrs = $field->xpath('ancestor::headerfields[@name]/@name');
$names = array_map('strval', $attrs ? $attrs : array());
// If the field is in the exact group use it and break out of the loop.
if ($names == (array)$groupNames)
{
$element = &$field;
break;
}
}
}
else
{
// Get an array of fields with the correct name.
$fields = $this->xml->xpath('//header[@name="' . $name . '"]');
// Make sure something was found.
if (!$fields)
{
return false;
}
// Search through the fields for the right one.
foreach ($fields as &$field)
{
// If we find an ancestor fields element with a group name then it isn't what we want.
if ($field->xpath('ancestor::headerfields[@name]'))
{
continue;
}
// Found it!
else
{
$element = &$field;
break;
}
}
}
return $element;
}
/**
* Method to load, setup and return a HeaderInterface object based on field data.
*
* @param string $element The XML element object representation of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
*
* @return HeaderInterface|bool The HeaderInterface object for the field or boolean false on error.
*
* @since 2.0
*/
protected function loadHeader($element, $group = null)
{
// Make sure there is a valid SimpleXMLElement.
if (!($element instanceof \SimpleXMLElement))
{
return false;
}
// Get the field type.
$type = $element['type'] ? (string)$element['type'] : 'field';
// Load the JFormField object for the field.
$field = $this->loadHeaderType($type);
// If the object could not be loaded, get a text field object.
if ($field === false)
{
$field = $this->loadHeaderType('field');
}
// Setup the HeaderInterface object.
$field->setForm($this);
if ($field->setup($element, $group))
{
return $field;
}
else
{
return false;
}
}
/**
* Method to remove a header from the form definition.
*
* @param string $name The name of the form field for which remove.
* @param string $group The optional dot-separated form group path on which to find the field.
*
* @return boolean True on success, false otherwise.
*
* @throws \UnexpectedValueException
*/
public function removeHeader($name, $group = null)
{
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof SimpleXMLElement))
{
throw new \UnexpectedValueException(sprintf('%s::getFieldAttribute `xml` is not an instance of SimpleXMLElement', get_class($this)));
}
// Find the form field element from the definition.
$element = $this->findHeader($name, $group);
// If the element exists remove it from the form definition.
if ($element instanceof SimpleXMLElement)
{
$dom = dom_import_simplexml($element);
$dom->parentNode->removeChild($dom);
return true;
}
return false;
}
/**
* Proxy for {@link Helper::loadFieldType()}.
*
* @param string $type The field type.
* @param boolean $new Flag to toggle whether we should get a new instance of the object.
*
* @return FieldInterface|bool FieldInterface object on success, false otherwise.
*
* @since 2.0
*/
protected function loadFieldType($type, $new = true)
{
return $this->loadType('field', $type, $new);
}
/**
* Proxy for {@link Helper::loadHeaderType()}.
*
* @param string $type The field type.
* @param boolean $new Flag to toggle whether we should get a new instance of the object.
*
* @return HeaderInterface|bool HeaderInterface object on success, false otherwise.
*
* @since 2.0
*/
protected function loadHeaderType($type, $new = true)
{
return $this->loadType('header', $type, $new);
}
/**
* Proxy for {@link Helper::loadRuleType()}.
*
* @param string $type The rule type.
* @param boolean $new Flag to toggle whether we should get a new instance of the object.
*
* @return \JFormRule|bool JFormRule object on success, false otherwise.
*
* @see Helper::loadRuleType()
* @since 2.0
*/
protected function loadRuleType($type, $new = true)
{
return $this->loadType('rule', $type, $new);
}
/**
* Method to load a form entity object given a type.
* Each type is loaded only once and then used as a prototype for other objects of same type.
* Please, use this method only with those entities which support types (forms don't support them).
*
* @param string $entity The entity.
* @param string $type The entity type.
* @param boolean $new Flag to toggle whether we should get a new instance of the object.
*
* @return mixed Entity object on success, false otherwise.
*/
protected function loadType($entity, $type, $new = true)
{
// Reference to an array with current entity's type instances
$types = &$this->entities[$entity];
// Return an entity object if it already exists and we don't need a new one.
if (isset($types[$type]) && $new === false)
{
return $types[$type];
}
$class = $this->loadClass($entity, $type);
if ($class !== false)
{
// Instantiate a new type object.
$types[$type] = new $class;
return $types[$type];
}
else
{
return false;
}
}
/**
* Load a class for one of the form's entities of a particular type.
* Currently, it makes sense to use this method for the "field" and "rule" entities
* (but you can support more entities in your subclass).
*
* @param string $entity One of the form entities (field, header or rule).
* @param string $type Type of an entity.
*
* @return mixed Class name on success or false otherwise.
*
* @since 2.0
*/
public function loadClass($entity, $type)
{
// Get the prefixes for namespaced classes (FOF3 way)
$namespacedPrefixes = array(
$this->container->getNamespacePrefix(),
'FOF30\\',
);
// Get the prefixes for non-namespaced classes (FOF2 and Joomla! way)
$plainPrefixes = array('J');
// If the type is given as prefix.type add the custom type into the two prefix arrays
if (strpos($type, '.'))
{
list($prefix, $type) = explode('.', $type);
array_unshift($plainPrefixes, $prefix);
array_unshift($namespacedPrefixes, $prefix);
}
// First try to find the namespaced class
foreach ($namespacedPrefixes as $prefix)
{
$class = rtrim($prefix, '\\') . '\\Form\\' . ucfirst($entity) . '\\' . ucfirst($type);
if (class_exists($class, true))
{
return $class;
}
}
// TODO The rest of the code is legacy and will be removed in a future version
// Then try to find the non-namespaced class
$classes = array();
foreach ($plainPrefixes as $prefix)
{
$class = \JString::ucfirst($prefix, '_') . 'Form' . \JString::ucfirst($entity, '_') . \JString::ucfirst($type, '_');
if (class_exists($class, true))
{
return $class;
}
$classes[] = $class;
}
// Get the field search path array.
$reflector = new \ReflectionClass('\\JFormHelper');
$addPathMethod = $reflector->getMethod('addPath');
$addPathMethod->setAccessible(true);
$paths = $addPathMethod->invoke(null, $entity);
// If the type is complex, add the base type to the paths.
if ($pos = strpos($type, '_'))
{
// Add the complex type prefix to the paths.
for ($i = 0, $n = count($paths); $i < $n; $i++)
{
// Derive the new path.
$path = $paths[$i] . '/' . strtolower(substr($type, 0, $pos));
// If the path does not exist, add it.
if (!in_array($path, $paths))
{
$paths[] = $path;
}
}
// Break off the end of the complex type.
$type = substr($type, $pos + 1);
}
// Try to find the class file.
$type = strtolower($type) . '.php';
foreach ($paths as $path)
{
if ($file = \JPath::find($path, $type))
{
require_once $file;
foreach ($classes as $class)
{
if (class_exists($class, false))
{
return $class;
}
}
}
}
return false;
}
/**
* WARNING: THIS IS IGNORED IN FOF3!
*
* @param string $new IGNORED!
*
* @return void
*
* @deprecated 3.0
*/
public static function addFieldPath($new = null)
{
if ($new) {}; // Prevents phpStorm from freaking out about the unused $new parameter...
if (class_exists('JLog'))
{
\JLog::add(__CLASS__ . '::' . __METHOD__ . '() is deprecated since FOF 3.0 and should not be used.', \JLog::WARNING, 'deprecated');
}
}
/**
* WARNING: THIS IS IGNORED IN FOF3!
*
* @param string $new IGNORED!
*
* @return void
*
* @deprecated 3.0
*/
public static function addHeaderPath($new = null)
{
if ($new) {}; // Prevents phpStorm from freaking out about the unused $new parameter...
if (class_exists('JLog'))
{
\JLog::add(__CLASS__ . '::' . __METHOD__ . '() is deprecated since FOF 3.0 and should not be used.', \JLog::WARNING, 'deprecated');
}
}
/**
* WARNING: THIS IS IGNORED IN FOF3!
*
* @param string $new IGNORED!
*
* @return void
*
* @deprecated 3.0
*/
public static function addFormPath($new = null)
{
if ($new) {}; // Prevents phpStorm from freaking out about the unused $new parameter...
if (class_exists('JLog'))
{
\JLog::add(__CLASS__ . '::' . __METHOD__ . '() is deprecated since FOF 3.0 and should not be used.', \JLog::WARNING, 'deprecated');
}
}
/**
* WARNING: THIS IS IGNORED IN FOF3!
*
* @param string $new IGNORED!
*
* @return void
*
* @deprecated 3.0
*/
public static function addRulePath($new = null)
{
if ($new) {}; // Prevents phpStorm from freaking out about the unused $new parameter...
if (class_exists('JLog'))
{
\JLog::add(__CLASS__ . '::' . __METHOD__ . '() is deprecated since FOF 3.0 and should not be used.', \JLog::WARNING, 'deprecated');
}
}
/**
* Get a reference to the form's Container
*
* @return Container
*/
public function &getContainer()
{
return $this->container;
}
/**
* Set the form's Container
*
* @param Container $container
*/
public function setContainer($container)
{
$this->container = $container;
}
/**
* Method to bind data to the form.
*
* @param mixed $data An array or object of data to bind to the form.
*
* @return boolean True on success.
*
* @since 11.1
*/
public function bind($data)
{
$this->data = class_exists('JRegistry') ? new \JRegistry() : new Registry();
if (is_object($data) && ($data instanceof DataModel))
{
$maxDepth = (int) $this->getAttribute('relation_depth', '1');
return parent::bind($this->modelToBindSource($data, $maxDepth));
}
return parent::bind($data);
}
/**
* Method to bind data to the form for the group level.
*
* @param string $group The dot-separated form group path on which to bind the data.
* @param mixed $data An array or object of data to bind to the form for the group level.
*
* @return void
*
* @since 11.1
*/
protected function bindLevel($group, $data)
{
if (is_object($data) && ($data instanceof DataModel))
{
parent::bindLevel($group, $this->modelToBindSource($data));
return;
}
parent::bindLevel($group, $data);
}
/**
* Method to load, setup and return a JFormField object based on field data.
*
* @param string $element The XML element object representation of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
* @param mixed $value The optional value to use as the default for the field.
*
* @return mixed The JFormField object for the field or boolean false on error.
*
* @since 11.1
*/
protected function loadField($element, $group = null, $value = null)
{
// Make sure there is a valid SimpleXMLElement.
if (!($element instanceof SimpleXMLElement))
{
return false;
}
// Get the field type.
$type = $element['type'] ? (string) $element['type'] : 'text';
// Load the JFormField object for the field.
$field = $this->loadFieldType($type);
// If the object could not be loaded, get a text field object.
if ($field === false)
{
$field = $this->loadFieldType('text');
}
/*
* Get the value for the form field if not set.
* Default to the translated version of the 'default' attribute
* if 'translate_default' attribute if set to 'true' or '1'
* else the value of the 'default' attribute for the field.
*/
if ($value === null)
{
$default = (string) $element['default'];
if (($translate = $element['translate_default']) && ((string) $translate == 'true' || (string) $translate == '1'))
{
$lang = JFactory::getLanguage();
if ($lang->hasKey($default))
{
$debug = $lang->setDebug(false);
$default = JText::_($default);
$lang->setDebug($debug);
}
else
{
$default = JText::_($default);
}
}
$getValueFrom = (isset($element['name_from'])) ? (string) $element['name_from'] : (string) $element['name'];
$value = $this->getValue($getValueFrom, $group, $default);
}
// Setup the JFormField object.
$field->setForm($this);
if ($field->setup($element, $value, $group))
{
return $field;
}
else
{
return false;
}
}
/**
* Method to get a form field represented as an XML element object.
*
* @param string $name The name of the form field.
* @param string $group The optional dot-separated form group path on which to find the field.
*
* @return mixed The XML element object for the field or boolean false on error.
*
* @since 11.1
*/
protected function findField($name, $group = null)
{
$element = false;
$fields = array();
// Make sure there is a valid JForm XML document.
if (!($this->xml instanceof SimpleXMLElement))
{
return false;
}
// Let's get the appropriate field element based on the method arguments.
if ($group)
{
// Get the fields elements for a given group.
$elements = &$this->findGroup($group);
// Get all of the field elements with the correct name for the fields elements.
/** @var SimpleXMLElement $element */
foreach ($elements as $element)
{
// If there are matching field elements add them to the fields array.
if ($tmp = $element->xpath('descendant::field[@name="' . $name . '"]'))
{
$fields = array_merge($fields, $tmp);
}
elseif ($tmp = $element->xpath('descendant::field[@name_from="' . $name . '"]'))
{
$fields = array_merge($fields, $tmp);
}
}
// Make sure something was found.
if (!$fields)
{
return false;
}
// Use the first correct match in the given group.
$groupNames = explode('.', $group);
/** @var SimpleXMLElement $field */
foreach ($fields as &$field)
{
// Get the group names as strings for ancestor fields elements.
$attrs = $field->xpath('ancestor::fields[@name]/@name');
$names = array_map('strval', $attrs ? $attrs : array());
// If the field is in the exact group use it and break out of the loop.
if ($names == (array) $groupNames)
{
$element = &$field;
break;
}
}
}
else
{
// Get an array of fields with the correct name.
$fields = $this->xml->xpath('//field[@name="' . $name . '"]');
if (!$fields)
{
$fields = array();
}
$fieldsNameFrom = $this->xml->xpath('//field[@name_from="' . $name . '"]');
if ($fieldsNameFrom)
{
$fields = array_merge($fields, $fieldsNameFrom);
}
// Make sure something was found.
if (empty($fields))
{
return false;
}
// Search through the fields for the right one.
foreach ($fields as &$field)
{
// If we find an ancestor fields element with a group name then it isn't what we want.
if ($field->xpath('ancestor::fields[@name]'))
{
continue;
}
// Found it!
else
{
$element = &$field;
break;
}
}
}
return $element;
}
/**
* Converts a DataModel into data suitable for use with the form. The difference to the Model's getData() method is
* that we process hasOne and belongsTo relations. This is a recursive function which will be called at most
* $maxLevel deep. You can set this in the form XML file, in the relation_depth attribute.
*
* The $modelsProcessed array which is passed in successive recursions lets us prevent pointless Inception-style
* recursions, e.g. Model A is related to Model B is related to Model C is related to Model A. You clearly don't
* care to see a.b.c.a.b in the results. You just want a.b.c. Obviously c is indirectly related to a because that's
* where you began the recursion anyway.
*
* @param DataModel $model The item to dump its contents into an array
* @param int $maxLevel Maximum nesting level of relations to process. Default: 1.
* @param array $modelsProcessed Array of the fully qualified model class names already processed.
*
* @return array
* @throws DataModel\Relation\Exception\RelationNotFound
*/
protected function modelToBindSource(DataModel $model, $maxLevel = 1, $modelsProcessed = array())
{
$maxLevel--;
$data = $model->toArray();
$relations = $model->getRelations()->getRelationNames();
$relationTypes = $model->getRelations()->getRelationTypes();
$relationTypes = array_map(function ($x) {
return ltrim($x, '\\');
}, $relationTypes);
$relationTypes = array_flip($relationTypes);
if (is_array($relations) && count($relations) && ($maxLevel >= 0))
{
foreach ($relations as $relationName)
{
$rel = $model->getRelations()->getRelation($relationName);
$class = get_class($rel);
if (!isset($relationTypes[$class]))
{
continue;
}
if (!in_array($relationTypes[$class], array('hasOne', 'belongsTo')))
{
continue;
}
/** @var DataModel $relData */
$relData = $model->$relationName;
if (!($relData instanceof DataModel))
{
continue;
}
$modelType = get_class($relData);
if (in_array($modelType, $modelsProcessed))
{
continue;
}
$modelsProcessed[] = $modelType;
$relDataArray = $this->modelToBindSource($relData, $maxLevel, $modelsProcessed);
if (!is_array($relDataArray) || empty($relDataArray))
{
continue;
}
foreach ($relDataArray as $k => $v)
{
$data[$relationName . '.' . $k] = $v;
}
}
}
return $data;
}
}