Fixed changelog direction so newest changes is listed at top of the file. Finished the init function of super powers. Adds rest function inside super power. Adds super powers to all templates. Updates many helper class methods to now use the utility classes. Adds the method to the component entry file (as-well). Moved most methods from the compiler fields class to powers. #955 Refactored many new builder classes from the registry class. Converted the Content class to two builder classes. Adds option to add additional templates to a module. Resolves #1002 by adding STRING instead of WORD. Ported the FOF encryption class into Powers. https://git.vdm.dev/joomla/fof Changed all CSS and JS to use instead of in compiler code. Adds option to turn jQuery off if UIKIT 3 is added. Adds option to auto write injection boilerplate code in Powers area. Adds option to auto write service provider boilerplate code in the Powers area. Improved the method and all banner locations to fetch from https://git.vdm.dev/joomla/jcb-external/ instead. Major stability improvements all over the new powers complier classes. New [base Registry class](https://git.vdm.dev/joomla/super-powers/src/branch/master/src/7e822c03-1b20-41d1-9427-f5b8d5836af7) has been created specially for JCB. Remember to update all plug-ins with this version update (use the package).

This commit is contained in:
2023-10-18 09:26:30 +02:00
parent a77eac9adf
commit e99899f6f1
632 changed files with 30604 additions and 16888 deletions

View File

@@ -0,0 +1,532 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Application\CMSApplication;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentOne as Content;
use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentMulti as Contents;
use VDM\Joomla\Componentbuilder\Compiler\Builder\SiteFieldData as SiteField;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Language;
use VDM\Joomla\Componentbuilder\Compiler\Component\Placeholder as ComponentPlaceholder;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Structure;
use VDM\Joomla\Componentbuilder\Compiler\Field\InputButton;
use VDM\Joomla\Componentbuilder\Compiler\Builder\FieldGroupControl;
use VDM\Joomla\Componentbuilder\Compiler\Builder\ExtensionCustomFields;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Utilities\StringHelper;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Indent;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Placefix;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Line;
use VDM\Joomla\Utilities\String\FieldHelper;
/**
* Custom Field Type File Creator Class
*
* @since 3.2.0
*/
final class CustomFieldTypeFile
{
/**
* The Config Class.
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The ContentOne Class.
*
* @var Content
* @since 3.2.0
*/
protected Content $content;
/**
* The ContentMulti Class.
*
* @var Contents
* @since 3.2.0
*/
protected Contents $contents;
/**
* The SiteFieldData Class.
*
* @var SiteField
* @since 3.2.0
*/
protected SiteField $sitefield;
/**
* The Placeholder Class.
*
* @var Placeholder
* @since 3.2.0
*/
protected Placeholder $placeholder;
/**
* The Language Class.
*
* @var Language
* @since 3.2.0
*/
protected Language $language;
/**
* The Placeholder Class.
*
* @var ComponentPlaceholder
* @since 3.2.0
*/
protected ComponentPlaceholder $componentplaceholder;
/**
* The Structure Class.
*
* @var Structure
* @since 3.2.0
*/
protected Structure $structure;
/**
* The InputButton Class.
*
* @var InputButton
* @since 3.2.0
*/
protected InputButton $inputbutton;
/**
* The FieldGroupControl Class.
*
* @var FieldGroupControl
* @since 3.2.0
*/
protected FieldGroupControl $fieldgroupcontrol;
/**
* The ExtensionCustomFields Class.
*
* @var ExtensionCustomFields
* @since 3.2.0
*/
protected ExtensionCustomFields $extensioncustomfields;
/**
* Application object.
*
* @var CMSApplication
* @since 3.2.0
**/
protected CMSApplication $app;
/**
* Array of php fields Allowed (16)
*
* @var array
* @since 3.2.0
**/
protected array $phpFieldArray = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'x', 'HEADER'];
/**
* Constructor.
*
* @param Config $config The Config Class.
* @param Content $content The ContentOne Class.
* @param Contents $contents The ContentMulti Class.
* @param SiteField $sitefield The SiteFieldData Class.
* @param Placeholder $placeholder The Placeholder Class.
* @param Language $language The Language Class.
* @param ComponentPlaceholder $componentplaceholder The Placeholder Class.
* @param Structure $structure The Structure Class.
* @param InputButton $inputbutton The InputButton Class.
* @param FieldGroupControl $fieldgroupcontrol The FieldGroupControl Class.
* @param ExtensionCustomFields $extensioncustomfields The ExtensionCustomFields Class.
* @param CMSApplication|null $app The app object.
*
* @since 3.2.0
*/
public function __construct(Config $config, Content $content, Contents $contents,
SiteField $sitefield, Placeholder $placeholder,
Language $language,
ComponentPlaceholder $componentplaceholder,
Structure $structure, InputButton $inputbutton,
FieldGroupControl $fieldgroupcontrol,
ExtensionCustomFields $extensioncustomfields,
?CMSApplication $app = null)
{
$this->config = $config;
$this->content = $content;
$this->contents = $contents;
$this->sitefield = $sitefield;
$this->placeholder = $placeholder;
$this->language = $language;
$this->componentplaceholder = $componentplaceholder;
$this->structure = $structure;
$this->inputbutton = $inputbutton;
$this->fieldgroupcontrol = $fieldgroupcontrol;
$this->extensioncustomfields = $extensioncustomfields;
$this->app = $app ?: Factory::getApplication();
}
/**
* set Custom Field Type File
*
* @param array $data The field complete data set
* @param string $nameListCode The list view code name
* @param string $nameSingleCode The single view code name
*
* @return void
* @since 3.2.0
*/
public function set(array $data, string $nameListCode, string $nameSingleCode): void
{
// make sure it is not already been build or if it is prime
if (isset($data['custom']) && isset($data['custom']['extends'])
&& ((isset($data['custom']['prime_php']) && $data['custom']['prime_php'] == 1)
|| !$this->contents->isArray('customfield_' . $data['type']))
)
{
// set J prefix
$jprefix = 'J';
// check if this field has a dot in field type name
if (strpos((string) $data['type'], '.') !== false)
{
// so we have name spacing in custom field type name
$dotTypeArray = explode('.', (string) $data['type']);
// set the J prefix
if (count((array) $dotTypeArray) > 1)
{
$jprefix = strtoupper(array_shift($dotTypeArray));
}
// update the type name now
$data['type'] = implode('', $dotTypeArray);
$data['custom']['type'] = $data['type'];
}
// set the contents key
$contents_key = "customfield_{$data['type']}|";
// set tab and break replacements
$tabBreak = array(
'\t' => Indent::_(1),
'\n' => PHP_EOL
);
// set the [[[PLACEHOLDER]]] options
$replace = array(
Placefix::_('JPREFIX') => $jprefix,
Placefix::_('TABLE') => (isset($data['custom']['table']))
? $data['custom']['table'] : '',
Placefix::_('ID') => (isset($data['custom']['id']))
? $data['custom']['id'] : '',
Placefix::_('TEXT') => (isset($data['custom']['text']))
? $data['custom']['text'] : '',
Placefix::_('CODE_TEXT') => (isset($data['code'], $data['custom']['text']))
? $data['code'] . '_' . $data['custom']['text'] : '',
Placefix::_('CODE') => (isset($data['code']))
? $data['code'] : '',
Placefix::_('view_type') => $nameSingleCode
. '_' . $data['type'],
Placefix::_('type') => (isset($data['type']))
? $data['type'] : '',
Placefix::_('com_component') => (isset($data['custom']['component'])
&& StringHelper::check(
$data['custom']['component']
)) ? StringHelper::safe(
$data['custom']['component']
) : 'com_' . $this->config->component_code_name,
// set the generic values
Placefix::_('component') => $this->config->component_code_name,
Placefix::_('Component') => $this->content->get('Component'),
Placefix::_('view') => (isset($data['custom']['view'])
&& StringHelper::check(
$data['custom']['view']
)) ? StringHelper::safe(
$data['custom']['view']
) : $nameSingleCode,
Placefix::_('views') => (isset($data['custom']['views'])
&& StringHelper::check(
$data['custom']['views']
)) ? StringHelper::safe(
$data['custom']['views']
) : $nameListCode
);
// now set the ###PLACEHOLDER### options
foreach ($replace as $replacekey => $replacevalue)
{
// update the key value
$replacekey = str_replace(
array(Placefix::b(), Placefix::d()),
array(Placefix::h(), Placefix::h()), $replacekey
);
// now set the value
$replace[$replacekey] = $replacevalue;
}
// load the global placeholders
foreach ($this->componentplaceholder->get() as $globalPlaceholder => $gloabalValue)
{
$replace[$globalPlaceholder] = $gloabalValue;
}
// start loading the field type
// JPREFIX <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JPREFIX", $jprefix);
// Type <<<DYNAMIC>>>
$this->contents->set("{$contents_key}Type",
StringHelper::safe(
$data['custom']['type'], 'F'
)
);
// type <<<DYNAMIC>>>
$this->contents->set("{$contents_key}type", StringHelper::safe($data['custom']['type']));
// is this a own custom field
if (isset($data['custom']['own_custom']))
{
// make sure the button option notice is set to notify the developer that the button option is not available in own custom field types
if (isset($data['custom']['add_button'])
&& ($data['custom']['add_button'] === 'true'
|| 1 == $data['custom']['add_button']))
{
// set error
$this->app->enqueueMessage(
Text::_('COM_COMPONENTBUILDER_HR_HTHREEDYNAMIC_BUTTON_ERRORHTHREE'), 'Error'
);
$this->app->enqueueMessage(
Text::_('COM_COMPONENTBUILDER_THE_OPTION_TO_ADD_A_DYNAMIC_BUTTON_IS_NOT_AVAILABLE_IN_BOWN_CUSTOM_FIELD_TYPESB_YOU_WILL_HAVE_TO_CUSTOM_CODE_IT'), 'Error'
);
}
// load another file
$target = array('admin' => 'customfield');
$this->structure->build(
$target, 'fieldcustom', $data['custom']['type']
);
// get the extends name
$JFORM_extends = StringHelper::safe(
$data['custom']['extends']
);
// JFORM_TYPE_HEADER <<<DYNAMIC>>>
$add_default_header = true;
$this->contents->set("{$contents_key}JFORM_TYPE_HEADER",
"//" . Line::_(
__LINE__,__CLASS__
) . " Import the " . $JFORM_extends
. " field type classes needed"
);
// JFORM_extens <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JFORM_extends", $JFORM_extends
);
// JFORM_EXTENDS <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JFORM_EXTENDS",
StringHelper::safe(
$data['custom']['extends'], 'F'
)
);
// JFORM_TYPE_PHP <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JFORM_TYPE_PHP",
PHP_EOL . PHP_EOL . Indent::_(1) . "//" . Line::_(
__LINE__,__CLASS__
) . " A " . $data['custom']['own_custom'] . " Field"
);
// load the other PHP options
foreach ($this->phpFieldArray as $x)
{
// reset the php bucket
$phpBucket = '';
// only set if available
if (isset($data['custom']['php' . $x])
&& ArrayHelper::check(
$data['custom']['php' . $x]
))
{
foreach ($data['custom']['php' . $x] as $line => $code)
{
if (StringHelper::check($code))
{
$phpBucket .= PHP_EOL . $this->placeholder->update(
$code, $tabBreak
);
}
}
// check if this is header text
if ('HEADER' === $x)
{
$this->contents->add("{$contents_key}JFORM_TYPE_HEADER",
PHP_EOL . $this->placeholder->update(
$phpBucket, $replace
), false
);
// stop default headers from loading
$add_default_header = false;
}
else
{
// JFORM_TYPE_PHP <<<DYNAMIC>>>
$this->contents->add("{$contents_key}JFORM_TYPE_PHP",
PHP_EOL . $this->placeholder->update(
$phpBucket, $replace
), false
);
}
}
}
// check if we should add default header
if ($add_default_header)
{
$this->contents->add("{$contents_key}JFORM_TYPE_HEADER",
PHP_EOL . "jimport('joomla.form.helper');",
false
);
$this->contents->add("{$contents_key}JFORM_TYPE_HEADER",
PHP_EOL . "JFormHelper::loadFieldClass('" . $JFORM_extends . "');",
false
);
}
// check the the JFormHelper::loadFieldClass(..) was set
elseif (strpos((string) $this->contents->get("{$contents_key}JFORM_TYPE_HEADER"),
'JFormHelper::loadFieldClass(') === false)
{
$this->contents->add("{$contents_key}JFORM_TYPE_HEADER",
PHP_EOL . "JFormHelper::loadFieldClass('"
. $JFORM_extends . "');", false
);
}
}
else
{
// first build the custom field type file
$target = array('admin' => 'customfield');
$this->structure->build(
$target, 'field' . $data['custom']['extends'],
$data['custom']['type']
);
// make sure the value is reset
$phpCode = '';
// now load the php script
if (isset($data['custom']['php'])
&& ArrayHelper::check(
$data['custom']['php']
))
{
foreach ($data['custom']['php'] as $line => $code)
{
if (StringHelper::check($code))
{
if ($line == 1)
{
$phpCode .= $this->placeholder->update(
$code, $tabBreak
);
}
else
{
$phpCode .= PHP_EOL . Indent::_(2)
. $this->placeholder->update($code, $tabBreak);
}
}
}
// replace the placholders
$phpCode = $this->placeholder->update($phpCode, $replace);
}
// catch empty stuff
if (!StringHelper::check($phpCode))
{
$phpCode = 'return null;';
}
// some house cleaning for users
if ($data['custom']['extends'] === 'user')
{
// make sure the value is reset
$phpxCode = '';
// now load the php xclude script
if (ArrayHelper::check(
$data['custom']['phpx']
))
{
foreach ($data['custom']['phpx'] as $line => $code)
{
if (StringHelper::check($code))
{
if ($line == 1)
{
$phpxCode .= $this->placeholder->update(
$code, $tabBreak
);
}
else
{
$phpxCode .= PHP_EOL . Indent::_(2)
. $this->placeholder->update(
$code, $tabBreak
);
}
}
}
// replace the placholders
$phpxCode = $this->placeholder->update($phpxCode, $replace);
}
// catch empty stuff
if (!StringHelper::check($phpxCode))
{
$phpxCode = 'return null;';
}
// temp holder for name
$tempName = $data['custom']['label'] . ' Group';
// set lang
$groupLangName = $this->config->lang_prefix . '_'
. FieldHelper::safe(
$tempName, true
);
// add to lang array
$this->language->set(
$this->config->lang_target, $groupLangName,
StringHelper::safe($tempName, 'W')
);
// build the Group Control
$this->fieldgroupcontrol->set($data['type'], $groupLangName);
// JFORM_GETGROUPS_PHP <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JFORM_GETGROUPS_PHP",
$phpCode
);
// JFORM_GETEXCLUDED_PHP <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JFORM_GETEXCLUDED_PHP",
$phpxCode
);
}
else
{
// JFORM_GETOPTIONS_PHP <<<DYNAMIC>>>
$this->contents->set("{$contents_key}JFORM_GETOPTIONS_PHP",
$phpCode
);
}
// type <<<DYNAMIC>>>
$this->contents->set("{$contents_key}ADD_BUTTON",
$this->inputbutton->get($data['custom'])
);
}
}
// if this field gets used in plug-in or module we should track it so if needed we can copy it over
if ((strpos($nameSingleCode, 'pLuG!n') !== false || strpos($nameSingleCode, 'M0dUl3') !== false)
&& isset($data['custom'])
&& isset($data['custom']['type']))
{
$this->extensioncustomfields->set($data['type'], $data['custom']['type']);
}
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Creator\FieldDynamic;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Xml;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Indent;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Line;
/**
* Get any field as a string Creator Class
*
* @since 3.2.0
*/
final class FieldAsString
{
/**
* The FieldDynamic Class.
*
* @var FieldDynamic
* @since 3.2.0
*/
protected FieldDynamic $fielddynamic;
/**
* The Xml Class.
*
* @var Xml
* @since 3.2.0
*/
protected Xml $xml;
/**
* Constructor.
*
* @param FieldDynamic $fielddynamic The FieldDynamic Class.
* @param Xml $xml The Xml Class.
*
* @since 3.2.0
*/
public function __construct(FieldDynamic $fielddynamic, Xml $xml)
{
$this->fielddynamic = $fielddynamic;
$this->xml = $xml;
}
/**
* Get field as a string (no matter the build type)
*
* @param array $field The field data
* @param array $view The view data
* @param int $viewType The view type
* @param string $langView The language string of the view
* @param string $nameSingleCode The single view name
* @param string $nameListCode The list view name
* @param array $placeholders The placeholder and replace values
* @param string $dbkey The custom table key
* @param boolean $build The switch to set the build option
*
* @return string The complete field in xml-string
* @since 3.2.0
*/
public function get(array &$field, array &$view, int $viewType, string $langView,
string $nameSingleCode, string $nameListCode, array &$placeholders,
string &$dbkey, bool $build = false): string
{
// get field
$field_xml = $this->fielddynamic->get(
$field, $view, $viewType, $langView,
$nameSingleCode, $nameListCode,
$placeholders, $dbkey, $build
);
if (is_string($field_xml))
{
return $field_xml;
}
elseif (is_object($field_xml) && isset($field_xml->fieldXML))
{
return PHP_EOL . Indent::_(2) . "<!--"
. Line::_(__Line__, __Class__) . " "
. $field_xml->comment . ' -->' . PHP_EOL
. Indent::_(1) . $this->xml->pretty(
$field_xml->fieldXML, 'field'
);
}
return '';
}
}

