Release of v5.1.1-alpha2
Adds the ModalSelect fieldtype to Joomla Component Builder - J5. Adds the Data Import Function to the Demo Component. Adds new country related tables and fields to the Demo Component. Resolves the Database Updating issue in the compiler. #1212,#1209. Adds the Component Commands Plugin to the CLI for Import of spreadsheet data-sets.
This commit is contained in:
@@ -315,6 +315,11 @@ class Data
|
||||
*/
|
||||
public function get($view): ?object
|
||||
{
|
||||
if (empty($view))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($this->index[$view]))
|
||||
{
|
||||
$id = $this->index[$view];
|
||||
@@ -478,6 +483,13 @@ class Data
|
||||
'jcb_ce_onBeforeModelViewData', [&$view]
|
||||
);
|
||||
|
||||
// should we add sql?
|
||||
if ($view->add_sql !== 1)
|
||||
{
|
||||
unset($view->addtables);
|
||||
unset($view->sql);
|
||||
}
|
||||
|
||||
// add the tables
|
||||
$view->addtables = (isset($view->addtables) && JsonHelper::check($view->addtables))
|
||||
? json_decode((string) $view->addtables, true)
|
||||
|
@@ -397,7 +397,7 @@ final class Structuresingle
|
||||
return false;
|
||||
}
|
||||
// take action based on type
|
||||
elseif ($details->type === 'file' && !File::exists($this->currentFullPath))
|
||||
elseif ($details->type === 'file' && !is_file($this->currentFullPath))
|
||||
{
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEFILE_PATH_ERRORHTHREE'), 'Error'
|
||||
|
@@ -689,6 +689,8 @@ final class Builders
|
||||
// to identify the field
|
||||
$this->databasetables->set($nameSingleCode . '.' . $name . '.ID',
|
||||
$field['settings']->id);
|
||||
$this->databasetables->set($nameSingleCode . '.' . $name . '.GUID',
|
||||
$field['settings']->guid);
|
||||
$this->databasetables->set($nameSingleCode . '.' . $name . '.null_switch',
|
||||
$field['settings']->null_switch);
|
||||
// set index types
|
||||
@@ -912,6 +914,7 @@ final class Builders
|
||||
&& $typeName != 'repeatable'
|
||||
&& $typeName != 'subform')
|
||||
{
|
||||
// do not add if extends is empty
|
||||
$this->customfield->add($nameListCode, [
|
||||
'type' => $typeName,
|
||||
'code' => $name,
|
||||
|
@@ -15,6 +15,7 @@ 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\ModalSelect;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\Groups;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Builder\FieldNames;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Creator\Fieldtypeinterface as Field;
|
||||
@@ -56,6 +57,14 @@ final class FieldDynamic implements Fielddynamicinterface
|
||||
*/
|
||||
protected Attributes $attributes;
|
||||
|
||||
/**
|
||||
* The ModalSelect Class.
|
||||
*
|
||||
* @var ModalSelect
|
||||
* @since 5.2.1
|
||||
*/
|
||||
protected ModalSelect $modalselect;
|
||||
|
||||
/**
|
||||
* The Groups Class.
|
||||
*
|
||||
@@ -102,6 +111,7 @@ final class FieldDynamic implements Fielddynamicinterface
|
||||
* @param Name $name The Name Class.
|
||||
* @param TypeName $typename The TypeName Class.
|
||||
* @param Attributes $attributes The Attributes Class.
|
||||
* @param ModalSelect $modalselect The ModalSelect Class.
|
||||
* @param Groups $groups The Groups Class.
|
||||
* @param FieldNames $fieldnames The FieldNames Class.
|
||||
* @param Field $field The Fieldtypeinterface Class.
|
||||
@@ -111,12 +121,14 @@ final class FieldDynamic implements Fielddynamicinterface
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(Name $name, TypeName $typename,
|
||||
Attributes $attributes, Groups $groups, FieldNames $fieldnames,
|
||||
Attributes $attributes, ModalSelect $modalselect,
|
||||
Groups $groups, FieldNames $fieldnames,
|
||||
Field $field, Builders $builders, Layout $layout)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->typename = $typename;
|
||||
$this->attributes = $attributes;
|
||||
$this->modalselect = $modalselect;
|
||||
$this->groups = $groups;
|
||||
$this->fieldnames = $fieldnames;
|
||||
$this->field = $field;
|
||||
@@ -172,6 +184,12 @@ final class FieldDynamic implements Fielddynamicinterface
|
||||
// set options as null
|
||||
$optionArray = null;
|
||||
|
||||
// special treatment for Modal Select
|
||||
if ($typeName === 'ModalSelect')
|
||||
{
|
||||
$fieldAttributes['custom'] = $this->modalselect->extract($fieldAttributes);
|
||||
}
|
||||
|
||||
if ($this->groups->check($typeName, 'option'))
|
||||
{
|
||||
// set options array
|
||||
@@ -253,6 +271,7 @@ final class FieldDynamic implements Fielddynamicinterface
|
||||
// set the custom array
|
||||
$custom = $fieldAttributes['custom'];
|
||||
unset($fieldAttributes['custom']);
|
||||
|
||||
// set db key
|
||||
$custom['db'] = $dbkey;
|
||||
// increment the db key
|
||||
|
@@ -19,6 +19,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Field\Groups;
|
||||
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\ModalSelect;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Creator\CustomFieldTypeFile;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
@@ -94,6 +95,14 @@ final class FieldString implements Fieldtypeinterface
|
||||
*/
|
||||
protected Attributes $attributes;
|
||||
|
||||
/**
|
||||
* The ModalSelect Class.
|
||||
*
|
||||
* @var ModalSelect
|
||||
* @since 5.2.1
|
||||
*/
|
||||
protected ModalSelect $modalselect;
|
||||
|
||||
/**
|
||||
* The CustomFieldTypeFile Class.
|
||||
*
|
||||
@@ -120,6 +129,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
* @param Name $name The Name Class.
|
||||
* @param TypeName $typename The TypeName Class.
|
||||
* @param Attributes $attributes The Attributes Class.
|
||||
* @param ModalSelect $modalselect The ModalSelect Class.
|
||||
* @param CustomFieldTypeFile $customfieldtypefile The CustomFieldTypeFile Class.
|
||||
* @param Counter $counter The Counter Class.
|
||||
*
|
||||
@@ -127,7 +137,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
*/
|
||||
public function __construct(Config $config, Language $language, Field $field,
|
||||
Groups $groups, Name $name, TypeName $typename,
|
||||
Attributes $attributes,
|
||||
Attributes $attributes, ModalSelect $modalselect,
|
||||
CustomFieldTypeFile $customfieldtypefile,
|
||||
Counter $counter)
|
||||
{
|
||||
@@ -138,6 +148,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
$this->name = $name;
|
||||
$this->typename = $typename;
|
||||
$this->attributes = $attributes;
|
||||
$this->modalselect = $modalselect;
|
||||
$this->customfieldtypefile = $customfieldtypefile;
|
||||
$this->counter = $counter;
|
||||
}
|
||||
@@ -591,6 +602,13 @@ final class FieldString implements Fieldtypeinterface
|
||||
{
|
||||
//reset options array
|
||||
$r_optionArray = array();
|
||||
|
||||
// special treatment for Modal Select
|
||||
if ($r_typeName === 'ModalSelect')
|
||||
{
|
||||
$r_fieldValues['custom'] = $this->modalselect->extract($r_fieldValues);
|
||||
}
|
||||
|
||||
if ($this->groups->check(
|
||||
$r_typeName, 'option'
|
||||
))
|
||||
@@ -740,7 +758,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
$fieldData['settings']
|
||||
))
|
||||
{
|
||||
$r_name = $this->name->get(
|
||||
$r_name = $this->name->get(
|
||||
$fieldData, $nameListCode, $_resolverKey
|
||||
);
|
||||
$r_typeName = $this->typename->get($fieldData);
|
||||
@@ -763,6 +781,13 @@ final class FieldString implements Fieldtypeinterface
|
||||
{
|
||||
//reset options array
|
||||
$r_optionArray = array();
|
||||
|
||||
// special treatment for Modal Select
|
||||
if ($r_typeName === 'ModalSelect')
|
||||
{
|
||||
$r_fieldValues['custom'] = $this->modalselect->extract($r_fieldValues);
|
||||
}
|
||||
|
||||
if ($this->groups->check(
|
||||
$r_typeName, 'option'
|
||||
))
|
||||
|
@@ -19,6 +19,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Field\Groups;
|
||||
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\ModalSelect;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Xml;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Creator\CustomFieldTypeFile;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
|
||||
@@ -93,6 +94,14 @@ final class FieldXML implements Fieldtypeinterface
|
||||
*/
|
||||
protected Attributes $attributes;
|
||||
|
||||
/**
|
||||
* The ModalSelect Class.
|
||||
*
|
||||
* @var ModalSelect
|
||||
* @since 5.2.1
|
||||
*/
|
||||
protected ModalSelect $modalselect;
|
||||
|
||||
/**
|
||||
* The Xml Class.
|
||||
*
|
||||
@@ -127,6 +136,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param Name $name The Name Class.
|
||||
* @param TypeName $typename The TypeName Class.
|
||||
* @param Attributes $attributes The Attributes Class.
|
||||
* @param ModalSelect $modalselect The ModalSelect Class.
|
||||
* @param Xml $xml The Xml Class.
|
||||
* @param CustomFieldTypeFile $customfieldtypefile The CustomFieldTypeFile Class.
|
||||
* @param Counter $counter The Counter Class.
|
||||
@@ -135,8 +145,8 @@ final class FieldXML implements Fieldtypeinterface
|
||||
*/
|
||||
public function __construct(Config $config, Language $language, Field $field,
|
||||
Groups $groups, Name $name, TypeName $typename,
|
||||
Attributes $attributes, Xml $xml,
|
||||
CustomFieldTypeFile $customfieldtypefile,
|
||||
Attributes $attributes, ModalSelect $modalselect,
|
||||
Xml $xml, CustomFieldTypeFile $customfieldtypefile,
|
||||
Counter $counter)
|
||||
{
|
||||
$this->config = $config;
|
||||
@@ -146,6 +156,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
$this->name = $name;
|
||||
$this->typename = $typename;
|
||||
$this->attributes = $attributes;
|
||||
$this->modalselect = $modalselect;
|
||||
$this->xml = $xml;
|
||||
$this->customfieldtypefile = $customfieldtypefile;
|
||||
$this->counter = $counter;
|
||||
@@ -571,6 +582,13 @@ final class FieldXML implements Fieldtypeinterface
|
||||
{
|
||||
//reset options array
|
||||
$r_optionArray = array();
|
||||
|
||||
// special treatment for Modal Select
|
||||
if ($r_typeName === 'ModalSelect')
|
||||
{
|
||||
$r_fieldValues['custom'] = $this->modalselect->extract($r_fieldValues);
|
||||
}
|
||||
|
||||
if ($this->groups->check(
|
||||
$r_typeName, 'option'
|
||||
))
|
||||
@@ -735,7 +753,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
$fieldData['settings']
|
||||
))
|
||||
{
|
||||
$r_name = $this->name->get(
|
||||
$r_name = $this->name->get(
|
||||
$fieldData, $nameListCode, $_resolverKey
|
||||
);
|
||||
$r_typeName = $this->typename->get($fieldData);
|
||||
@@ -756,6 +774,13 @@ final class FieldXML implements Fieldtypeinterface
|
||||
{
|
||||
//reset options array
|
||||
$r_optionArray = array();
|
||||
|
||||
// special treatment for Modal Select
|
||||
if ($r_typeName === 'ModalSelect')
|
||||
{
|
||||
$r_fieldValues['custom'] = $this->modalselect->extract($r_fieldValues);
|
||||
}
|
||||
|
||||
if ($this->groups->check(
|
||||
$r_typeName, 'option'
|
||||
))
|
||||
@@ -763,11 +788,11 @@ final class FieldXML implements Fieldtypeinterface
|
||||
// now add to the field set
|
||||
$this->xml->append(
|
||||
$form, $this->get(
|
||||
'option', $r_fieldValues, $r_name,
|
||||
$r_typeName, $langView,
|
||||
$nameSingleCode, $nameListCode,
|
||||
$placeholders, $r_optionArray
|
||||
)
|
||||
'option', $r_fieldValues, $r_name,
|
||||
$r_typeName, $langView,
|
||||
$nameSingleCode, $nameListCode,
|
||||
$placeholders, $r_optionArray
|
||||
)
|
||||
);
|
||||
}
|
||||
elseif ($r_typeName === 'subform')
|
||||
@@ -789,12 +814,12 @@ final class FieldXML implements Fieldtypeinterface
|
||||
// now add to the field set
|
||||
$this->xml->append(
|
||||
$form, $this->get(
|
||||
'special', $r_fieldValues,
|
||||
$r_name, $r_typeName, $langView,
|
||||
$nameSingleCode,
|
||||
$nameListCode, $placeholders,
|
||||
$r_optionArray
|
||||
)
|
||||
'special', $r_fieldValues,
|
||||
$r_name, $r_typeName, $langView,
|
||||
$nameSingleCode,
|
||||
$nameListCode, $placeholders,
|
||||
$r_optionArray
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -810,11 +835,11 @@ final class FieldXML implements Fieldtypeinterface
|
||||
// now add to the field set
|
||||
$this->xml->append(
|
||||
$form, $this->get(
|
||||
'custom', $r_fieldValues, $r_name,
|
||||
$r_typeName, $langView,
|
||||
$nameSingleCode, $nameListCode,
|
||||
$placeholders, $r_optionArray
|
||||
)
|
||||
'custom', $r_fieldValues, $r_name,
|
||||
$r_typeName, $langView,
|
||||
$nameSingleCode, $nameListCode,
|
||||
$placeholders, $r_optionArray
|
||||
)
|
||||
);
|
||||
// set lang (just incase)
|
||||
$r_listLangName = $langView . '_'
|
||||
@@ -851,11 +876,11 @@ final class FieldXML implements Fieldtypeinterface
|
||||
// now add to the field set
|
||||
$this->xml->append(
|
||||
$form, $this->get(
|
||||
'plain', $r_fieldValues, $r_name,
|
||||
$r_typeName, $langView,
|
||||
$nameSingleCode, $nameListCode,
|
||||
$placeholders, $r_optionArray
|
||||
)
|
||||
'plain', $r_fieldValues, $r_name,
|
||||
$r_typeName, $langView,
|
||||
$nameSingleCode, $nameListCode,
|
||||
$placeholders, $r_optionArray
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -151,6 +151,11 @@ class Data
|
||||
*/
|
||||
public function get($field, ?string $singleViewName = null, ?string $listViewName = null): ?object
|
||||
{
|
||||
if (empty($field))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($this->index[$field]))
|
||||
{
|
||||
$id = $this->index[$field];
|
||||
|
@@ -0,0 +1,150 @@
|
||||
<?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\Field;
|
||||
|
||||
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Structure;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentMulti;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Field Modal Select
|
||||
*
|
||||
* @since 5.2.1
|
||||
*/
|
||||
final class ModalSelect
|
||||
{
|
||||
/**
|
||||
* The Structure Class.
|
||||
*
|
||||
* @var Structure
|
||||
* @since 5.2.1
|
||||
*/
|
||||
protected Structure $structure;
|
||||
|
||||
/**
|
||||
* The ContentMulti Class.
|
||||
*
|
||||
* @var ContentMulti
|
||||
* @since 5.2.1
|
||||
*/
|
||||
protected ContentMulti $contentmulti;
|
||||
|
||||
/**
|
||||
* The switch to ensure the fix is just added once
|
||||
*
|
||||
* @var bool
|
||||
* @since 5.2.1
|
||||
*/
|
||||
protected bool $addedFix = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Structure $structure The Structure Class.
|
||||
* @param ContentMulti $contentmulti The ContentMulti Class.
|
||||
*
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public function __construct(Structure $structure, ContentMulti $contentmulti)
|
||||
{
|
||||
$this->structure = $structure;
|
||||
$this->contentmulti = $contentmulti;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts component and view details from field attributes for a Modal Select field.
|
||||
*
|
||||
* @param array $fieldAttributes The field attributes containing URLs and SQL table details.
|
||||
*
|
||||
* @return array An associative array with extracted component, view, views, table, id, and text.
|
||||
* @since 5.1.2
|
||||
*/
|
||||
public function extract(array $fieldAttributes): array
|
||||
{
|
||||
$component = null;
|
||||
$views = null;
|
||||
$view = null;
|
||||
|
||||
// Extract parameters from the given URL
|
||||
$extractParams = function ($url) {
|
||||
if (empty($url)) {
|
||||
return ['option' => null, 'view' => null];
|
||||
}
|
||||
$query = parse_url($url, PHP_URL_QUERY);
|
||||
parse_str($query, $params);
|
||||
return [
|
||||
'option' => $params['option'] ?? $params['amp;option'] ?? null,
|
||||
'view' => $params['view'] ?? $params['amp;view'] ?? null,
|
||||
];
|
||||
};
|
||||
|
||||
// Process URL attributes
|
||||
foreach (['urlSelect', 'urlEdit', 'urlNew'] as $urlKey)
|
||||
{
|
||||
$params = $extractParams($fieldAttributes[$urlKey] ?? '');
|
||||
$component ??= $params['option'];
|
||||
if ($urlKey === 'urlSelect')
|
||||
{
|
||||
$views ??= $params['view'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$view ??= $params['view'];
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the target table and extract the view name
|
||||
$field_target_table = $fieldAttributes['sql_title_table'] ?? '';
|
||||
if (!$view && !empty($field_target_table))
|
||||
{
|
||||
$clean_table = str_replace('__', '', $field_target_table);
|
||||
$view = substr($clean_table, strpos($clean_table, '_') + 1);
|
||||
}
|
||||
|
||||
$sql_title_key = $fieldAttributes['sql_title_key'] ?? 'id';
|
||||
|
||||
// if one field is not id, we add an override to the ModalSelectField as a FIX
|
||||
if (!$this->addedFix && $sql_title_key !== 'id')
|
||||
{
|
||||
$this->structure->build(
|
||||
['admin' => 'fieldmodalselect_override'],
|
||||
'fieldmodalselect_override'
|
||||
);
|
||||
$this->structure->build(
|
||||
['site' => 'fieldmodalselect_override'],
|
||||
'fieldmodalselect_override'
|
||||
);
|
||||
// to make sure the file is updated TODO
|
||||
$this->contentmulti->set('fieldmodalselect_override|BLABLA', 'blabla');
|
||||
|
||||
$this->addedFix = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'modal_select' => true,
|
||||
'urlSelect' => $fieldAttributes['urlSelect'] ?? '',
|
||||
'hint' => $fieldAttributes['hint'] ?? '',
|
||||
'titleSelect' => $fieldAttributes['titleSelect'] ?? '',
|
||||
'iconSelect' => $fieldAttributes['iconSelect'] ?? '',
|
||||
'table' => $field_target_table,
|
||||
'id' => $sql_title_key,
|
||||
'text' => $fieldAttributes['sql_title_column'] ?? '',
|
||||
'component' => $component ?? 'error',
|
||||
'view' => $view ?? 'error',
|
||||
'views' => $views ?? 'error',
|
||||
'button' => false,
|
||||
'extends' => ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -418,7 +418,7 @@ class Compiler extends Infusion
|
||||
// first we do the static files
|
||||
foreach (CFactory::_('Utilities.Files')->get('static') as $static)
|
||||
{
|
||||
if (File::exists($static['path']))
|
||||
if (is_file($static['path']))
|
||||
{
|
||||
$this->setFileContent(
|
||||
$static['name'], $static['path'], $bom
|
||||
@@ -434,7 +434,7 @@ class Compiler extends Infusion
|
||||
{
|
||||
if ($file['view'] == $view)
|
||||
{
|
||||
if (File::exists($file['path']))
|
||||
if (is_file($file['path']))
|
||||
{
|
||||
$this->setFileContent(
|
||||
$file['name'], $file['path'], $bom,
|
||||
@@ -513,7 +513,7 @@ class Compiler extends Infusion
|
||||
// update the module files
|
||||
foreach (CFactory::_('Utilities.Files')->get($module->key) as $module_file)
|
||||
{
|
||||
if (File::exists($module_file['path']))
|
||||
if (is_file($module_file['path']))
|
||||
{
|
||||
$this->setFileContent(
|
||||
$module_file['name'], $module_file['path'],
|
||||
@@ -591,7 +591,7 @@ class Compiler extends Infusion
|
||||
// update the plugin files
|
||||
foreach (CFactory::_('Utilities.Files')->get($plugin->key) as $plugin_file)
|
||||
{
|
||||
if (File::exists($plugin_file['path']))
|
||||
if (is_file($plugin_file['path']))
|
||||
{
|
||||
$this->setFileContent(
|
||||
$plugin_file['name'], $plugin_file['path'],
|
||||
@@ -625,7 +625,7 @@ class Compiler extends Infusion
|
||||
// update the power files
|
||||
foreach (CFactory::_('Utilities.Files')->get($power->key) as $power_file)
|
||||
{
|
||||
if (File::exists($power_file['path']))
|
||||
if (is_file($power_file['path']))
|
||||
{
|
||||
$this->setFileContent(
|
||||
$power_file['name'], $power_file['path'],
|
||||
@@ -650,7 +650,7 @@ class Compiler extends Infusion
|
||||
// update the power files
|
||||
foreach (CFactory::_('Utilities.Files')->get($key) as $power_file)
|
||||
{
|
||||
if (File::exists($power_file['path']))
|
||||
if (is_file($power_file['path']))
|
||||
{
|
||||
$this->setFileContent(
|
||||
$power_file['name'], $power_file['path'],
|
||||
@@ -775,7 +775,7 @@ class Compiler extends Infusion
|
||||
$update_server_xml_path = CFactory::_('Utilities.Paths')->component_path . '/'
|
||||
. $this->updateServerFileName . '.xml';
|
||||
// make sure we have the correct file
|
||||
if (File::exists($update_server_xml_path)
|
||||
if (is_file($update_server_xml_path)
|
||||
&& ($update_server = CFactory::_('Component')->get('update_server')) !== null)
|
||||
{
|
||||
// move to server
|
||||
@@ -811,7 +811,7 @@ class Compiler extends Infusion
|
||||
&& is_numeric($module->update_server)
|
||||
&& $module->update_server > 0
|
||||
&& isset($module->update_server_xml_path)
|
||||
&& File::exists($module->update_server_xml_path)
|
||||
&& is_file($module->update_server_xml_path)
|
||||
&& isset($module->update_server_xml_file_name)
|
||||
&& StringHelper::check(
|
||||
$module->update_server_xml_file_name
|
||||
@@ -852,7 +852,7 @@ class Compiler extends Infusion
|
||||
&& is_numeric($plugin->update_server)
|
||||
&& $plugin->update_server > 0
|
||||
&& isset($plugin->update_server_xml_path)
|
||||
&& File::exists($plugin->update_server_xml_path)
|
||||
&& is_file($plugin->update_server_xml_path)
|
||||
&& isset($plugin->update_server_xml_file_name)
|
||||
&& StringHelper::check(
|
||||
$plugin->update_server_xml_file_name
|
||||
@@ -952,7 +952,7 @@ class Compiler extends Infusion
|
||||
if (('README.md' === $static['name']
|
||||
|| 'README.txt' === $static['name'])
|
||||
&& CFactory::_('Component')->get('addreadme')
|
||||
&& File::exists($static['path']))
|
||||
&& is_file($static['path']))
|
||||
{
|
||||
$this->setReadMe($static['path']);
|
||||
$two++;
|
||||
@@ -1467,7 +1467,7 @@ class Compiler extends Infusion
|
||||
}
|
||||
$counter = 0;
|
||||
// check if file exist
|
||||
if (File::exists($file))
|
||||
if (is_file($file))
|
||||
{
|
||||
foreach (
|
||||
new \SplFileObject($file) as $lineNumber => $lineContent
|
||||
|
@@ -1326,6 +1326,30 @@ class Fields extends Structure
|
||||
. $filter['type'] . '"';
|
||||
// set css classname of this field
|
||||
$filter_class = ucfirst((string) $filter['type']);
|
||||
|
||||
// if this is a modal_select field
|
||||
$modal_select = $filter['custom']['modal_select'] ?? null;
|
||||
if ($modal_select)
|
||||
{
|
||||
$field_filter_sets[] = Indent::_(3) . 'sql_title_table="'
|
||||
. $filter['custom']['table'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'sql_title_column="'
|
||||
. $filter['custom']['text'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'sql_title_key="'
|
||||
. $filter['custom']['id'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'urlSelect="'
|
||||
. $filter['custom']['urlSelect'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'hint="'
|
||||
. $filter['custom']['hint'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'titleSelect="'
|
||||
. $filter['custom']['titleSelect'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'iconSelect="'
|
||||
. $filter['custom']['iconSelect'] . '"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'select="true"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'edit="false"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'clear="true"';
|
||||
$field_filter_sets[] = Indent::_(3) . 'onchange="form.submit()"';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -445,6 +445,11 @@ class Infusion extends Interpretation
|
||||
$this->setAddToolBar($view)
|
||||
);
|
||||
|
||||
// ADDMODALTOOLBAR <<<DYNAMIC>>>
|
||||
CFactory::_('Compiler.Builder.Content.Multi')->set($nameSingleCode . '|ADDMODALTOOLBAR',
|
||||
$this->setAddModalToolBar($view)
|
||||
);
|
||||
|
||||
// set the script for this view
|
||||
$this->buildTheViewScript($view);
|
||||
|
||||
@@ -945,6 +950,14 @@ class Infusion extends Interpretation
|
||||
)
|
||||
);
|
||||
|
||||
// VIEWS_MODAL_BODY <<<DYNAMIC>>>
|
||||
CFactory::_('Compiler.Builder.Content.Multi')->set($nameListCode . '|VIEWS_MODAL_BODY',
|
||||
$this->setModalViewsBody(
|
||||
$nameSingleCode,
|
||||
$nameListCode
|
||||
)
|
||||
);
|
||||
|
||||
// LISTHEAD <<<DYNAMIC>>>
|
||||
CFactory::_('Compiler.Builder.Content.Multi')->set($nameListCode . '|LISTHEAD',
|
||||
$this->setListHead(
|
||||
@@ -1046,6 +1059,13 @@ class Infusion extends Interpretation
|
||||
)
|
||||
);
|
||||
|
||||
// ADMIN_VIEWS_MODAL_HEADER <<<DYNAMIC>>> add the header details for the views
|
||||
CFactory::_('Compiler.Builder.Content.Multi')->set($nameListCode . '|ADMIN_VIEWS_MODAL_HEADER',
|
||||
CFactory::_('Header')->get(
|
||||
'admin.views.modal', $nameListCode
|
||||
)
|
||||
);
|
||||
|
||||
// API_VIEWS_CONTROLLER_HEADER <<<DYNAMIC>>> add the header details for the controller
|
||||
CFactory::_('Compiler.Builder.Content.Multi')->set($nameListCode . '|API_VIEWS_CONTROLLER_HEADER',
|
||||
CFactory::_('Header')->get(
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -679,7 +679,7 @@ class Structure extends Get
|
||||
!isset($this->extentionTrackingFilesMoved[$check]))
|
||||
{
|
||||
// check files exist
|
||||
if (File::exists(
|
||||
if (is_file(
|
||||
CFactory::_('Utilities.Paths')->component_path . '/admin/models/fields/'
|
||||
. $field['type_name'] . '.php'
|
||||
))
|
||||
@@ -707,7 +707,7 @@ class Structure extends Get
|
||||
!isset($this->extentionTrackingFilesMoved[$check]))
|
||||
{
|
||||
// check files exist
|
||||
if (File::exists(
|
||||
if (is_file(
|
||||
CFactory::_('Utilities.Paths')->component_path . '/admin/models/rules/'
|
||||
. CFactory::_('Registry')->get('validation.linked.' . $field['field'])
|
||||
. '.php'
|
||||
|
@@ -426,6 +426,8 @@ final class Header implements HeaderInterface
|
||||
$headers[] = 'use Joomla\Input\Input;';
|
||||
break;
|
||||
|
||||
case 'admin.views.modal':
|
||||
$headers[] = 'use Joomla\CMS\Session\Session;';
|
||||
case 'admin.views':
|
||||
$headers[] = 'use Joomla\CMS\HTML\HTMLHelper as Html;';
|
||||
$headers[] = 'use Joomla\CMS\Layout\LayoutHelper;';
|
||||
|
@@ -426,6 +426,8 @@ final class Header implements HeaderInterface
|
||||
$headers[] = 'use Joomla\Input\Input;';
|
||||
break;
|
||||
|
||||
case 'admin.views.modal':
|
||||
$headers[] = 'use Joomla\CMS\Session\Session;';
|
||||
case 'admin.views':
|
||||
$headers[] = 'use Joomla\CMS\HTML\HTMLHelper as Html;';
|
||||
$headers[] = 'use Joomla\CMS\Layout\LayoutHelper;';
|
||||
|
@@ -63,9 +63,9 @@ class Sql
|
||||
*/
|
||||
public function set(object &$item)
|
||||
{
|
||||
if (isset($item->add_sql) && $item->add_sql == 1 && isset($item->source))
|
||||
if (isset($item->add_sql) && (int) $item->add_sql === 1 && isset($item->source))
|
||||
{
|
||||
if ($item->source == 1 && isset($item->tables) &&
|
||||
if ((int) $item->source === 1 && isset($item->tables) &&
|
||||
($string = $this->dump->get(
|
||||
$item->tables, $item->name_single_code, $item->guid
|
||||
)) !== null)
|
||||
@@ -77,7 +77,7 @@ class Sql
|
||||
$this->dispenser->hub['sql'][$item->name_single_code]
|
||||
= $string;
|
||||
}
|
||||
elseif ($item->source == 2 && isset($item->sql))
|
||||
elseif ((int) $item->source === 2 && isset($item->sql))
|
||||
{
|
||||
// add the SQL dump string
|
||||
$this->dispenser->set(
|
||||
|
@@ -199,82 +199,88 @@ class Sqldump
|
||||
else
|
||||
{
|
||||
// see where
|
||||
// var_dump($view);
|
||||
// jexit();
|
||||
// var_dump($view, $view_guid);
|
||||
// exit;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we should run query
|
||||
if ($run_query)
|
||||
{
|
||||
// now get the data
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
if ($this->db->getNumRows())
|
||||
{
|
||||
// get the data
|
||||
$data = $this->db->loadObjectList();
|
||||
|
||||
// start building the MySql dump
|
||||
$dump = "--";
|
||||
$dump .= PHP_EOL . "-- Dumping data for table `#__"
|
||||
. Placefix::_("component") . "_" . $view
|
||||
. "`";
|
||||
$dump .= PHP_EOL . "--";
|
||||
$dump .= PHP_EOL . PHP_EOL . "INSERT INTO `#__" . Placefix::_("component") . "_" . $view . "` (";
|
||||
foreach ($data as $line)
|
||||
try{
|
||||
// now get the data
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
if ($this->db->getNumRows())
|
||||
{
|
||||
$comaSet = 0;
|
||||
foreach ($line as $fieldName => $fieldValue)
|
||||
// get the data
|
||||
$data = $this->db->loadObjectList();
|
||||
|
||||
// start building the MySql dump
|
||||
$dump = "--";
|
||||
$dump .= PHP_EOL . "-- Dumping data for table `#__"
|
||||
. Placefix::_("component") . "_" . $view
|
||||
. "`";
|
||||
$dump .= PHP_EOL . "--";
|
||||
$dump .= PHP_EOL . PHP_EOL . "INSERT INTO `#__" . Placefix::_("component") . "_" . $view . "` (";
|
||||
foreach ($data as $line)
|
||||
{
|
||||
if ($comaSet == 0)
|
||||
$comaSet = 0;
|
||||
foreach ($line as $fieldName => $fieldValue)
|
||||
{
|
||||
$dump .= $this->db->quoteName($fieldName);
|
||||
if ($comaSet == 0)
|
||||
{
|
||||
$dump .= $this->db->quoteName($fieldName);
|
||||
}
|
||||
else
|
||||
{
|
||||
$dump .= ", " . $this->db->quoteName(
|
||||
$fieldName
|
||||
);
|
||||
}
|
||||
$comaSet++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$dump .= ") VALUES";
|
||||
$coma = 0;
|
||||
foreach ($data as $line)
|
||||
{
|
||||
if ($coma == 0)
|
||||
{
|
||||
$dump .= PHP_EOL . "(";
|
||||
}
|
||||
else
|
||||
{
|
||||
$dump .= ", " . $this->db->quoteName(
|
||||
$fieldName
|
||||
);
|
||||
$dump .= "," . PHP_EOL . "(";
|
||||
}
|
||||
$comaSet++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$dump .= ") VALUES";
|
||||
$coma = 0;
|
||||
foreach ($data as $line)
|
||||
{
|
||||
if ($coma == 0)
|
||||
{
|
||||
$dump .= PHP_EOL . "(";
|
||||
}
|
||||
else
|
||||
{
|
||||
$dump .= "," . PHP_EOL . "(";
|
||||
}
|
||||
$comaSet = 0;
|
||||
foreach ($line as $fieldName => $fieldValue)
|
||||
{
|
||||
if ($comaSet == 0)
|
||||
$comaSet = 0;
|
||||
foreach ($line as $fieldName => $fieldValue)
|
||||
{
|
||||
$dump .= $this->escape($fieldValue);
|
||||
if ($comaSet == 0)
|
||||
{
|
||||
$dump .= $this->escape($fieldValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$dump .= ", " . $this->escape(
|
||||
$fieldValue
|
||||
);
|
||||
}
|
||||
$comaSet++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dump .= ", " . $this->escape(
|
||||
$fieldValue
|
||||
);
|
||||
}
|
||||
$comaSet++;
|
||||
$dump .= ")";
|
||||
$coma++;
|
||||
}
|
||||
$dump .= ")";
|
||||
$coma++;
|
||||
}
|
||||
$dump .= ";";
|
||||
$dump .= ";";
|
||||
|
||||
// return build dump query
|
||||
return $dump;
|
||||
// return build dump query
|
||||
return $dump;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// see where
|
||||
// var_dump($view, $view_guid);
|
||||
// exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -78,13 +78,13 @@ class Updatesql
|
||||
{
|
||||
$newItem = true;
|
||||
|
||||
// check if this is an id to ignore
|
||||
// check if this is an id/guid to ignore
|
||||
if (ArrayHelper::check($ignore)
|
||||
&& in_array(
|
||||
$item, $ignore
|
||||
))
|
||||
{
|
||||
// don't add ignored ids
|
||||
// don't add ignored ids/guids
|
||||
$newItem = false;
|
||||
}
|
||||
// check if this is old repeatable field
|
||||
@@ -142,11 +142,11 @@ class Updatesql
|
||||
// search to see if this is a new value
|
||||
$newItem = true;
|
||||
|
||||
// check if this is an id to ignore
|
||||
// check if this is an id/guid to ignore
|
||||
if (ArrayHelper::check($ignore)
|
||||
&& in_array($item[$type], $ignore))
|
||||
{
|
||||
// don't add ignored ids
|
||||
// don't add ignored ids/guids
|
||||
$newItem = false;
|
||||
}
|
||||
// check if this is old repeatable field
|
||||
|
@@ -773,6 +773,7 @@ class Creator implements ServiceProviderInterface
|
||||
$container->get('Field.Name'),
|
||||
$container->get('Field.Type.Name'),
|
||||
$container->get('Field.Attributes'),
|
||||
$container->get('Field.ModalSelect'),
|
||||
$container->get('Utilities.Xml'),
|
||||
$container->get('Compiler.Creator.Custom.Field.Type.File'),
|
||||
$container->get('Utilities.Counter')
|
||||
@@ -797,6 +798,7 @@ class Creator implements ServiceProviderInterface
|
||||
$container->get('Field.Name'),
|
||||
$container->get('Field.Type.Name'),
|
||||
$container->get('Field.Attributes'),
|
||||
$container->get('Field.ModalSelect'),
|
||||
$container->get('Compiler.Creator.Custom.Field.Type.File'),
|
||||
$container->get('Utilities.Counter')
|
||||
);
|
||||
@@ -816,6 +818,7 @@ class Creator implements ServiceProviderInterface
|
||||
$container->get('Field.Name'),
|
||||
$container->get('Field.Type.Name'),
|
||||
$container->get('Field.Attributes'),
|
||||
$container->get('Field.ModalSelect'),
|
||||
$container->get('Field.Groups'),
|
||||
$container->get('Compiler.Builder.Field.Names'),
|
||||
$container->get('Compiler.Creator.Field.Type'),
|
||||
|
@@ -20,6 +20,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Field\Data;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\Groups;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\Attributes;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\Name;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\ModalSelect;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\TypeName;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\UniqueName;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Field\Rule;
|
||||
@@ -83,6 +84,9 @@ class Field implements ServiceProviderInterface
|
||||
$container->alias(Name::class, 'Field.Name')
|
||||
->share('Field.Name', [$this, 'getName'], true);
|
||||
|
||||
$container->alias(ModalSelect::class, 'Field.ModalSelect')
|
||||
->share('Field.ModalSelect', [$this, 'getModalSelect'], true);
|
||||
|
||||
$container->alias(TypeName::class, 'Field.Type.Name')
|
||||
->share('Field.Type.Name', [$this, 'getTypeName'], true);
|
||||
|
||||
@@ -214,6 +218,22 @@ class Field implements ServiceProviderInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The ModalSelect Class.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return ModalSelect
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public function getModalSelect(Container $container): ModalSelect
|
||||
{
|
||||
return new ModalSelect(
|
||||
$container->get('Utilities.Structure'),
|
||||
$container->get('Compiler.Builder.Content.Multi')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The TypeName Class.
|
||||
*
|
||||
|
@@ -50,7 +50,7 @@ final class RowDataArray implements RowDataProcessorInterface
|
||||
|
||||
foreach ($cellIterator as $cell)
|
||||
{
|
||||
$rowData['values'][$cell->getColumn()] = $cell->getValueString();
|
||||
$rowData['values'][$cell->getColumn()] = (string) $cell->getValue();
|
||||
}
|
||||
|
||||
return $rowData;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@ final class MultiSubform implements MultiSubformInterface
|
||||
* $items,
|
||||
* $setMap = [
|
||||
* '_core' => [
|
||||
* 'table' =>'data',
|
||||
* 'table' => 'data',
|
||||
* 'indexKey' => 'guid',
|
||||
* 'linkKey' => 'look',
|
||||
* 'linkValue' => $data['guid'] ?? ''
|
||||
|
@@ -147,36 +147,43 @@ abstract class FileHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a file to the server
|
||||
* Write a file to the server safely and efficiently.
|
||||
* This function will always overwrite the existing file with new data.
|
||||
*
|
||||
* @param string $path The path and file name where to safe the data
|
||||
* @param string $data The data to safe
|
||||
*
|
||||
* @return bool true On success
|
||||
* @param string $path The full path and file name where to save the data.
|
||||
* @param string $data The data to save.
|
||||
*
|
||||
* @return bool Returns true on success, false on failure.
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function write($path, $data): bool
|
||||
{
|
||||
$klaar = false;
|
||||
if (StringHelper::check($data))
|
||||
if (!is_string($path) || !is_string($data) || trim($path) === '')
|
||||
{
|
||||
// open the file
|
||||
$fh = fopen($path, "w");
|
||||
if (!is_resource($fh))
|
||||
{
|
||||
return $klaar;
|
||||
}
|
||||
// write to the file
|
||||
if (fwrite($fh, $data))
|
||||
{
|
||||
// has been done
|
||||
$klaar = true;
|
||||
}
|
||||
// close file.
|
||||
fclose($fh);
|
||||
return false;
|
||||
}
|
||||
return $klaar;
|
||||
|
||||
$handle = null;
|
||||
$success = false;
|
||||
|
||||
try {
|
||||
$handle = fopen($path, "wb"); // Open in write-binary mode to ensure full overwrite
|
||||
if (!is_resource($handle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = fwrite($handle, $data) !== false;
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (is_resource($handle))
|
||||
{
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -29,7 +29,14 @@ abstract class TypeHelper
|
||||
*
|
||||
* @since 3.0.9
|
||||
*/
|
||||
protected static $builder = false;
|
||||
protected static int $builder = 0;
|
||||
|
||||
/**
|
||||
* Cache for processed field type names to avoid redundant computations.
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected static array $cache = [];
|
||||
|
||||
/**
|
||||
* Making field type name safe
|
||||
@@ -41,42 +48,144 @@ abstract class TypeHelper
|
||||
*
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function safe($string, $option = null)
|
||||
public static function safe($string, $option = null): string
|
||||
{
|
||||
// get global value
|
||||
if (self::$builder === false)
|
||||
// Check if result is already cached
|
||||
if (isset(self::$cache[$string]))
|
||||
{
|
||||
self::$builder = Helper::getParams($option)->get('type_name_builder', 1);
|
||||
return self::$cache[$string];
|
||||
}
|
||||
|
||||
// use the new convention
|
||||
// get global value
|
||||
if (self::$builder == 0)
|
||||
{
|
||||
self::$builder = (int) Helper::getParams($option)->get('type_name_builder', 2);
|
||||
}
|
||||
|
||||
// Apply new naming convention
|
||||
if (2 == self::$builder)
|
||||
{
|
||||
// 0nly continue if we have a string
|
||||
// Ensure input is a valid string
|
||||
if (StringHelper::check($string))
|
||||
{
|
||||
// check that the first character is not a number
|
||||
// Ensure the first character is not a number
|
||||
if (is_numeric(substr($string, 0, 1)))
|
||||
{
|
||||
$string = StringHelper::numbers($string);
|
||||
}
|
||||
|
||||
// Transliterate string
|
||||
$string = StringHelper::transliterate($string);
|
||||
// Detect if camel case is used
|
||||
$has_camel_case = preg_match('/[a-z][A-Z]/', $string);
|
||||
|
||||
// remove all and keep only characters and numbers and point (TODO just one point)
|
||||
$string = trim(preg_replace("/[^A-Za-z0-9_\.]/", '', (string) $string));
|
||||
// Detect non-ASCII characters (extended Unicode)
|
||||
$has_non_ascii = preg_match('/[^\x20-\x7E]/', $string); // Anything outside printable ASCII
|
||||
|
||||
// best is to return lower (for all string equality in compiler)
|
||||
return strtolower($string);
|
||||
// Detect non-standard symbols (anything that is not a letter, number, underscore, or dot)
|
||||
$has_non_standard_symbols = preg_match('/[^a-zA-Z0-9_.]/', $string);
|
||||
|
||||
// Only transliterate if necessary:
|
||||
// - If it contains non-ASCII characters, or
|
||||
// - If it has non-standard symbols that may affect safe usage
|
||||
if ($has_non_ascii || $has_non_standard_symbols)
|
||||
{
|
||||
// Store original casing before transliteration
|
||||
$original_casing = $string;
|
||||
|
||||
// Run transliteration
|
||||
$string = StringHelper::transliterate($string);
|
||||
|
||||
// If original had camel case and transliterate altered casing, restore it
|
||||
if ($has_camel_case)
|
||||
{
|
||||
// Use original casing where possible, as Joomla's transliteration might enforce lowercase
|
||||
$string = self::restoreCamelCase($original_casing, $string);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean the string while preserving camelCase
|
||||
$cleaned = self::clean($string);
|
||||
|
||||
// Cache the result
|
||||
self::$cache[$string] = $cleaned;
|
||||
|
||||
return $cleaned;
|
||||
}
|
||||
// not a string
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// use the default (original behaviour/convention)
|
||||
return StringHelper::safe($string);
|
||||
// Default behaviour for legacy convention
|
||||
$result = StringHelper::safe($string);
|
||||
|
||||
// Cache the result
|
||||
self::$cache[$string] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restores the camel case pattern from the original string after transliteration.
|
||||
*
|
||||
* @param string $original The original string before transliteration.
|
||||
* @param string $modified The string after transliteration.
|
||||
*
|
||||
* @return string The string with restored camel case.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected static function restoreCamelCase(string $original, string $modified): string
|
||||
{
|
||||
// Split original and modified strings into character arrays
|
||||
$origChars = preg_split('//u', $original, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$modChars = preg_split('//u', $modified, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
// Ensure lengths match before processing
|
||||
if (count($origChars) !== count($modChars))
|
||||
{
|
||||
return $modified; // Return as-is if lengths differ (indicating complex transformation)
|
||||
}
|
||||
|
||||
// Restore camel case where applicable
|
||||
foreach ($origChars as $index => $char)
|
||||
{
|
||||
if (ctype_upper($char))
|
||||
{
|
||||
$modChars[$index] = strtoupper($modChars[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
return implode('', $modChars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans type name string by:
|
||||
* - Removing all characters except letters, numbers, underscores, and periods.
|
||||
* - Allowing only one period (the first period in the string).
|
||||
*
|
||||
* @param string $string Type name string to clean.
|
||||
*
|
||||
* @return string Cleaned string with only one period (first occurrence).
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected static function clean(string $string): string
|
||||
{
|
||||
// Step 1: Remove unwanted characters (allow letters, numbers, underscores, and periods)
|
||||
$string = preg_replace('/[^A-Za-z0-9_.]/', '', $string);
|
||||
|
||||
// Step 2: Keep only the first period, remove all subsequent periods
|
||||
$parts = explode('.', $string, 2); // Split on first period only
|
||||
|
||||
if (count($parts) === 2)
|
||||
{
|
||||
// Reconstruct string: first part + '.' + remove any further periods from second part
|
||||
$cleaned_string = $parts[0] . '.' . str_replace('.', '', $parts[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No period or just one part, no further action needed
|
||||
$cleaned_string = $string;
|
||||
}
|
||||
|
||||
return trim($cleaned_string);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -12,8 +12,10 @@
|
||||
namespace VDM\Joomla\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\Filter\InputFilter;
|
||||
use Joomla\CMS\Language\Language;
|
||||
use Joomla\CMS\Language\LanguageFactoryInterface;
|
||||
use Joomla\CMS\Language\LanguageFactory;
|
||||
use VDM\Joomla\Utilities\Component\Helper;
|
||||
|
||||
|
||||
@@ -27,188 +29,219 @@ abstract class StringHelper
|
||||
/**
|
||||
* The Main Active Language
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @var string
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static $langTag;
|
||||
|
||||
/**
|
||||
* Check if we have a string with a length
|
||||
* Validate that input is a non-empty, non-whitespace-only string.
|
||||
*
|
||||
* @input string $string The string to check
|
||||
* @param mixed $input The input value to validate.
|
||||
*
|
||||
* @returns bool true on success
|
||||
*
|
||||
* @returns bool True if input is a non-empty, non-whitespace-only string, otherwise false.
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function check($string): bool
|
||||
public static function check($input): bool
|
||||
{
|
||||
return is_string($string) && strlen($string) > 0;
|
||||
return is_string($input) && trim($input) !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten a string
|
||||
* Shortens a string to a specified length, optionally adding a tooltip with the full text.
|
||||
*
|
||||
* @input string The sting that you would like to shorten
|
||||
* This method safely shortens the input string without cutting words abruptly. If the string
|
||||
* exceeds the specified length, ellipses (...) are added. Optionally, a tooltip containing the
|
||||
* longer original string can be included.
|
||||
*
|
||||
* @returns string on success
|
||||
*
|
||||
* @since 3.2.0
|
||||
* @param mixed $string The string you would like to shorten.
|
||||
* @param int $length The maximum length for the shortened string. Default is 40.
|
||||
* @param bool $addTip Whether to add a tooltip with the original longer string. Default true.
|
||||
*
|
||||
* @return string|mixed The shortened string, optionally with a tooltip. Or original value passed
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static function shorten($string, $length = 40, $addTip = true)
|
||||
public static function shorten($string, int $length = 40, bool $addTip = true)
|
||||
{
|
||||
if (self::check($string))
|
||||
// Validate string input and return original if invalid or short enough.
|
||||
if (!self::check($string) || mb_strlen($string) <= $length)
|
||||
{
|
||||
$initial = strlen((string) $string);
|
||||
$words = preg_split('/([\s\n\r]+)/', (string) $string, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$words_count = count((array)$words);
|
||||
|
||||
$word_length = 0;
|
||||
$last_word = 0;
|
||||
for (; $last_word < $words_count; ++$last_word)
|
||||
{
|
||||
$word_length += strlen($words[$last_word]);
|
||||
if ($word_length > $length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$newString = implode(array_slice($words, 0, $last_word));
|
||||
$final = strlen($newString);
|
||||
if ($initial !== $final && $addTip)
|
||||
{
|
||||
$title = self::shorten($string, 400 , false);
|
||||
return '<span class="hasTip" title="' . $title . '" style="cursor:help">' . trim($newString) . '...</span>';
|
||||
}
|
||||
elseif ($initial !== $final && !$addTip)
|
||||
{
|
||||
return trim($newString) . '...';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
return $string;
|
||||
|
||||
// Truncate string to nearest word boundary
|
||||
$shortened = mb_substr($string, 0, $length);
|
||||
|
||||
// Find the last space to avoid cutting off a word
|
||||
$lastSpace = mb_strrpos($shortened, ' ');
|
||||
if ($lastSpace !== false)
|
||||
{
|
||||
$shortened = mb_substr($shortened, 0, $lastSpace);
|
||||
}
|
||||
|
||||
// Prepare trimmed and shortened output with ellipses
|
||||
$shortened = trim($shortened) . '...';
|
||||
|
||||
// Add tooltip if requested
|
||||
if ($addTip)
|
||||
{
|
||||
// Safely escape output for HTML
|
||||
$title = self::shorten($string, 400 , false);
|
||||
$escapedTitle = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
|
||||
$escapedShort = htmlspecialchars($shortened, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
return '<span class="hasTip" title="' . $escapedTitle . '" style="cursor:help">'
|
||||
. $escapedShort
|
||||
. '</span>';
|
||||
}
|
||||
|
||||
// Return shortened version without tooltip
|
||||
return $shortened;
|
||||
}
|
||||
|
||||
/**
|
||||
* Making strings safe (various ways)
|
||||
* Makes a string safe by sanitizing and formatting it according to the specified type.
|
||||
*
|
||||
* @input string The you would like to make safe
|
||||
* This method can remove unwanted characters, transliterate text, replace numbers with
|
||||
* their English equivalents, and apply different case formatting styles.
|
||||
*
|
||||
* @returns string on success
|
||||
*
|
||||
* @param string $string The string to sanitize and format.
|
||||
* @param string $type The formatting type to apply. Supported values:
|
||||
* - 'filename' : Removes special characters and extra spaces.
|
||||
* - 'L' : Converts to lowercase with underscores replacing spaces.
|
||||
* - 'strtolower': Alias for 'L'.
|
||||
* - 'W' : Capitalizes the first letter of each word.
|
||||
* - 'w' : Converts to lowercase (spaces remain).
|
||||
* - 'word' : Alias for 'w'.
|
||||
* - 'Ww' : Capitalizes only the first word.
|
||||
* - 'Word' : Alias for 'Ww'.
|
||||
* - 'WW' : Converts the entire string to uppercase.
|
||||
* - 'WORD' : Alias for 'WW'.
|
||||
* - 'U' : Converts to uppercase with underscores replacing spaces.
|
||||
* - 'strtoupper': Alias for 'U'.
|
||||
* - 'F' : Capitalizes only the first letter of the entire string.
|
||||
* - 'ucfirst' : Alias for 'F'.
|
||||
* - 'cA' : Converts to camelCase.
|
||||
* - 'cAmel' : Alias for 'cA'.
|
||||
* - 'camelcase' : Alias for 'cA'.
|
||||
* @param string $spacer The character to replace spaces with (default: '_').
|
||||
* @param bool $replaceNumbers Whether to replace numbers with their English text equivalents (default: true).
|
||||
* @param bool $keepOnlyCharacters Whether to remove all non-alphabetic characters (default: true).
|
||||
*
|
||||
* @return string The sanitized and formatted string.
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function safe($string, $type = 'L', $spacer = '_', $replaceNumbers = true, $keepOnlyCharacters = true)
|
||||
public static function safe($string, string $type = 'L', string $spacer = '_', bool $replaceNumbers = true, bool $keepOnlyCharacters = true): string
|
||||
{
|
||||
if ($replaceNumbers === true)
|
||||
if ($replaceNumbers)
|
||||
{
|
||||
// remove all numbers and replace with English text version (works well only up to millions)
|
||||
$string = self::numbers($string);
|
||||
}
|
||||
// 0nly continue if we have a string
|
||||
if (self::check($string))
|
||||
{
|
||||
// create file name without the extension that is safe
|
||||
if ($type === 'filename')
|
||||
{
|
||||
// make sure VDM is not in the string
|
||||
$string = str_replace('VDM', 'vDm', (string) $string);
|
||||
// Remove anything which isn't a word, whitespace, number
|
||||
// or any of the following caracters -_()
|
||||
// If you don't need to handle multi-byte characters
|
||||
// you can use preg_replace rather than mb_ereg_replace
|
||||
// Thanks @Łukasz Rysiak!
|
||||
// $string = mb_ereg_replace("([^\w\s\d\-_\(\)])", '', $string);
|
||||
$string = preg_replace("([^\w\s\d\-_\(\)])", '', $string);
|
||||
|
||||
// http://stackoverflow.com/a/2021729/1429677
|
||||
return preg_replace('/\s+/', ' ', (string) $string);
|
||||
}
|
||||
// remove all other characters
|
||||
$string = trim((string) $string);
|
||||
$string = preg_replace('/'.$spacer.'+/', ' ', $string);
|
||||
$string = preg_replace('/\s+/', ' ', $string);
|
||||
// Transliterate string
|
||||
$string = self::transliterate($string);
|
||||
// remove all and keep only characters
|
||||
if ($keepOnlyCharacters)
|
||||
{
|
||||
$string = preg_replace("/[^A-Za-z ]/", '', (string) $string);
|
||||
}
|
||||
// keep both numbers and characters
|
||||
else
|
||||
{
|
||||
$string = preg_replace("/[^A-Za-z0-9 ]/", '', (string) $string);
|
||||
}
|
||||
// select final adaptations
|
||||
if ($type === 'L' || $type === 'strtolower')
|
||||
{
|
||||
// replace white space with underscore
|
||||
$string = preg_replace('/\s+/', (string) $spacer, (string) $string);
|
||||
// default is to return lower
|
||||
return strtolower($string);
|
||||
}
|
||||
elseif ($type === 'W')
|
||||
{
|
||||
// return a string with all first letter of each word uppercase(no underscore)
|
||||
return ucwords(strtolower($string));
|
||||
}
|
||||
elseif ($type === 'w' || $type === 'word')
|
||||
{
|
||||
// return a string with all lowercase(no underscore)
|
||||
return strtolower($string);
|
||||
}
|
||||
elseif ($type === 'Ww' || $type === 'Word')
|
||||
{
|
||||
// return a string with first letter of the first word uppercase and all the rest lowercase(no underscore)
|
||||
return ucfirst(strtolower($string));
|
||||
}
|
||||
elseif ($type === 'WW' || $type === 'WORD')
|
||||
{
|
||||
// return a string with all the uppercase(no underscore)
|
||||
return strtoupper($string);
|
||||
}
|
||||
elseif ($type === 'U' || $type === 'strtoupper')
|
||||
{
|
||||
// replace white space with underscore
|
||||
$string = preg_replace('/\s+/', (string) $spacer, $string);
|
||||
// return all upper
|
||||
return strtoupper($string);
|
||||
}
|
||||
elseif ($type === 'F' || $type === 'ucfirst')
|
||||
{
|
||||
// replace white space with underscore
|
||||
$string = preg_replace('/\s+/', (string) $spacer, $string);
|
||||
// return with first character to upper
|
||||
return ucfirst(strtolower($string));
|
||||
}
|
||||
elseif ($type === 'cA' || $type === 'cAmel' || $type === 'camelcase')
|
||||
{
|
||||
// convert all words to first letter uppercase
|
||||
$string = ucwords(strtolower($string));
|
||||
// remove white space
|
||||
$string = preg_replace('/\s+/', '', $string);
|
||||
// now return first letter lowercase
|
||||
return lcfirst($string);
|
||||
}
|
||||
// return string
|
||||
return $string;
|
||||
// Only continue if we have a string
|
||||
if (!self::check($string))
|
||||
{
|
||||
// not a string
|
||||
return '';
|
||||
}
|
||||
// not a string
|
||||
return '';
|
||||
|
||||
// create file name without the extension that is safe
|
||||
if ($type === 'filename')
|
||||
{
|
||||
// make sure VDM is not in the string
|
||||
$string = str_replace('VDM', 'vDm', (string) $string);
|
||||
// Remove anything which isn't a word, whitespace, number
|
||||
// or any of the following caracters -_()
|
||||
// If you don't need to handle multi-byte characters
|
||||
// you can use preg_replace rather than mb_ereg_replace
|
||||
// Thanks @Łukasz Rysiak!
|
||||
// $string = mb_ereg_replace("([^\w\s\d\-_\(\)])", '', $string);
|
||||
$string = preg_replace("([^\w\s\d\-_\(\)])", '', $string);
|
||||
|
||||
// http://stackoverflow.com/a/2021729/1429677
|
||||
return preg_replace('/\s+/', ' ', (string) $string);
|
||||
}
|
||||
// remove all other characters
|
||||
$string = trim((string) $string);
|
||||
$string = preg_replace('/'.$spacer.'+/', ' ', $string);
|
||||
$string = preg_replace('/\s+/', ' ', $string);
|
||||
// Transliterate string
|
||||
$string = self::transliterate($string);
|
||||
// remove all and keep only characters
|
||||
if ($keepOnlyCharacters)
|
||||
{
|
||||
$string = preg_replace("/[^A-Za-z ]/", '', (string) $string);
|
||||
}
|
||||
// keep both numbers and characters
|
||||
else
|
||||
{
|
||||
$string = preg_replace("/[^A-Za-z0-9 ]/", '', (string) $string);
|
||||
}
|
||||
// select final adaptations
|
||||
if ($type === 'L' || $type === 'strtolower')
|
||||
{
|
||||
// replace white space with underscore
|
||||
$string = preg_replace('/\s+/', (string) $spacer, (string) $string);
|
||||
// default is to return lower
|
||||
return strtolower($string);
|
||||
}
|
||||
elseif ($type === 'W')
|
||||
{
|
||||
// return a string with all first letter of each word uppercase(no underscore)
|
||||
return ucwords(strtolower($string));
|
||||
}
|
||||
elseif ($type === 'w' || $type === 'word')
|
||||
{
|
||||
// return a string with all lowercase(no underscore)
|
||||
return strtolower($string);
|
||||
}
|
||||
elseif ($type === 'Ww' || $type === 'Word')
|
||||
{
|
||||
// return a string with first letter of the first word uppercase and all the rest lowercase(no underscore)
|
||||
return ucfirst(strtolower($string));
|
||||
}
|
||||
elseif ($type === 'WW' || $type === 'WORD')
|
||||
{
|
||||
// return a string with all the uppercase(no underscore)
|
||||
return strtoupper($string);
|
||||
}
|
||||
elseif ($type === 'U' || $type === 'strtoupper')
|
||||
{
|
||||
// replace white space with underscore
|
||||
$string = preg_replace('/\s+/', (string) $spacer, $string);
|
||||
// return all upper
|
||||
return strtoupper($string);
|
||||
}
|
||||
elseif ($type === 'F' || $type === 'ucfirst')
|
||||
{
|
||||
// replace white space with underscore
|
||||
$string = preg_replace('/\s+/', (string) $spacer, $string);
|
||||
// return with first character to upper
|
||||
return ucfirst(strtolower($string));
|
||||
}
|
||||
elseif ($type === 'cA' || $type === 'cAmel' || $type === 'camelcase')
|
||||
{
|
||||
// convert all words to first letter uppercase
|
||||
$string = ucwords(strtolower($string));
|
||||
// remove white space
|
||||
$string = preg_replace('/\s+/', '', $string);
|
||||
// now return first letter lowercase
|
||||
return lcfirst($string);
|
||||
}
|
||||
// return string
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert none English strings to code usable string
|
||||
*
|
||||
* @input an string
|
||||
* @input $string an string
|
||||
*
|
||||
* @returns a string
|
||||
*
|
||||
* @since 3.0.9
|
||||
* @returns string
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function transliterate($string)
|
||||
public static function transliterate($string): string
|
||||
{
|
||||
// set tag only once
|
||||
if (!self::check(self::$langTag))
|
||||
@@ -217,22 +250,31 @@ abstract class StringHelper
|
||||
self::$langTag = Helper::getParams()->get('language', 'en-GB');
|
||||
}
|
||||
|
||||
// Transliterate on the language requested
|
||||
$lang = Language::getInstance(self::$langTag);
|
||||
/** @var $langFactory LanguageFactory **/
|
||||
$langFactory = Factory::getContainer()->get(LanguageFactoryInterface::class);
|
||||
$lang = $langFactory->createLanguage(self::$langTag);
|
||||
|
||||
// Transliterate on the language requested
|
||||
return $lang->transliterate($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* make sure a string is HTML save
|
||||
* Ensures a string is safe for HTML output by encoding entities and applying an input filter.
|
||||
*
|
||||
* @input an html string
|
||||
* This method sanitizes the input string, converting special characters to HTML entities
|
||||
* and applying Joomla's `InputFilter` to remove potentially unsafe HTML.
|
||||
* Optionally, it can also shorten the string while preserving word integrity.
|
||||
*
|
||||
* @returns a string
|
||||
*
|
||||
* @since 3.0.9
|
||||
* @param string $var The input string containing HTML content.
|
||||
* @param string $charset The character set to use for encoding (default: 'UTF-8').
|
||||
* @param bool $shorten Whether to shorten the string to a specified length (default: false).
|
||||
* @param int $length The maximum length for shortening, if enabled (default: 40).
|
||||
* @param bool $addTip Whether to append a tooltip (ellipsis) when shortening (default: true).
|
||||
*
|
||||
* @return string The sanitized and optionally shortened HTML-safe string.
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function html($var, $charset = 'UTF-8', $shorten = false, $length = 40, $addTip = true)
|
||||
public static function html($var, $charset = 'UTF-8', $shorten = false, $length = 40, $addTip = true): string
|
||||
{
|
||||
if (self::check($var))
|
||||
{
|
||||
@@ -262,13 +304,12 @@ abstract class StringHelper
|
||||
/**
|
||||
* Convert all int in a string to an English word string
|
||||
*
|
||||
* @input an string with numbers
|
||||
* @input $string an string with numbers
|
||||
*
|
||||
* @returns a string
|
||||
*
|
||||
* @returns string|null
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function numbers($string)
|
||||
public static function numbers($string): ?string
|
||||
{
|
||||
// set numbers array
|
||||
$numbers = [];
|
||||
@@ -300,19 +341,19 @@ abstract class StringHelper
|
||||
* Convert an integer into an English word string
|
||||
* Thanks to Tom Nicholson <http://php.net/manual/en/function.strval.php#41988>
|
||||
*
|
||||
* @input an int
|
||||
* @returns a string
|
||||
* @input $x an int
|
||||
*
|
||||
* @returns string
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function number($x)
|
||||
{
|
||||
$nwords = array( "zero", "one", "two", "three", "four", "five", "six", "seven",
|
||||
$nwords = ["zero", "one", "two", "three", "four", "five", "six", "seven",
|
||||
"eight", "nine", "ten", "eleven", "twelve", "thirteen",
|
||||
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
|
||||
"nineteen", "twenty", 30 => "thirty", 40 => "forty",
|
||||
50 => "fifty", 60 => "sixty", 70 => "seventy", 80 => "eighty",
|
||||
90 => "ninety" );
|
||||
90 => "ninety"];
|
||||
|
||||
if(!is_numeric($x))
|
||||
{
|
||||
@@ -372,7 +413,7 @@ abstract class StringHelper
|
||||
}
|
||||
}
|
||||
else // millions
|
||||
{
|
||||
{
|
||||
$w .= self::number(floor($x/1000000)) .' million';
|
||||
$r = fmod($x, 1000000);
|
||||
if($r > 0)
|
||||
@@ -392,9 +433,9 @@ abstract class StringHelper
|
||||
/**
|
||||
* Random Key
|
||||
*
|
||||
* @input int $size The size of the random string
|
||||
* @input int $size The size of the random string
|
||||
*
|
||||
* @returns a string
|
||||
* @returns string
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static function random(int $size): string
|
||||
|
Reference in New Issue
Block a user