View File

@@ -0,0 +1,302 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Field\Name;
use VDM\Joomla\Componentbuilder\Compiler\Field\TypeName;
use VDM\Joomla\Componentbuilder\Compiler\Field\Attributes;
use VDM\Joomla\Componentbuilder\Compiler\Field\Groups;
use VDM\Joomla\Componentbuilder\Compiler\Builder\FieldNames;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Creator\Fieldtypeinterface as Field;
use VDM\Joomla\Componentbuilder\Compiler\Creator\Builders;
use VDM\Joomla\Componentbuilder\Compiler\Creator\Layout;
use VDM\Joomla\Utilities\ObjectHelper;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Creator\Fielddynamicinterface;
/**
* Dynamic Field Creator Class
*
* @since 3.2.0
*/
final class FieldDynamic implements Fielddynamicinterface
{
/**
* The Name Class.
*
* @var Name
* @since 3.2.0
*/
protected Name $name;
/**
* The TypeName Class.
*
* @var TypeName
* @since 3.2.0
*/
protected TypeName $typename;
/**
* The Attributes Class.
*
* @var Attributes
* @since 3.2.0
*/
protected Attributes $attributes;
/**
* The Groups Class.
*
* @var Groups
* @since 3.2.0
*/
protected Groups $groups;
/**
* The FieldNames Class.
*
* @var FieldNames
* @since 3.2.0
*/
protected FieldNames $fieldnames;
/**
* The Fieldtypeinterface Class.
*
* @var Field
* @since 3.2.0
*/
protected Field $field;
/**
* The Builders Class.
*
* @var Builders
* @since 3.2.0
*/
protected Builders $builders;
/**
* The Layout Class.
*
* @var Layout
* @since 3.2.0
*/
protected Layout $layout;
/**
* Constructor.
*
* @param Name $name The Name Class.
* @param TypeName $typename The TypeName Class.
* @param Attributes $attributes The Attributes Class.
* @param Groups $groups The Groups Class.
* @param FieldNames $fieldnames The FieldNames Class.
* @param Field $field The Fieldtypeinterface Class.
* @param Builders $builders The Builders Class.
* @param Layout $layout The Layout Class.
*
* @since 3.2.0
*/
public function __construct(Name $name, TypeName $typename,
Attributes $attributes, Groups $groups, FieldNames $fieldnames,
Field $field, Builders $builders, Layout $layout)
{
$this->name = $name;
$this->typename = $typename;
$this->attributes = $attributes;
$this->groups = $groups;
$this->fieldnames = $fieldnames;
$this->field = $field;
$this->builders = $builders;
$this->layout = $layout;
}
/**
* Get the Dynamic field and build all it needs
*
* @param array $field The field data
* @param array $view The view data
* @param int $viewType The view type
* @param string $langView The language string of the view
* @param string $nameSingleCode The single view name
* @param string $nameListCode The list view name
* @param array $placeholders The placeholder and replace values
* @param string $dbkey The custom table key
* @param boolean $build The switch to set the build option
*
* @return mixed The complete field
* @since 3.2.0
*/
public function get(array &$field, array &$view, int &$viewType, string &$langView, string &$nameSingleCode,
string &$nameListCode, array &$placeholders, string &$dbkey, bool $build)
{
// set default return
$dynamicField = null;
// make sure we have settings
if (isset($field['settings'])
&& ObjectHelper::check($field['settings']))
{
// reset some values
$name = $this->name->get($field, $nameListCode);
$typeName = $this->typename->get($field);
$multiple = false;
$langLabel = '';
$fieldSet = '';
// set field attributes
$fieldAttributes = $this->attributes->set(
$field, $viewType, $name, $typeName, $multiple, $langLabel,
$langView, $nameListCode, $nameSingleCode, $placeholders
);
// check if values were set
if (ArrayHelper::check($fieldAttributes))
{
// set the array of field names
$this->fieldnames->set(
$nameSingleCode . '.' . $fieldAttributes['name'], $fieldAttributes['name']
);
// set options as null
$optionArray = null;
if ($this->groups->check($typeName, 'option'))
{
// set options array
$optionArray = array();
// now add to the field set
$dynamicField = $this->field->get(
'option', $fieldAttributes, $name, $typeName, $langView,
$nameSingleCode, $nameListCode, $placeholders,
$optionArray
);
if ($build)
{
// set builders
$this->builders->set(
$langLabel, $langView, $nameSingleCode,
$nameListCode, $name, $view, $field, $typeName,
$multiple, null, $optionArray
);
}
}
elseif ($this->groups->check($typeName, 'spacer'))
{
if ($build)
{
// make sure spacers gets loaded to layout
$tabName = '';
if (isset($view['settings']->tabs)
&& isset($view['settings']->tabs[(int) $field['tab']]))
{
$tabName
= $view['settings']->tabs[(int) $field['tab']];
}
elseif ((int) $field['tab'] == 15)
{
// set to publishing tab
$tabName = 'publishing';
}
$this->layout->set(
$nameSingleCode, $tabName, $name, $field
);
}
// now add to the field set
$dynamicField = $this->field->get(
'spacer', $fieldAttributes, $name, $typeName, $langView,
$nameSingleCode, $nameListCode, $placeholders,
$optionArray
);
}
elseif ($this->groups->check($typeName, 'special'))
{
// set the repeatable field or subform field
if ($typeName === 'repeatable' || $typeName === 'subform')
{
if ($build)
{
// set builders
$this->builders->set(
$langLabel, $langView, $nameSingleCode,
$nameListCode, $name, $view, $field,
$typeName, $multiple, null
);
}
// now add to the field set
$dynamicField = $this->field->get(
'special', $fieldAttributes, $name, $typeName,
$langView, $nameSingleCode, $nameListCode,
$placeholders, $optionArray
);
}
}
elseif (isset($fieldAttributes['custom'])
&& ArrayHelper::check($fieldAttributes['custom']))
{
// set the custom array
$custom = $fieldAttributes['custom'];
unset($fieldAttributes['custom']);
// set db key
$custom['db'] = $dbkey;
// increment the db key
$dbkey++;
if ($build)
{
// set builders
$this->builders->set(
$langLabel, $langView, $nameSingleCode,
$nameListCode, $name, $view, $field, $typeName,
$multiple, $custom
);
}
// now add to the field set
$dynamicField = $this->field->get(
'custom', $fieldAttributes, $name, $typeName, $langView,
$nameSingleCode, $nameListCode, $placeholders,
$optionArray, $custom
);
}
else
{
if ($build)
{
// set builders
$this->builders->set(
$langLabel, $langView, $nameSingleCode,
$nameListCode, $name, $view, $field, $typeName,
$multiple
);
}
// now add to the field set
$dynamicField = $this->field->get(
'plain', $fieldAttributes, $name, $typeName, $langView,
$nameSingleCode, $nameListCode, $placeholders,
$optionArray
);
}
}
}
return $dynamicField;
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Creator\FieldAsString;
use VDM\Joomla\Utilities\StringHelper;
use VDM\Joomla\Utilities\ArrayHelper;
/**
* Fieldset Dynamic Creator Class
*
* @since 3.2.0
*/
final class FieldsetDynamic
{
/**
* The FieldAsString Class.
*
* @var FieldAsString
* @since 3.2.0
*/
protected FieldAsString $fieldasstring;
/**
* Constructor.
*
* @param FieldAsString $fieldasstring The FieldAsString Class.
*
* @since 3.2.0
*/
public function __construct(FieldAsString $fieldasstring)
{
$this->fieldasstring = $fieldasstring;
}
/**
* build field set
*
* @param array $fields The fields data
* @param string $langView The language string of the view
* @param string $nameSingleCode The single view name
* @param string $nameListCode The list view name
* @param array $placeholders The placeholder and replace values
* @param string $dbkey The custom table key
* @param boolean $build The switch to set the build option
* @param int $return_type The return type 1 = string, 2 = array
*
* @return mixed The complete field in string or array
* @since 3.2.0
*/
public function get(array &$fields, string &$langView, string &$nameSingleCode,
string &$nameListCode, array &$placeholders, string &$dbkey, bool $build = false,
int $returnType = 1)
{
// set some defaults
$view = [];
$view_type = 0;
// build the fieldset
if ($returnType == 1)
{
$fieldset = '';
}
else
{
$fieldset = [];
}
// loop over the fields to build
if (ArrayHelper::check($fields))
{
foreach ($fields as $field)
{
// get the field
$field_xml_string = $this->fieldasstring->get(
$field, $view, $view_type, $langView,
$nameSingleCode, $nameListCode,
$placeholders, $dbkey, $build
);
// make sure the xml is set and a string
if (StringHelper::check($field_xml_string))
{
if ($returnType == 1)
{
$fieldset .= $field_xml_string;
}
else
{
$fieldset[] = $field_xml_string;
}
}
}
}
return $fieldset;
}
}

View File

@@ -0,0 +1,616 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Language\Fieldset as Language;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\EventInterface as Event;
use VDM\Joomla\Componentbuilder\Compiler\Adminview\Permission;
use VDM\Joomla\Componentbuilder\Compiler\Creator\FieldDynamic;
use VDM\Joomla\Componentbuilder\Compiler\Builder\FieldNames;
use VDM\Joomla\Componentbuilder\Compiler\Builder\AccessSwitch;
use VDM\Joomla\Componentbuilder\Compiler\Builder\MetaData;
use VDM\Joomla\Componentbuilder\Compiler\Creator\Layout;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Indent;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Line;
use VDM\Joomla\Utilities\StringHelper;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Creator\Fieldsetinterface;
/**
* Fieldset String Creator Class
*
* @since 3.2.0
*/
final class FieldsetString implements Fieldsetinterface
{
/**
* The Config Class.
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The Placeholder Class.
*
* @var Placeholder
* @since 3.2.0
*/
protected Placeholder $placeholder;
/**
* The Fieldset Class.
*
* @var Language
* @since 3.2.0
*/
protected Language $language;
/**
* The EventInterface Class.
*
* @var Event
* @since 3.2.0
*/
protected Event $event;
/**
* The Permission Class.
*
* @var Permission
* @since 3.2.0
*/
protected Permission $permission;
/**
* The FieldDynamic Class.
*
* @var FieldDynamic
* @since 3.2.0
*/
protected FieldDynamic $fielddynamic;
/**
* The FieldNames Class.
*
* @var FieldNames
* @since 3.2.0
*/
protected FieldNames $fieldnames;
/**
* The AccessSwitch Class.
*
* @var AccessSwitch
* @since 3.2.0
*/
protected AccessSwitch $accessswitch;
/**
* The MetaData Class.
*
* @var MetaData
* @since 3.2.0
*/
protected MetaData $metadata;
/**
* The Layout Class.
*
* @var Layout
* @since 3.2.0
*/
protected Layout $layout;
/**
* The Counter Class.
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* Constructor.
*
* @param Config $config The Config Class.
* @param Placeholder $placeholder The Placeholder Class.
* @param Language $language The Fieldset Class.
* @param Event $event The EventInterface Class.
* @param Permission $permission The Permission Class.
* @param FieldDynamic $fielddynamic The FieldDynamic Class.
* @param FieldNames $fieldnames The FieldNames Class.
* @param AccessSwitch $accessswitch The AccessSwitch Class.
* @param MetaData $metadata The MetaData Class.
* @param Layout $layout The Layout Class.
* @param Counter $counter The Counter Class.
*
* @since 3.2.0
*/
public function __construct(Config $config, Placeholder $placeholder,
Language $language, Event $event, Permission $permission,
FieldDynamic $fielddynamic, FieldNames $fieldnames,
AccessSwitch $accessswitch, MetaData $metadata,
Layout $layout, Counter $counter)
{
$this->config = $config;
$this->placeholder = $placeholder;
$this->language = $language;
$this->event = $event;
$this->permission = $permission;
$this->fielddynamic = $fielddynamic;
$this->fieldnames = $fieldnames;
$this->accessswitch = $accessswitch;
$this->metadata = $metadata;
$this->layout = $layout;
$this->counter = $counter;
}
/**
* Get a fieldset
*
* @param array $view The view data
* @param string $component The component name
* @param string $nameSingleCode The single view name
* @param string $nameListCode The list view name
*
* @return string The fields set as a string or empty string if no field found.
* @since 3.2.0
*/
public function get(array $view, string $component, string $nameSingleCode,
string $nameListCode): string
{
// setup the fieldset language values of this view
if (!isset($view['settings']->fields)
|| !ArrayHelper::check($view['settings']->fields))
{
return '';
}
// add metadata to the view
$metadata = false;
if (isset($view['metadata']) && $view['metadata'])
{
$metadata = true;
}
// add access to the view
$access = false;
if (isset($view['access']) && $view['access'])
{
$access = true;
}
// main lang prefix
$lang_view = $this->config->lang_prefix . '_'
. $this->placeholder->get('VIEW');
$lang_views = $this->config->lang_prefix . '_'
. $this->placeholder->get('VIEWS');
$name_single = $view['settings']->name_single ?? 'Error';
$name_list = $view['settings']->name_list ?? 'Error';
$lang_target = $this->config->lang_target ?? 'both';
// load the language values
$this->language->set(
$access,
$metadata,
$lang_target,
$lang_view,
$lang_views,
$name_single,
$name_list,
$nameSingleCode,
$nameListCode
);
// set the read only
$read_only = false;
if ($view['settings']->type == 2)
{
$read_only = Indent::_(3) . 'readonly="true"' . PHP_EOL . Indent::_(
3
) . 'disabled="true"';
}
// start adding dynamic fields
$dynamic_fields = '';
// set the custom table key
$dbkey = 'g';
// for plugin event TODO change event api signatures
$placeholders = $this->placeholder->active;
$component_context = $this->config->component_context;
// Trigger Event: jcb_ce_onBeforeBuildFields
$this->event->trigger(
'jcb_ce_onBeforeBuildFields',
array(&$component_context, &$dynamic_fields, &$read_only,
&$dbkey, &$view, &$component, &$nameSingleCode,
&$nameListCode, &$placeholders, &$lang_view,
&$lang_views)
);
unset($placeholders);
// TODO we should add the global and local view switch if field for front end
foreach ($view['settings']->fields as $field)
{
$dynamic_fields .= $this->fielddynamic->get(
$field, $view, $view['settings']->type, $lang_view,
$nameSingleCode, $nameListCode, $this->placeholder->active, $dbkey,
true
);
}
// for plugin event TODO change event api signatures
$placeholders = $this->placeholder->active;
// Trigger Event: jcb_ce_onAfterBuildFields
$this->event->trigger(
'jcb_ce_onAfterBuildFields',
array(&$component_context, &$dynamic_fields, &$read_only,
&$dbkey, &$view, &$component, &$nameSingleCode,
&$nameListCode, &$placeholders, &$lang_view,
&$lang_views)
);
unset($placeholders);
// set the default fields
$field_set = array();
$field_set[] = '<fieldset name="details">';
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Default Fields. -->";
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Id Field. Type: Text (joomla) -->";
// if id is not set
if (!$this->fieldnames->isString($nameSingleCode . '.id'))
{
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . "name=" . '"id"';
$field_set[] = Indent::_(3)
. 'type="text" class="readonly" label="JGLOBAL_FIELD_ID_LABEL"';
$field_set[] = Indent::_(3)
. 'description ="JGLOBAL_FIELD_ID_DESC" size="10" default="0"';
$field_set[] = Indent::_(3) . 'readonly="true"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// if created is not set
if (!$this->fieldnames->isString($nameSingleCode . '.created'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Date Created Field. Type: Calendar (joomla) -->";
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . "name=" . '"created"';
$field_set[] = Indent::_(3) . "type=" . '"calendar"';
$field_set[] = Indent::_(3) . "label=" . '"' . $lang_view
. '_CREATED_DATE_LABEL"';
$field_set[] = Indent::_(3) . "description=" . '"' . $lang_view
. '_CREATED_DATE_DESC"';
$field_set[] = Indent::_(3) . "size=" . '"22"';
if ($read_only)
{
$field_set[] = $read_only;
}
$field_set[] = Indent::_(3) . "format=" . '"%Y-%m-%d %H:%M:%S"';
$field_set[] = Indent::_(3) . "filter=" . '"user_utc"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// if created_by is not set
if (!$this->fieldnames->isString($nameSingleCode . '.created_by'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " User Created Field. Type: User (joomla) -->";
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . "name=" . '"created_by"';
$field_set[] = Indent::_(3) . "type=" . '"user"';
$field_set[] = Indent::_(3) . "label=" . '"' . $lang_view
. '_CREATED_BY_LABEL"';
if ($read_only)
{
$field_set[] = $read_only;
}
$field_set[] = Indent::_(3) . "description=" . '"' . $lang_view
. '_CREATED_BY_DESC"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// if published is not set
if (!$this->fieldnames->isString($nameSingleCode . '.published'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Published Field. Type: List (joomla) -->";
$field_set[] = Indent::_(2) . "<field name="
. '"published" type="list" label="JSTATUS"';
$field_set[] = Indent::_(3) . "description="
. '"JFIELD_PUBLISHED_DESC" class="chzn-color-state"';
if ($read_only)
{
$field_set[] = $read_only;
}
$field_set[] = Indent::_(3) . "filter="
. '"intval" size="1" default="1" >';
$field_set[] = Indent::_(3) . "<option value=" . '"1">';
$field_set[] = Indent::_(4) . "JPUBLISHED</option>";
$field_set[] = Indent::_(3) . "<option value=" . '"0">';
$field_set[] = Indent::_(4) . "JUNPUBLISHED</option>";
$field_set[] = Indent::_(3) . "<option value=" . '"2">';
$field_set[] = Indent::_(4) . "JARCHIVED</option>";
$field_set[] = Indent::_(3) . "<option value=" . '"-2">';
$field_set[] = Indent::_(4) . "JTRASHED</option>";
$field_set[] = Indent::_(2) . "</field>";
// count the static field created
$this->counter->field++;
}
// if modified is not set
if (!$this->fieldnames->isString($nameSingleCode . '.modified'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Date Modified Field. Type: Calendar (joomla) -->";
$field_set[] = Indent::_(2)
. '<field name="modified" type="calendar" class="readonly"';
$field_set[] = Indent::_(3) . 'label="' . $lang_view
. '_MODIFIED_DATE_LABEL" description="' . $lang_view
. '_MODIFIED_DATE_DESC"';
$field_set[] = Indent::_(3)
. 'size="22" readonly="true" format="%Y-%m-%d %H:%M:%S" filter="user_utc" />';
// count the static field created
$this->counter->field++;
}
// if modified_by is not set
if (!$this->fieldnames->isString($nameSingleCode . '.modified_by'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " User Modified Field. Type: User (joomla) -->";
$field_set[] = Indent::_(2)
. '<field name="modified_by" type="user"';
$field_set[] = Indent::_(3) . 'label="' . $lang_view
. '_MODIFIED_BY_LABEL"';
$field_set[] = Indent::_(3) . "description=" . '"' . $lang_view
. '_MODIFIED_BY_DESC"';
$field_set[] = Indent::_(3) . 'class="readonly"';
$field_set[] = Indent::_(3) . 'readonly="true"';
$field_set[] = Indent::_(3) . 'filter="unset"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// check if view has access
if ($this->accessswitch->exists($nameSingleCode)
&& !$this->fieldnames->isString($nameSingleCode . '.access'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Access Field. Type: Accesslevel (joomla) -->";
$field_set[] = Indent::_(2) . '<field name="access"';
$field_set[] = Indent::_(3) . 'type="accesslevel"';
$field_set[] = Indent::_(3) . 'label="JFIELD_ACCESS_LABEL"';
$field_set[] = Indent::_(3) . 'description="JFIELD_ACCESS_DESC"';
$field_set[] = Indent::_(3) . 'default="1"';
if ($read_only)
{
$field_set[] = $read_only;
}
$field_set[] = Indent::_(3) . 'required="false"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// if ordering is not set
if (!$this->fieldnames->isString($nameSingleCode . '.ordering'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Ordering Field. Type: Numbers (joomla) -->";
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . 'name="ordering"';
$field_set[] = Indent::_(3) . 'type="number"';
$field_set[] = Indent::_(3) . 'class="inputbox validate-ordering"';
$field_set[] = Indent::_(3) . 'label="' . $lang_view
. '_ORDERING_LABEL' . '"';
$field_set[] = Indent::_(3) . 'description=""';
$field_set[] = Indent::_(3) . 'default="0"';
$field_set[] = Indent::_(3) . 'size="6"';
if ($read_only)
{
$field_set[] = $read_only;
}
$field_set[] = Indent::_(3) . 'required="false"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// if version is not set
if (!$this->fieldnames->isString($nameSingleCode . '.version'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Version Field. Type: Text (joomla) -->";
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . 'name="version"';
$field_set[] = Indent::_(3) . 'type="text"';
$field_set[] = Indent::_(3) . 'class="readonly"';
$field_set[] = Indent::_(3) . 'label="' . $lang_view
. '_VERSION_LABEL"';
$field_set[] = Indent::_(3) . 'description="' . $lang_view
. '_VERSION_DESC"';
$field_set[] = Indent::_(3) . 'size="6"';
$field_set[] = Indent::_(3) . 'readonly="true"';
$field_set[] = Indent::_(3) . 'filter="unset"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// check if metadata is added to this view
if ($this->metadata->isString($nameSingleCode))
{
// metakey
if (!$this->fieldnames->isString($nameSingleCode . '.metakey'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Metakey Field. Type: Textarea (joomla) -->";
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . 'name="metakey"';
$field_set[] = Indent::_(3) . 'type="textarea"';
$field_set[] = Indent::_(3)
. 'label="JFIELD_META_KEYWORDS_LABEL"';
$field_set[] = Indent::_(3)
. 'description="JFIELD_META_KEYWORDS_DESC"';
$field_set[] = Indent::_(3) . 'rows="3"';
$field_set[] = Indent::_(3) . 'cols="30"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
// metadesc
if (!$this->fieldnames->isString($nameSingleCode . '.metadesc'))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Metadesc Field. Type: Textarea (joomla) -->";
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . 'name="metadesc"';
$field_set[] = Indent::_(3) . 'type="textarea"';
$field_set[] = Indent::_(3)
. 'label="JFIELD_META_DESCRIPTION_LABEL"';
$field_set[] = Indent::_(3)
. 'description="JFIELD_META_DESCRIPTION_DESC"';
$field_set[] = Indent::_(3) . 'rows="3"';
$field_set[] = Indent::_(3) . 'cols="30"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
}
}
// fix the permissions field "title" issue gh-629
// check if the title is not already set
if (!$this->fieldnames->isString($nameSingleCode . '.title')
&& $this->permission->check($view, $nameSingleCode))
{
// set the field/tab name
$field_name = "title";
$tab_name = "publishing";
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Was added due to Permissions JS needing a Title field -->";
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Let us know at gh-629 should this change -->";
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " https://github.com/vdm-io/Joomla-Component-Builder/issues/629#issuecomment-750117235 -->";
// at this point we know that we must add a hidden title field
// and make sure it does not get stored to the database
$field_set[] = Indent::_(2) . "<field";
$field_set[] = Indent::_(3) . "name=" . '"' . $field_name . '"';
$field_set[] = Indent::_(3)
. 'type="hidden"';
$field_set[] = Indent::_(3) . 'default="' . $component . ' '
. $nameSingleCode . '"';
$field_set[] = Indent::_(2) . "/>";
// count the static field created
$this->counter->field++;
// setup needed field values for layout
$field_array = array();
$field_array['order_edit'] = 0;
$field_array['tab'] = 15;
$field_array['alignment'] = 1;
// make sure it gets added to view
$this->layout->set(
$nameSingleCode, $tab_name, $field_name, $field_array
);
}
// load the dynamic fields now
if (StringHelper::check($dynamic_fields))
{
$field_set[] = Indent::_(2) . "<!--" . Line::_(__Line__, __Class__)
. " Dynamic Fields. -->" . $dynamic_fields;
}
// close fieldset
$field_set[] = Indent::_(1) . "</fieldset>";
// check if metadata is added to this view
if ($this->metadata->isString($nameSingleCode))
{
if (!$this->fieldnames->isString($nameSingleCode . '.robots')
|| !$this->fieldnames->isString($nameSingleCode . '.rights')
|| !$this->fieldnames->isString($nameSingleCode . '.author'))
{
$field_set[] = PHP_EOL . Indent::_(1) . "<!--" . Line::_(
__LINE__,__CLASS__
) . " Metadata Fields. -->";
$field_set[] = Indent::_(1) . "<fields"
. ' name="metadata" label="JGLOBAL_FIELDSET_METADATA_OPTIONS">';
$field_set[] = Indent::_(2) . '<fieldset name="vdmmetadata"';
$field_set[] = Indent::_(3)
. 'label="JGLOBAL_FIELDSET_METADATA_OPTIONS">';
// robots
if (!$this->fieldnames->isString($nameSingleCode . '.robots'))
{
$field_set[] = Indent::_(3) . "<!--" . Line::_(
__LINE__,__CLASS__
) . " Robots Field. Type: List (joomla) -->";
$field_set[] = Indent::_(3) . '<field name="robots"';
$field_set[] = Indent::_(4) . 'type="list"';
$field_set[] = Indent::_(4)
. 'label="JFIELD_METADATA_ROBOTS_LABEL"';
$field_set[] = Indent::_(4)
. 'description="JFIELD_METADATA_ROBOTS_DESC" >';
$field_set[] = Indent::_(4)
. '<option value="">JGLOBAL_USE_GLOBAL</option>';
$field_set[] = Indent::_(4)
. '<option value="index, follow">JGLOBAL_INDEX_FOLLOW</option>';
$field_set[] = Indent::_(4)
. '<option value="noindex, follow">JGLOBAL_NOINDEX_FOLLOW</option>';
$field_set[] = Indent::_(4)
. '<option value="index, nofollow">JGLOBAL_INDEX_NOFOLLOW</option>';
$field_set[] = Indent::_(4)
. '<option value="noindex, nofollow">JGLOBAL_NOINDEX_NOFOLLOW</option>';
$field_set[] = Indent::_(3) . '</field>';
// count the static field created
$this->counter->field++;
}
// author
if (!$this->fieldnames->isString($nameSingleCode . '.author'))
{
$field_set[] = Indent::_(3) . "<!--" . Line::_(
__LINE__,__CLASS__
) . " Author Field. Type: Text (joomla) -->";
$field_set[] = Indent::_(3) . '<field name="author"';
$field_set[] = Indent::_(4) . 'type="text"';
$field_set[] = Indent::_(4)
. 'label="JAUTHOR" description="JFIELD_METADATA_AUTHOR_DESC"';
$field_set[] = Indent::_(4) . 'size="20"';
$field_set[] = Indent::_(3) . "/>";
// count the static field created
$this->counter->field++;
}
// rights
if (!$this->fieldnames->isString($nameSingleCode . '.rights'))
{
$field_set[] = Indent::_(3) . "<!--" . Line::_(
__LINE__,__CLASS__
) . " Rights Field. Type: Textarea (joomla) -->";
$field_set[] = Indent::_(3)
. '<field name="rights" type="textarea" label="JFIELD_META_RIGHTS_LABEL"';
$field_set[] = Indent::_(4)
. 'description="JFIELD_META_RIGHTS_DESC" required="false" filter="string"';
$field_set[] = Indent::_(4) . 'cols="30" rows="2"';
$field_set[] = Indent::_(3) . "/>";
// count the static field created
$this->counter->field++;
}
$field_set[] = Indent::_(2) . "</fieldset>";
$field_set[] = Indent::_(1) . "</fields>";
}
}
// return the set
return implode(PHP_EOL, $field_set);
}
}

View File

@@ -0,0 +1,680 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
use VDM\Joomla\Componentbuilder\Compiler\Language\Fieldset as Language;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\EventInterface as Event;
use VDM\Joomla\Componentbuilder\Compiler\Adminview\Permission;
use VDM\Joomla\Componentbuilder\Compiler\Creator\FieldDynamic;
use VDM\Joomla\Componentbuilder\Compiler\Builder\FieldNames;
use VDM\Joomla\Componentbuilder\Compiler\Builder\AccessSwitch;
use VDM\Joomla\Componentbuilder\Compiler\Builder\MetaData;
use VDM\Joomla\Componentbuilder\Compiler\Creator\Layout;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Xml;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Line;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Creator\Fieldsetinterface;
/**
* Fieldset XML Creator Class
*
* @since 3.2.0
*/
final class FieldsetXML implements Fieldsetinterface
{
/**
* The Config Class.
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The Placeholder Class.
*
* @var Placeholder
* @since 3.2.0
*/
protected Placeholder $placeholder;
/**
* The Fieldset Class.
*
* @var Language
* @since 3.2.0
*/
protected Language $language;
/**
* The EventInterface Class.
*
* @var Event
* @since 3.2.0
*/
protected Event $event;
/**
* The Permission Class.
*
* @var Permission
* @since 3.2.0
*/
protected Permission $permission;
/**
* The FieldDynamic Class.
*
* @var FieldDynamic
* @since 3.2.0
*/
protected FieldDynamic $fielddynamic;
/**
* The FieldNames Class.
*
* @var FieldNames
* @since 3.2.0
*/
protected FieldNames $fieldnames;
/**
* The AccessSwitch Class.
*
* @var AccessSwitch
* @since 3.2.0
*/
protected AccessSwitch $accessswitch;
/**
* The MetaData Class.
*
* @var MetaData
* @since 3.2.0
*/
protected MetaData $metadata;
/**
* The Layout Class.
*
* @var Layout
* @since 3.2.0
*/
protected Layout $layout;
/**
* The Counter Class.
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* The Xml Class.
*
* @var Xml
* @since 3.2.0
*/
protected Xml $xml;
/**
* Constructor.
*
* @param Config $config The Config Class.
* @param Placeholder $placeholder The Placeholder Class.
* @param Language $language The Fieldset Class.
* @param Event $event The EventInterface Class.
* @param Permission $permission The Permission Class.
* @param FieldDynamic $fielddynamic The FieldDynamic Class.
* @param FieldNames $fieldnames The FieldNames Class.
* @param AccessSwitch $accessswitch The AccessSwitch Class.
* @param MetaData $metadata The MetaData Class.
* @param Layout $layout The Layout Class.
* @param Counter $counter The Counter Class.
* @param Xml $xml The Xml Class.
*
* @since 3.2.0
*/
public function __construct(Config $config, Placeholder $placeholder,
Language $language, Event $event, Permission $permission,
FieldDynamic $fielddynamic, FieldNames $fieldnames,
AccessSwitch $accessswitch, MetaData $metadata,
Layout $layout, Counter $counter, Xml $xml)
{
$this->config = $config;
$this->placeholder = $placeholder;
$this->language = $language;
$this->event = $event;
$this->permission = $permission;
$this->fielddynamic = $fielddynamic;
$this->fieldnames = $fieldnames;
$this->accessswitch = $accessswitch;
$this->metadata = $metadata;
$this->layout = $layout;
$this->counter = $counter;
$this->xml = $xml;
}
/**
* Get a fieldset
*
* @param array $view The view data
* @param string $component The component name
* @param string $nameSingleCode The single view name
* @param string $nameListCode The list view name
*
* @return string The fields set as a string or empty string if no field found.
* @since 3.2.0
*/
public function get(array $view, string $component, string $nameSingleCode,
string $nameListCode): string
{
// setup the fieldset language values of this view
if (!isset($view['settings']->fields)
|| !ArrayHelper::check($view['settings']->fields))
{
return '';
}
// add metadata to the view
$metadata = false;
if (isset($view['metadata']) && $view['metadata'])
{
$metadata = true;
}
// add access to the view
$access = false;
if (isset($view['access']) && $view['access'])
{
$access = true;
}
// main lang prefix
$lang_view = $this->config->lang_prefix . '_'
. $this->placeholder->get('VIEW');
$lang_views = $this->config->lang_prefix . '_'
. $this->placeholder->get('VIEWS');
$name_single = $view['settings']->name_single ?? 'Error';
$name_list = $view['settings']->name_list ?? 'Error';
$lang_target = $this->config->lang_target ?? 'both';
// load the language values
$this->language->set(
$access,
$metadata,
$lang_target,
$lang_view,
$lang_views,
$name_single,
$name_list,
$nameSingleCode,
$nameListCode
);
// set the read only
$read_only_xml = [];
if ($view['settings']->type == 2)
{
$read_only_xml['readonly'] = true;
$read_only_xml['disabled'] = true;
}
// start adding dynamc fields
$dynamic_fields_xml = [];
// set the custom table key
$dbkey = 'g';
// for plugin event TODO change event api signatures
$placeholders = $this->placeholder->active;
$component_context = $this->config->component_context;
// Trigger Event: jcb_ce_onBeforeBuildFields
$this->event->trigger(
'jcb_ce_onBeforeBuildFields',
array(&$component_context, &$dynamic_fields_xml, &$read_only_xml,
&$dbkey, &$view, &$component, &$nameSingleCode,
&$nameListCode, &$placeholders, &$lang_view,
&$lang_views)
);
unset($placeholders);
// TODO we should add the global and local view switch if field for front end
foreach ($view['settings']->fields as $field)
{
$dynamic_fields_xml[] = $this->fielddynamic->get(
$field, $view, $view['settings']->type, $lang_view,
$nameSingleCode, $nameListCode, $this->placeholder->active, $dbkey,
true
);
}
// for plugin event TODO change event api signatures
$placeholders = $this->placeholder->active;
// Trigger Event: jcb_ce_onAfterBuildFields
$this->event->trigger(
'jcb_ce_onAfterBuildFields',
array(&$component_context, &$dynamic_fields_xml, &$read_only_xml,
&$dbkey, &$view, &$component, &$nameSingleCode,
&$nameListCode, &$placeholders, &$lang_view,
&$lang_views)
);
unset($placeholders);
// set the default fields
$main_xml = new \simpleXMLElement('<a/>');
$field_set_xml = $main_xml->addChild('fieldset');
$field_set_xml->addAttribute('name', 'details');
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__) . " Default Fields."
);
$this->xml->comment(
$field_set_xml,
Line::_(__Line__, __Class__) . " Id Field. Type: Text (joomla)"
);
// if id is not set
if (!$this->fieldnames->isString($nameSingleCode . '.id'))
{
$attributes = [
'name' => 'id',
'type' => 'text',
'class' => 'readonly',
'readonly' => "true",
'label' => 'JGLOBAL_FIELD_ID_LABEL',
'description' => 'JGLOBAL_FIELD_ID_DESC',
'size' => 10,
'default' => 0
];
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// if created is not set
if (!$this->fieldnames->isString($nameSingleCode . '.created'))
{
$attributes = [
'name' => 'created',
'type' => 'calendar',
'label' => $lang_view . '_CREATED_DATE_LABEL',
'description' => $lang_view . '_CREATED_DATE_DESC',
'size' => 22,
'format' => '%Y-%m-%d %H:%M:%S',
'filter' => 'user_utc'
];
$attributes = array_merge($attributes, $read_only_xml);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Date Created Field. Type: Calendar (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// if created_by is not set
if (!$this->fieldnames->isString($nameSingleCode . '.created_by'))
{
$attributes = [
'name' => 'created_by',
'type' => 'user',
'label' => $lang_view . '_CREATED_BY_LABEL',
'description' => $lang_view . '_CREATED_BY_DESC',
];
$attributes = array_merge($attributes, $read_only_xml);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " User Created Field. Type: User (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// if published is not set
if (!$this->fieldnames->isString($nameSingleCode . '.published'))
{
$attributes = [
'name' => 'published',
'type' => 'list',
'label' => 'JSTATUS'
];
$attributes = array_merge($attributes, $read_only_xml);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Published Field. Type: List (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
foreach (['JPUBLISHED' => 1, 'JUNPUBLISHED' => 0,
'JARCHIVED' => 2, 'JTRASHED' => -2] as $text => $value
)
{
$optionXML = $field_xml->addChild('option');
$optionXML->addAttribute('value', $value);
$optionXML[] = $text;
}
}
// if modified is not set
if (!$this->fieldnames->isString($nameSingleCode . '.modified'))
{
$attributes = [
'name' => 'modified',
'type' => 'calendar',
'class' => 'readonly',
'label' => $lang_view . '_MODIFIED_DATE_LABEL',
'description' => $lang_view . '_MODIFIED_DATE_DESC',
'size' => 22,
'readonly' => "true",
'format' => '%Y-%m-%d %H:%M:%S',
'filter' => 'user_utc'
];
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Date Modified Field. Type: Calendar (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// if modified_by is not set
if (!$this->fieldnames->isString($nameSingleCode . '.modified_by'))
{
$attributes = [
'name' => 'modified_by',
'type' => 'user',
'label' => $lang_view . '_MODIFIED_BY_LABEL',
'description' => $lang_view . '_MODIFIED_BY_DESC',
'class' => 'readonly',
'readonly' => 'true',
'filter' => 'unset'
];
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " User Modified Field. Type: User (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// check if view has access
if ($this->accessswitch->exists($nameSingleCode)
&& !$this->fieldnames->isString($nameSingleCode . '.access'))
{
$attributes = [
'name' => 'access',
'type' => 'accesslevel',
'label' => 'JFIELD_ACCESS_LABEL',
'description' => 'JFIELD_ACCESS_DESC',
'default' => 1,
'required' => "false"
];
$attributes = array_merge($attributes, $read_only_xml);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Access Field. Type: Accesslevel (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// if ordering is not set
if (!$this->fieldnames->isString($nameSingleCode . '.ordering'))
{
$attributes = [
'name' => 'ordering',
'type' => 'number',
'class' => 'inputbox validate-ordering',
'label' => $lang_view . '_ORDERING_LABEL',
'description' => '',
'default' => 0,
'size' => 6,
'required' => "false"
];
$attributes = array_merge($attributes, $read_only_xml);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Ordering Field. Type: Numbers (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// if version is not set
if (!$this->fieldnames->isString($nameSingleCode . '.version'))
{
$attributes = [
'name' => 'version',
'type' => 'text',
'class' => 'readonly',
'label' => $lang_view . '_VERSION_LABEL',
'description' => $lang_view . '_VERSION_DESC',
'size' => 6,
'readonly' => "true",
'filter' => 'unset'
];
$this->xml->comment(
$field_set_xml,
Line::_(__Line__, __Class__) . " Version Field. Type: Text (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
}
// check if metadata is added to this view
if ($this->metadata->isString($nameSingleCode))
{
// metakey
if (!$this->fieldnames->isString($nameSingleCode . '.metakey'))
{
$attributes = [
'name' => 'metakey',
'type' => 'textarea',
'label' => 'JFIELD_META_KEYWORDS_LABEL',
'description' => 'JFIELD_META_KEYWORDS_DESC',
'rows' => 3,
'cols' => 30
];
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Metakey Field. Type: Textarea (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes(
$field_xml, $attributes
);
// count the static field created
$this->counter->field++;
}
// metadesc
if (!$this->fieldnames->isString($nameSingleCode . '.metadesc'))
{
$attributes['name'] = 'metadesc';
$attributes['label'] = 'JFIELD_META_DESCRIPTION_LABEL';
$attributes['description'] = 'JFIELD_META_DESCRIPTION_DESC';
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Metadesc Field. Type: Textarea (joomla)"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes(
$field_xml, $attributes
);
// count the static field created
$this->counter->field++;
}
}
// fix the permissions field "title" issue gh-629
// check if the title is not already set
if (!$this->fieldnames->isString($nameSingleCode . '.title')
&& $this->permission->check($view, $nameSingleCode))
{
// set the field/tab name
$field_name = "title";
$tab_name = "publishing";
$attributes = [
'name' => $field_name,
'type' => 'hidden',
'default' => $component . ' ' . $nameSingleCode
];
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Was added due to Permissions JS needing a Title field"
);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " Let us know at gh-629 should this change"
);
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__)
. " https://github.com/vdm-io/Joomla-Component-Builder/issues/629#issuecomment-750117235"
);
$field_xml = $field_set_xml->addChild('field');
$this->xml->attributes($field_xml, $attributes);
// count the static field created
$this->counter->field++;
// setup needed field values for layout
$field_array = [];
$field_array['order_edit'] = 0;
$field_array['tab'] = 15;
$field_array['alignment'] = 1;
// make sure it gets added to view
$this->layout->set(
$nameSingleCode, $tab_name, $field_name, $field_array
);
}
// load the dynamic fields now
if (count((array) $dynamic_fields_xml))
{
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__) . " Dynamic Fields."
);
foreach ($dynamic_fields_xml as $dynamicfield)
{
$this->xml->append($field_set_xml, $dynamicfield);
}
}
// check if metadata is added to this view
if ($this->metadata->isString($nameSingleCode))
{
if (!$this->fieldnames->isString($nameSingleCode . '.robots')
|| !$this->fieldnames->isString($nameSingleCode . '.author')
|| !$this->fieldnames->isString($nameSingleCode . '.rights'))
{
$this->xml->comment(
$field_set_xml, Line::_(__Line__, __Class__) . " Metadata Fields"
);
$fields_xml = $field_set_xml->addChild('fields');
$fields_xml->addAttribute('name', 'metadata');
$fields_xml->addAttribute(
'label', 'JGLOBAL_FIELDSET_METADATA_OPTIONS'
);
$fields_field_set_xml = $fields_xml->addChild('fieldset');
$fields_field_set_xml->addAttribute('name', 'vdmmetadata');
$fields_field_set_xml->addAttribute(
'label', 'JGLOBAL_FIELDSET_METADATA_OPTIONS'
);
// robots
if (!$this->fieldnames->isString($nameSingleCode . '.robots'))
{
$this->xml->comment(
$fields_field_set_xml, Line::_(__Line__, __Class__)
. " Robots Field. Type: List (joomla)"
);
$robots = $fields_field_set_xml->addChild('field');
$attributes = [
'name' => 'robots',
'type' => 'list',
'label' => 'JFIELD_METADATA_ROBOTS_LABEL',
'description' => 'JFIELD_METADATA_ROBOTS_DESC'
];
$this->xml->attributes(
$robots, $attributes
);
// count the static field created
$this->counter->field++;
$options = [
'JGLOBAL_USE_GLOBAL' => '',
'JGLOBAL_INDEX_FOLLOW' => 'index, follow',
'JGLOBAL_NOINDEX_FOLLOW' => 'noindex, follow',
'JGLOBAL_INDEX_NOFOLLOW' => 'index, nofollow',
'JGLOBAL_NOINDEX_NOFOLLOW' => 'noindex, nofollow',
];
foreach ($options as $text => $value)
{
$option = $robots->addChild('option');
$option->addAttribute('value', $value);
$option[] = $text;
}
}
// author
if (!$this->fieldnames->isString($nameSingleCode . '.author'))
{
$this->xml->comment(
$fields_field_set_xml, Line::_(__Line__, __Class__)
. " Author Field. Type: Text (joomla)"
);
$author = $fields_field_set_xml->addChild('field');
$attributes = [
'name' => 'author',
'type' => 'text',
'label' => 'JAUTHOR',
'description' => 'JFIELD_METADATA_AUTHOR_DESC',
'size' => 20
];
$this->xml->attributes(
$author, $attributes
);
// count the static field created
$this->counter->field++;
}
// rights
if (!$this->fieldnames->isString($nameSingleCode . '.rights'))
{
$this->xml->comment(
$fields_field_set_xml, Line::_(__Line__, __Class__)
. " Rights Field. Type: Textarea (joomla)"
);
$rights = $fields_field_set_xml->addChild('field');
$attributes = [
'name' => 'rights',
'type' => 'textarea',
'label' => 'JFIELD_META_RIGHTS_LABEL',
'description' => 'JFIELD_META_RIGHTS_DESC',
'required' => 'false',
'filter' => 'string',
'cols' => 30,
'rows' => 2
];
$this->xml->attributes(
$rights, $attributes
);
// count the static field created
$this->counter->field++;
}
}
}
// return the set
return $this->xml->pretty($main_xml, 'fieldset');
}
}

View File

@@ -0,0 +1,218 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Builder\OrderZero;
use VDM\Joomla\Componentbuilder\Compiler\Builder\TabCounter;
use VDM\Joomla\Componentbuilder\Compiler\Builder\Layout as BuilderLayout;
use VDM\Joomla\Componentbuilder\Compiler\Builder\MovedPublishingFields;
use VDM\Joomla\Componentbuilder\Compiler\Builder\NewPublishingFields;
use VDM\Joomla\Utilities\StringHelper;
/**
* Layout Creator Class
*
* @since 3.2.0
*/
final class Layout
{
/**
* The Config Class.
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The OrderZero Class.
*
* @var OrderZero
* @since 3.2.0
*/
protected OrderZero $orderzero;
/**
* The TabCounter Class.
*
* @var TabCounter
* @since 3.2.0
*/
protected TabCounter $tabcounter;
/**
* The Builder Layout Class.
*
* @var BuilderLayout
* @since 3.2.0
*/
protected BuilderLayout $layout;
/**
* The MovedPublishingFields Class.
*
* @var MovedPublishingFields
* @since 3.2.0
*/
protected MovedPublishingFields $movedpublishingfields;
/**
* The NewPublishingFields Class.
*
* @var NewPublishingFields
* @since 3.2.0
*/
protected NewPublishingFields $newpublishingfields;
/**
* Constructor.
*
* @param Config $config The Config Class.
* @param OrderZero $orderzero The OrderZero Class.
* @param TabCounter $tabcounter The TabCounter Class.
* @param BuilderLayout $layout The Layout Class.
* @param MovedPublishingFields $movedpublishingfields The MovedPublishingFields Class.
* @param NewPublishingFields $newpublishingfields The NewPublishingFields Class.
*
* @since 3.2.0
*/
public function __construct(Config $config, OrderZero $orderzero,
TabCounter $tabcounter, BuilderLayout $layout,
MovedPublishingFields $movedpublishingfields,
NewPublishingFields $newpublishingfields)
{
$this->config = $config;
$this->orderzero = $orderzero;
$this->tabcounter = $tabcounter;
$this->layout = $layout;
$this->movedpublishingfields = $movedpublishingfields;
$this->newpublishingfields = $newpublishingfields;
}
/**
* set the layout builders
*
* @param string $nameSingleCode The single edit view code name
* @param string $tabName The tab code name
* @param string $name The field code name
* @param array $field The field details
*
* @return void
* @since 3.2.0
*/
public function set(string $nameSingleCode, string $tabName, string $name, array &$field): void
{
// first fix the zero order
// to insure it lands before all the other fields
// as zero is expected to behave
if ($field['order_edit'] == 0)
{
// get the value
$zero_counter = $this->orderzero->get($nameSingleCode . '.' . $field['tab'], -999);
if ($zero_counter != -999)
{
$zero_counter++;
}
$field['order_edit'] = $zero_counter;
// set the value
$this->orderzero->set($nameSingleCode . '.' . $field['tab'], $zero_counter);
}
// get the default fields
$default_fields = $this->config->default_fields;
// now build the layout
if (StringHelper::check($tabName)
&& strtolower($tabName) != 'publishing')
{
$this->tabcounter->set($nameSingleCode . '.' . $field['tab'], $tabName);
if ($this->layout->exists($nameSingleCode . '.' . $tabName . '.'
. $field['alignment'] . '.' . $field['order_edit']))
{
$size = $this->layout->count($nameSingleCode . '.' . $tabName . '.'
. $field['alignment']) + 1;
while ($this->layout->exists($nameSingleCode . '.' . $tabName . '.'
. $field['alignment'] . '.' . $size))
{
$size++;
}
$this->layout->set($nameSingleCode . '.' . $tabName . '.'
. $field['alignment'] . '.' . $size, $name);
}
else
{
$this->layout->set($nameSingleCode . '.'
. $tabName . '.' . $field['alignment'] . '.' . $field['order_edit'], $name);
}
// check if default fields were overwritten
if (in_array($name, $default_fields))
{
// just to eliminate
$this->movedpublishingfields->set($nameSingleCode . '.' . $name, true);
}
}
elseif ($tabName === 'publishing' || $tabName === 'Publishing')
{
if (!in_array($name, $default_fields))
{
if ($this->newpublishingfields->exists($nameSingleCode . '.' .
$field['alignment'] . '.' . $field['order_edit']))
{
$size = $this->newpublishingfields->count($nameSingleCode . '.' .
$field['alignment']) + 1;
while ($this->newpublishingfields->exists($nameSingleCode . '.' .
$field['alignment'] . '.' . $size))
{
$size++;
}
$this->newpublishingfields->set($nameSingleCode . '.' .
$field['alignment'] . '.' . $size, $name);
}
else
{
$this->newpublishingfields->set($nameSingleCode . '.' .
$field['alignment'] . '.' . $field['order_edit'], $name);
}
}
}
else
{
$this->tabcounter->set($nameSingleCode . '.1', 'Details');
if ($this->layout->exists($nameSingleCode . '.Details.'
. $field['alignment'] . '.' . $field['order_edit']))
{
$size = $this->layout->count($nameSingleCode . '.Details.'
. $field['alignment']) + 1;
while ($this->layout->exists($nameSingleCode . '.Details.'
. $field['alignment'] . '.' . $size))
{
$size++;
}
$this->layout->set($nameSingleCode . '.Details.'
. $field['alignment'] . '.' . $size, $name);
}
else
{
$this->layout->set($nameSingleCode . '.Details.' . $field['alignment'] . '.'
. $field['order_edit'], $name);
}
// check if default fields were overwritten
if (in_array($name, $default_fields))
{
// just to eliminate
$this->movedpublishingfields->set($nameSingleCode . '.' . $name, true);
}
}
}
}

View File

@@ -0,0 +1,691 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Builder\PermissionCore;
use VDM\Joomla\Componentbuilder\Compiler\Builder\PermissionViews;
use VDM\Joomla\Componentbuilder\Compiler\Builder\PermissionAction;
use VDM\Joomla\Componentbuilder\Compiler\Builder\PermissionComponent;
use VDM\Joomla\Componentbuilder\Compiler\Builder\PermissionGlobalAction;
use VDM\Joomla\Componentbuilder\Compiler\Builder\PermissionDashboard;
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
use VDM\Joomla\Componentbuilder\Compiler\Language;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Utilities\StringHelper;
/**
* Permission Creator Class
*
* @since 3.2.0
*/
final class Permission
{
/**
* The Config Class.
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The PermissionCore Class.
*
* @var PermissionCore
* @since 3.2.0
*/
protected PermissionCore $permissioncore;
/**
* The PermissionViews Class.
*
* @var PermissionViews
* @since 3.2.0
*/
protected PermissionViews $permissionviews;
/**
* The PermissionAction Class.
*
* @var PermissionAction
* @since 3.2.0
*/
protected PermissionAction $permissionaction;
/**
* The PermissionComponent Class.
*
* @var PermissionComponent
* @since 3.2.0
*/
protected PermissionComponent $permissioncomponent;
/**
* The PermissionGlobalAction Class.
*
* @var PermissionGlobalAction
* @since 3.2.0
*/
protected PermissionGlobalAction $permissionglobalaction;
/**
* The PermissionDashboard Class.
*
* @var PermissionDashboard
* @since 3.2.0
*/
protected PermissionDashboard $permissiondashboard;
/**
* The Counter Class.
*
* @var Counter
* @since 3.2.0
*/
protected Counter $counter;
/**
* The Language Class.
*
* @var Language
* @since 3.2.0
*/
protected Language $language;
/**
* The permissions
*
* @var array
* @since 3.2.0
*/
protected array $permissions;
/**
* The Name List View
*
* @var string
* @since 3.2.0
*/
protected string $nameList;
/**
* The Lowercase Name List View
*
* @var string
* @since 3.2.0
*/
protected string $nameListLower;
/**
* The Lowercase Name Single View
*
* @var string
* @since 3.2.0
*/
protected string $nameSingleLower;
/**
* Constructor.
*
* @param Config $config The Config Class.
* @param PermissionCore $permissioncore The PermissionCore Class.
* @param PermissionViews $permissionviews The PermissionViews Class.
* @param PermissionAction $permissionaction The PermissionAction Class.
* @param PermissionComponent $permissioncomponent The PermissionComponent Class.
* @param PermissionGlobalAction $permissionglobalaction The PermissionGlobalAction Class.
* @param PermissionDashboard $permissiondashboard The PermissionDashboard Class.
* @param Counter $counter The Counter Class.
* @param Language $language The Language Class.
*
* @since 3.2.0
*/
public function __construct(Config $config, PermissionCore $permissioncore, PermissionViews $permissionviews,
PermissionAction $permissionaction, PermissionComponent $permissioncomponent, PermissionGlobalAction $permissionglobalaction,
PermissionDashboard $permissiondashboard, Counter $counter, Language $language)
{
$this->config = $config;
$this->permissioncore = $permissioncore;
$this->permissionviews = $permissionviews;
$this->permissionaction = $permissionaction;
$this->permissioncomponent = $permissioncomponent;
$this->permissionglobalaction = $permissionglobalaction;
$this->permissiondashboard = $permissiondashboard;
$this->counter = $counter;
$this->language = $language;
}
/**
* Get the permission action
*
* @param string $nameView View Single Code Name
* @param string $action The Permission Action
*
* @return string|null The action name if set
* @since 3.2.0
*/
public function getAction(string $nameView, string $action): ?string
{
if (($set_action = $this->getCore($nameView, $action)) !== null &&
$this->permissionaction->exists("{$set_action}|{$nameView}"))
{
return $set_action;
}
return $action;
}
/**
* Get the global permission action
*
* @param string $nameView View Single Code Name
* @param string $action The Permission Action
*
* @return string The action name if set
* @since 3.2.0
*/
public function getGlobal(string $nameView, string $action): string
{
if (($set_action = $this->getCore($nameView, $action)) !== null &&
$this->permissionglobalaction->exists("{$set_action}|{$nameView}"))
{
return $set_action;
}
return $action;
}
/**
* Check if the permission action exist
*
* @param string $nameView View Single Code Name
* @param string $action The Permission Action
*
* @return bool true if it exist
* @since 3.2.0
*/
public function actionExist(string $nameView, string $action): bool
{
if (($set_action = $this->getCore($nameView, $action)) !== null &&
$this->permissionaction->exists("{$set_action}|{$nameView}"))
{
return true;
}
return false;
}
/**
* Check if the global permission action exist
*
* @param string $nameView View Single Code Name
* @param string $action The Permission Action
*
* @return bool true if it exist
* @since 3.2.0
*/
public function globalExist(string $nameView, string $action): bool
{
if (($set_action = $this->getCore($nameView, $action)) !== null &&
$this->permissionglobalaction->exists("{$set_action}|{$nameView}"))
{
return true;
}
return false;
}
/**
* Set the permissions
*
* @param array $view View details
* @param string $nameView View Single Code Name
* @param string $nameViews View List Code Name
* @param array $menuControllers Menu Controllers
* @param string $type Type of permissions area
*
* @return void
* @since 3.2.0
*/
public function set(array &$view, string $nameView, string $nameViews, array $menuControllers, string $type = 'admin'): void
{
if ($this->initialise($view, $type))
{
$this->build($view, $nameView, $nameViews, $menuControllers, $type);
}
}
/**
* Build of permissions
*
* @param array $view View details
* @param string $nameView View Single Code Name
* @param string $nameViews View List Code Name
* @param array $menuControllers Menu Controllers
* @param string $type Type of permissions area
*
* @return void
* @since 3.2.0
*/
private function build(array &$view, string $nameView, string $nameViews,
array $menuControllers, string $type = 'admin'): void
{
// load the permissions
foreach ($this->permissions as &$permission)
{
// set action name
$arr = explode('.', trim((string) $permission['action']));
if ($arr[0] != 'core' || $arr[0] === 'view')
{
array_shift($arr);
$action_main = implode('.', $arr);
$action = $nameView . '.' . $action_main;
}
else
{
if ($arr[0] === 'core')
{
// core is already set in global access
$permission['implementation'] = 1;
}
$action = $permission['action'];
}
// build action name
$action_name_builder = explode('.', trim((string) $permission['action']));
array_shift($action_name_builder);
$name_builder = trim(implode('___', $action_name_builder));
$custom_name = trim(implode(' ', $action_name_builder));
// check if we have access set for this view (if not skip)
if ($name_builder === 'edit___access' && $type === 'admin'
&& (!isset($view['access']) || $view['access'] != 1))
{
continue;
}
// set the names
$this->setNames($view['settings'], $custom_name, $type);
// set title (only if not set already)
if (!isset($permission['title']) || !StringHelper::check($permission['title']))
{
$permission['title'] = $this->getTitle($name_builder, $custom_name);
}
// set description (only if not set already)
if (!isset($permission['description']) || !StringHelper::check($permission['description']))
{
$permission['description'] = $this->getDescription($name_builder, $custom_name);
}
// if core is not used update all core strings
$core_check = explode('.', (string) $action);
$core_check[0] = 'core';
$core_target = implode('.', $core_check);
$this->permissioncore->set("{$nameView}|{$core_target}", $action);
// set array sort name
$sort_key = StringHelper::safe($permission['title']);
// set title
$title = $this->config->lang_prefix . '_' . StringHelper::safe($permission['title'], 'U');
// load the actions
if ($permission['implementation'] == 1)
{
// only related to view
$this->permissionviews->set("{$nameView}|{$action}", [
'name' => $action,
'title' => $title,
'description' => "{$title}_DESC"
]);
// load permission to action
$this->permissionaction->set("{$action}|{$nameView}", $nameView);
}
elseif ($permission['implementation'] == 2)
{
// relation to whole component
$this->permissioncomponent->set($sort_key, [
'name' => $action,
'title' => $title,
'description' => "{$title}_DESC"
]);
// the size needs increase
$this->counter->accessSize++;
// build permission switch
$this->permissionglobalaction->set("{$action}|{$nameView}", $nameView);
// add menu control view that has menus options
$this->setDashboard($nameView, $nameViews, $menuControllers, $action, $core_target);
}
elseif ($permission['implementation'] == 3)
{
// only related to view
$this->permissionviews->set("{$nameView}|{$action}", [
'name' => $action,
'title' => $title,
'description' => "{$title}_DESC"
]);
// load permission to action
$this->permissionaction->set("{$action}|{$nameView}", $nameView);
// relation to whole component
$this->permissioncomponent->set($sort_key, [
'name' => $action,
'title' => $title,
'description' => "{$title}_DESC"
]);
// the size needs increase
$this->counter->accessSize++;
// build permission switch
$this->permissionglobalaction->set("{$action}|{$nameView}", $nameView);
// add menu control view that has menus options
$this->setDashboard($nameView, $nameViews, $menuControllers, $action, $core_target);
}
// set to language file
$this->language->set(
'bothadmin', $title, $permission['title']
);
$this->language->set(
'bothadmin', "{$title}_DESC", $permission['description']
);
}
// update permissions
$view['settings']->permissions = $this->permissions;
}
/**
* Set dashboard permissions
*
* @param string $nameView View Single Code Name
* @param string $nameViews View List Code Name
* @param array $menuControllers Menu Controllers
* @param string $action The targeted action
* @param string $coreTarget The core target
*
* @return void
* @since 3.2.0
*/
private function setDashboard(string $nameView, string $nameViews,
array $menuControllers, string $action, string $coreTarget): void
{
// dashboard icon checker
if ($coreTarget === 'core.access')
{
$this->permissiondashboard->set(
"{$nameViews}.access", $action
);
$this->permissiondashboard->set(
"{$nameView}.access", $action
);
}
if ($coreTarget === 'core.create')
{
$this->permissiondashboard->set(
"{$nameView}.create", $action
);
}
// add menu control view that has menus options
foreach ($menuControllers as $menu_controller)
{
if ($coreTarget === 'core.' . $menu_controller)
{
if ($menu_controller === 'dashboard_add')
{
$this->permissiondashboard->set(
"{$nameView}.{$menu_controller}", $action
);
}
else
{
$this->permissiondashboard->set(
"{$nameViews}.{$menu_controller}", $action
);
}
}
}
}
/**
* Initialise build of permissions
*
* @param array $view View details
* @param string $type Type of permissions area
*
* @return bool true if build can continue
* @since 3.2.0
*/
private function initialise(array $view, string $type): bool
{
if (isset($view['settings']) && (isset($view['settings']->permissions)
&& ArrayHelper::check($view['settings']->permissions)
|| (isset($view['port']) && $view['port'])
|| (isset($view['history']) && $view['history'])))
{
if (isset($view['settings']->permissions)
&& ArrayHelper::check($view['settings']->permissions))
{
$this->permissions = $view['settings']->permissions;
}
else
{
$this->permissions = [];
}
$this->initPort($view['port'] ?? 0);
$this->initHistory($view['history'] ?? 0);
$this->initBatch($type);
return true;
}
return false;
}
/**
* Initialise build of import and export permissions
*
* @param int $port The port adding switch
*
* @return void
* @since 3.2.0
*/
private function initPort(int $port): void
{
if ($port)
{
// export
$add = [];
$add['action'] = 'view.export';
$add['implementation'] = '2';
array_push($this->permissions, $add);
// import
$add = [];
$add['action'] = 'view.import';
$add['implementation'] = '2';
array_push($this->permissions, $add);
}
}
/**
* Initialise build of history permissions
*
* @param int $history The history adding switch
*
* @return void
* @since 3.2.0
*/
private function initHistory(int $history): void
{
if ($history)
{
// export
$add = [];
$add['action'] = 'view.version';
$add['implementation'] = '3';
array_push($this->permissions, $add);
}
}
/**
* Initialise build of batch permissions
*
* @param string $type Type of permissions area
*
* @return void
* @since 3.2.0
*/
private function initBatch(string $type): void
{
// add batch permissions
if ($type === 'admin')
{
// set batch control
$add = [];
$add['action'] = 'view.batch';
$add['implementation'] = '2';
array_push($this->permissions, $add);
}
}
/**
* Initialise build of names used in permissions
*
* @param object $settings The view settings object
* @param string $customName The custom name
* @param string $type Type of permissions area
*
* @return void
* @since 3.2.0
*/
private function setNames(object $settings, string $customName, string $type): void
{
// build the names
if ($type === 'admin')
{
$this->nameList = StringHelper::safe(
$settings->name_list, 'W'
);
$this->nameListLower = StringHelper::safe(
$customName . ' ' . $settings->name_list, 'w'
);
$this->nameSingleLower = StringHelper::safe(
$settings->name_single, 'w'
);
}
elseif ($type === 'customAdmin')
{
$this->nameList = StringHelper::safe(
$settings->name, 'W'
);
$this->nameListLower = $settings->name;
$this->nameSingleLower = $settings->name;
}
}
/**
* Get the dynamic title
*
* @param string $nameBuilder The target builder name
* @param string $customName The dynamic custom name
*
* @return string The title
* @since 3.2.0
*/
private function getTitle(string $nameBuilder, string $customName): string
{
$actionTitles = [
'edit' => 'Edit',
'edit___own' => 'Edit Own',
'edit___access' => 'Edit Access',
'edit___state' => 'Edit State',
'edit___created_by' => 'Edit Created By',
'edit___created' => 'Edit Created Date',
'create' => 'Create',
'delete' => 'Delete',
'access' => 'Access',
'export' => 'Export',
'import' => 'Import',
'version' => 'Edit Version',
'batch' => 'Batch Use',
];
$titleSuffix = $actionTitles[$nameBuilder] ?? StringHelper::safe($customName, 'W');
return $this->nameList . ' ' . $titleSuffix;
}
/**
* Get the dynamic description
*
* @param string $nameBuilder The target builder name
* @param string $customName The dynamic custom name
*
* @return string The description
* @since 3.2.0
*/
private function getDescription(string $nameBuilder, string $customName): string
{
$actionDescriptions = [
'edit' => 'edit the ' . $this->nameSingleLower,
'edit___own' => 'edit ' . $this->nameListLower . ' created by them',
'edit___access' => 'change the access of the ' . $this->nameListLower,
'edit___state' => 'update the state of the ' . $this->nameSingleLower,
'edit___created_by' => 'update the created by of the ' . $this->nameListLower,
'edit___created' => 'update the created date of the ' . $this->nameListLower,
'create' => 'create ' . $this->nameListLower,
'delete' => 'delete ' . $this->nameListLower,
'access' => 'access ' . $this->nameListLower,
'export' => 'export ' . $this->nameListLower,
'import' => 'import ' . $this->nameListLower,
'version' => 'edit versions of ' . $this->nameListLower,
'batch' => 'use batch copy/update method of ' . $this->nameListLower
];
$description = $actionDescriptions[$nameBuilder] ?? StringHelper::safe($customName, 'w') . ' of ' . $this->nameSingleLower;
return ' Allows the users in this group to ' . $description;
}
/**
* Get the core permission action
*
* @param string $nameView View Single Code Name
* @param string $action The Permission Action
*
* @return string|null The action name if set
* @since 3.2.0
*/
private function getCore(string $nameView, string $action): ?string
{
return $this->permissioncore->get("{$nameView}|{$action}");
}
}

View File

@@ -0,0 +1,154 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Compiler\Creator;
use VDM\Joomla\Componentbuilder\Compiler\Config;
use VDM\Joomla\Componentbuilder\Compiler\Builder\SiteFields;
use VDM\Joomla\Componentbuilder\Compiler\Builder\SiteFieldData as SiteField;
/**
* Site Field Data Creator Class
*
* @since 3.2.0
*/
final class SiteFieldData
{
/**
* The Config Class.
*
* @var Config
* @since 3.2.0
*/
protected Config $config;
/**
* The SiteFields Class.
*
* @var SiteFields
* @since 3.2.0
*/
protected SiteFields $sitefields;
/**
* The SiteFieldData Class.
*
* @var SiteField
* @since 3.2.0
*/
protected SiteField $sitefield;
/**
* The decoding options
*
* @var array
* @since 3.2.0
*/
protected array $decode = [
'json',
'base64',
'basic_encryption',
'whmcs_encryption',
'medium_encryption',
'expert_mode'
];
/**
* The text areas
*
* @var array
* @since 3.2.0
*/
protected array $textareas = [
'textarea',
'editor'
];
/**
* Constructor.
*
* @param Config $config The Config Class.
* @param SiteFields $sitefields The SiteFields Class.
* @param SiteField $sitefield The SiteFieldData Class.
*
* @since 3.2.0
*/
public function __construct(Config $config, SiteFields $sitefields,
SiteField $sitefield)
{
$this->config = $config;
$this->sitefields = $sitefields;
$this->sitefield = $sitefield;
}
/**
* set the site field data needed
*
* @param string $view The single edit view code name
* @param string $field The field name
* @param string $set The decoding set this field belongs to
* @param string $type The field type
*
* @return void
*
*/
public function set(string $view, string $field, string $set, string $type): void
{
if (($site_fields = $this->sitefields->get($view . '.' . $field)) !== null)
{
foreach ($site_fields as $codeString => $site_field)
{
// get the code array
$codeArray = explode('___', (string) $codeString);
// set the code
$code = trim($codeArray[0]);
// set the path
$path = $site_field['site'] . '.' . $code . '.' . $site_field['as'] . '.' . $site_field['key'];
// set the decoding methods
if (in_array($set, $this->decode))
{
if ($this->sitefield->exists('decode.' . $path . '.decode'))
{
if (!$this->sitefield->inArray($set, 'decode.' . $path . '.decode'))
{
$this->sitefield->add('decode.' . $path . '.decode', $set, true);
}
}
else
{
$this->sitefield->set('decode.' . $path, [
'decode' => [$set],
'type' => $type,
'admin_view' => $view
]);
}
}
// set the uikit checker
if ((2 == $this->config->uikit || 1 == $this->config->uikit)
&& in_array($type, $this->textareas))
{
$this->sitefield->add('uikit.' . $path, (array) $site_field, true);
}
// set the text area checker
if (in_array($type, $this->textareas))
{
$this->sitefield->add('textareas.' . $path, (array) $site_field, true);
}
}
}
}
}

View File

@@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>