Update on v5.1.0-rc1 (changes towards the next release)

Here's an update on the current version, which includes changes towards the next release still in development.
This commit is contained in:
Robot 2025-02-04 18:32:29 +02:00
parent 408cac8dbd
commit 0321f9c469
Signed by: Robot
GPG Key ID: 14DECD44E7E1BB95
8 changed files with 386 additions and 255 deletions

View File

@ -148,7 +148,7 @@ TODO
+ *Version*: 5.1.0-rc1
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **926174**
+ *Line count*: **926305**
+ *Field count*: **2106**
+ *File count*: **6387**
+ *Folder count*: **640**

View File

@ -148,7 +148,7 @@ TODO
+ *Version*: 5.1.0-rc1
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **926174**
+ *Line count*: **926305**
+ *Field count*: **2106**
+ *File count*: **6387**
+ *Folder count*: **640**

View File

@ -53,7 +53,7 @@
type="list"
label="JGLOBAL_SORT_BY"
class="js-select-submit-on-change"
default="a.id desc"
default=" desc"
validate="options"
>
<option value="">JGLOBAL_SORT_BY</option>

View File

@ -1208,7 +1208,7 @@ class AjaxController extends BaseController
case 'viewTableColumns':
try
{
$idValue = $jinput->get('id', NULL, 'INT');
$idValue = $jinput->get('id', NULL, 'STRING');
$asValue = $jinput->get('as', NULL, 'WORD');
$typeValue = $jinput->get('type', NULL, 'INT');
if($idValue && $user->id != 0 && $asValue && $typeValue)
@ -1259,7 +1259,7 @@ class AjaxController extends BaseController
case 'getDynamicValues':
try
{
$idValue = $jinput->get('id', NULL, 'INT');
$idValue = $jinput->get('id', NULL, 'STRING');
$viewValue = $jinput->get('view', NULL, 'WORD');
if($idValue && $user->id != 0 && $viewValue)
{

View File

@ -3082,255 +3082,369 @@ class AjaxModel extends ListModel
}
// Used in dynamic_get
public function getViewTableColumns($admin_view, $as, $type)
/**
* Retrieve view table columns.
*
* @param string $adminView The admin view identifier.
* @param string $as The alias to use.
* @param int $type The type indicator.
*
* @return mixed The view table columns.
* @since 3.0.0
*/
public function getViewTableColumns($adminView, $as, $type)
{
return ComponentbuilderHelper::getViewTableColumns($admin_view, $as, $type);
return ComponentbuilderHelper::getViewTableColumns($adminView, $as, $type);
}
/**
* Retrieve database table columns.
*
* @param string $tableName The name of the database table.
* @param string $as The alias to use.
* @param int $type The type indicator.
*
* @return mixed The database table columns.
* @since 3.0.0
*/
public function getDbTableColumns($tableName, $as, $type)
{
return ComponentbuilderHelper::getDbTableColumns($tableName, $as, $type);
}
public function getDynamicValues($id, $view)
/**
* Retrieve dynamic values based on a key and view.
*
* The method builds a database query to retrieve dynamic settings, processes main and joined
* selections, and returns an HTML code snippet that shows PHP code for outputting these fields.
*
* @param mixed $key The key used to fetch dynamic values (can be a guid or numeric id).
* @param string $view The view context (e.g., 'template', 'site_view', 'custom_admin_view', 'layout').
*
* @return string|null HTML code snippet with dynamic value output or false if key is invalid or no rows found.
* @since 3.0.0
*/
public function getDynamicValues($key, $view)
{
// Get a db connection.
// Determine the target field based on the key.
if (GuidHelper::valid($key))
{
$target = 'guid';
}
elseif (is_numeric($key))
{
$target = 'id';
}
else
{
return null;
}
// Get a database connection.
$db = Factory::getDbo();
// Create a new query object.
// Build the query.
$query = $db->getQuery(true);
$query->select($db->quoteName(array('getcustom', 'gettype', 'select_all', 'db_table_main', 'view_table_main', 'main_source', 'view_selection', 'db_selection', 'join_view_table', 'join_db_table', 'addcalculation', 'php_calculation')));
$query->from($db->quoteName('#__componentbuilder_dynamic_get'));
$query->where($db->quoteName('published') . ' = 1');
$query->where($db->quoteName('id') . ' = ' . (int) $id);
$fields = [
'getcustom', 'gettype', 'select_all', 'db_table_main',
'view_table_main', 'main_source', 'view_selection',
'db_selection', 'join_view_table', 'join_db_table',
'addcalculation', 'php_calculation'
];
// Reset the query using our newly populated query object.
$query->select($db->quoteName($fields))
->from($db->quoteName('#__componentbuilder_dynamic_get'))
->where($db->quoteName('published') . ' = 1')
->where($db->quoteName($target) . ' = ' . $db->quote($key));
$db->setQuery($query);
$db->execute();
if ($db->getNumRows())
if (!$db->getNumRows())
{
$result = $db->loadObject();
// reset buket
$selections = array();
$selectionsList = array();
// get the main values (name)
if ($result->main_source == 1)
return null;
}
$result = $db->loadObject();
// Initialize selection arrays.
$selections = [];
$selectionsList = [];
// Process main source selections.
if ($result->main_source == 1)
{
if ($result->select_all == 1)
{
if ($result->select_all == 1)
$result->view_selection = ComponentbuilderHelper::getViewTableColumns($result->view_table_main, 'a', $result->gettype);
}
$selections[] = explode("\n", $result->view_selection);
}
elseif ($result->main_source == 2)
{
if ($result->select_all == 1)
{
$result->db_selection = ComponentbuilderHelper::getDbTableColumns($result->db_table_main, 'a', $result->gettype);
}
$selections[] = explode("\n", $result->db_selection);
}
elseif ($result->main_source == 3)
{
return '<br /><br /><h2>Custom get source! You will need to transpose the variables manually.</h2>';
}
// Process joined view table selections.
$joinViewTable = json_decode($result->join_view_table, true);
if (UtilitiesArrayHelper::check($joinViewTable))
{
list($joinSelections, $joinSelectionsList) = $this->processJoinTables($joinViewTable, true);
$selections = array_merge($selections, $joinSelections);
$selectionsList = array_merge($selectionsList, $joinSelectionsList);
}
// Process joined database table selections.
$joinDbTable = json_decode($result->join_db_table, true);
if (UtilitiesArrayHelper::check($joinDbTable))
{
list($joinSelections, $joinSelectionsList) = $this->processJoinTables($joinDbTable, false);
$selections = array_merge($selections, $joinSelections);
$selectionsList = array_merge($selectionsList, $joinSelectionsList);
}
// Process calculation selections.
if ($result->addcalculation == 1)
{
$phpCalculation = base64_decode($result->php_calculation);
$phpSelections = GetHelper::allBetween($phpCalculation, 'cal__', ' ');
$selections[] = array_unique($phpSelections);
unset($phpCalculation, $phpSelections, $result->php_calculation);
}
// Determine the bucket variable name based on view and get type.
$buketName = $this->determineBucketName($result, $view);
if (empty($buketName))
{
return null;
}
// Build and return the final HTML code snippet.
return $this->buildCodeOutput($result->gettype, $buketName, $selections, $selectionsList);
}
/**
* Process join tables for dynamic selections.
*
* This method iterates over an array of join table configurations, replacing '*' selections
* with full column lists and sorting the results into main selections and selection lists.
*
* @param array $joinTables An array of join table configurations.
* @param bool $isView True if processing view tables; false if processing DB tables.
*
* @return array Returns an array with two elements: [selections, selectionsList].
* @since 5.0.4
*/
protected function processJoinTables(array $joinTables, bool $isView): array
{
$selections = [];
$selectionsList = [];
foreach ($joinTables as $join)
{
// Replace '*' with full selection if applicable.
if (strpos($join['selection'], '*') !== false)
{
$join['selection'] = ComponentbuilderHelper::getViewTableColumns($join['view_table'], $join['as'], $join['row_type']);
}
// Process based on the row type.
if ($join['row_type'] == '1')
{
$selections[] = explode("\n", $join['selection']);
}
elseif ($join['row_type'] == '2')
{
$names = $this->setListMethodName(
[$join['on_field'], $join['join_field']],
$isView ? $join['view_table'] : $join['db_table'],
$join['as'],
$isView ? 1 : 2
);
$selectionsList[implode('', $names)] = explode("\n", $join['selection']);
}
}
return [$selections, $selectionsList];
}
/**
* Determine the bucket variable name based on the result type and view.
*
* This method selects the proper variable (e.g. "$this->item" or "$this->items")
* or a custom bucket name based on the provided result and view context.
*
* @param object $result The result object from the database query.
* @param string $view The view context.
*
* @return string|null The bucket variable name (or an empty string if none can be determined).
* @since 5.0.4
*/
protected function determineBucketName($result, string $view): ?string
{
if (in_array($view, ['template', 'site_view', 'custom_admin_view'], true))
{
switch ($result->gettype) {
case 1:
return 'this->item';
case 2:
return 'this->items';
case 3:
case 4:
$custom = StringHelper::safe($result->getcustom);
$varName = (strpos($custom, 'get') === 0) ? substr($custom, 3) : $custom;
return 'this->' . $varName;
default:
return null;
}
}
elseif ($view === 'layout')
{
return 'displayData';
}
return null;
}
/**
* Build the HTML code output for dynamic selections.
*
* This method generates HTML code snippets (using <code> blocks) that output the
* dynamic selection values based on the get type. For list types, it wraps the output
* in a foreach loop.
*
* @param int $getType The type of get operation.
* @param string $buketName The bucket variable name.
* @param array $selections An array of selections.
* @param array $selectionsList An array of selection lists.
*
* @return string The HTML code snippet.
* @since 5.0.4
*/
protected function buildCodeOutput(int $getType, string $buketName, array $selections, array $selectionsList): string
{
$outputLines = [];
// Set the starting code based on the get type.
switch ($getType)
{
case 1:
case 3:
$prefix = '&lt;?php echo $' . $buketName;
$suffix = '; ?&gt;';
break;
case 2:
case 4:
$prefix = '&lt;?php echo $item';
$suffix = '; ?&gt;';
$outputLines[] = '<code>&lt;?php foreach ($' . $buketName . ' as $item): ?&gt;</code><br />';
break;
default:
$prefix = '';
$suffix = '';
}
// Build code lines for the main selections.
foreach ($selections as $selection)
{
if (UtilitiesArrayHelper::check($selection))
{
foreach ($selection as $value)
{
$result->view_selection = ComponentbuilderHelper::getViewTableColumns($result->view_table_main, 'a', $result->gettype);
}
$selections[] = explode("\n", $result->view_selection);
}
elseif ($result->main_source == 2)
{
if ($result->select_all == 1)
{
$result->db_selection = ComponentbuilderHelper::getDbTableColumns($result->db_table_main, 'a', $result->gettype);
}
$selections[] = explode("\n", $result->db_selection);
}
elseif ($result->main_source == 3)
{
return '<br /><br /><h2>Custom get source! You will need to transpose the variables manually.</h2>';
}
// get the joined values (name)
$result->join_view_table = json_decode($result->join_view_table, true);
if (!UtilitiesArrayHelper::check($result->join_view_table))
{
unset($result->join_view_table);
}
$result->join_db_table = json_decode($result->join_db_table, true);
if (!UtilitiesArrayHelper::check($result->join_db_table))
{
unset($result->join_db_table);
}
// now load the joined values to the selection set
if (isset($result->join_view_table) && UtilitiesArrayHelper::check($result->join_view_table))
{
foreach ($result->join_view_table as $join_view_table)
{
// check if all is selected
if (strpos($join_view_table['selection'], '*') !== false)
$value = trim($value);
if (strpos($value, 'AS') !== false)
{
$join_view_table['selection'] = ComponentbuilderHelper::getViewTableColumns($join_view_table['view_table'], $join_view_table['as'], $join_view_table['row_type']);
}
// build selection
if ($join_view_table['row_type'] == '1')
{
$selections[] = explode("\n", $join_view_table['selection']);
}
elseif ($join_view_table['row_type'] == '2')
{
$names = $this->setListMethodName(array($join_view_table['on_field'],$join_view_table['join_field']),$join_view_table['view_table'],$join_view_table['as'],1);
$selectionsList[implode('',$names)] = explode("\n", $join_view_table['selection']);
}
}
unset($result->join_view_table);
}
if (isset($result->join_db_table) && UtilitiesArrayHelper::check($result->join_db_table))
{
foreach ($result->join_db_table as $join_db_table)
{
// check if all is selected
if (strpos($join_db_table['selection'], '*') !== false)
{
$join_db_table['selection'] = ComponentbuilderHelper::getViewTableColumns($join_db_table['view_table'], $join_db_table['as'], $join_db_table['row_type']);
}
// build selections
if ($join_db_table['row_type'] == '1')
{
$selections[] = explode("\n", $join_db_table['selection']);
}
elseif ($join_db_table['row_type'] == '2')
{
$names = $this->setListMethodName(array($join_db_table['on_field'],$join_db_table['join_field']),$join_db_table['db_table'],$join_db_table['as'],2);
$selectionsList[implode('',$names)] = explode("\n", $join_db_table['selection']);
}
}
unset($result->join_db_table);
}
// get the calculation result values (name)
if ($result->addcalculation == 1)
{
$php_calculation = base64_decode($result->php_calculation);
$phpSelections = GetHelper::allBetween($php_calculation,'cal__',' ');
$selections[] = array_unique($phpSelections);
unset($php_calculation);
unset($phpSelections);
unset($result->php_calculation);
}
// name the main var based on view
if ('template' === $view || 'site_view' === $view || 'custom_admin_view' === $view)
{
switch ($result->gettype)
{
case 1:
// single
$buketName = 'this->item';
break;
case 2:
// list
$buketName = 'this->items';
break;
case 3:
case 4:
// custom
$result->getcustom = StringHelper::safe($result->getcustom);
if (substr($result->getcustom, 0, strlen('get')) == 'get')
{
$varName = substr($result->getcustom, strlen('get'));
list(, $key) = explode('AS', $value);
$outputLines[] = '<code>' . $prefix . '->' . trim($key) . $suffix . '</code>';
}
else
{
$varName = $result->getcustom;
$outputLines[] = '<code>' . $prefix . '->' . $value . $suffix . '</code>';
}
$buketName = 'this->'.$varName;
break;
}
}
elseif ($view == 'layout')
{
$buketName = 'displayData';
}
// now build the return values
if (UtilitiesArrayHelper::check($selections))
{
$buket = array();
switch ($result->gettype)
{
case 1:
case 3:
// single
$ur = '&lt;?php echo $'.$buketName;
$cf = '; ?&gt;';
break;
case 2:
case 4:
// list
$ur = '&lt;?php echo $item';
$cf = '; ?&gt;';
$buket[] = '<code>&lt;?php foreach ($'.$buketName.' as $item): ?&gt;</code><br />';
break;
}
foreach ($selections as $selection)
{
if (UtilitiesArrayHelper::check($selection))
{
foreach ($selection as $value)
{
if (strpos($value,'AS') !== false)
{
list($table,$key) = explode('AS',$value);
$buket[] = '<code>'.$ur.'->'.trim($key).$cf.'</code>';
}
else
{
$buket[] = '<code>'.$ur.'->'.trim($value).$cf.'</code>';
}
}
}
}
if (UtilitiesArrayHelper::check($selectionsList))
{
$buket[] = '<hr />';
foreach ($selectionsList as $name => $selectionList)
{
if (UtilitiesArrayHelper::check($selectionList))
{
$ur = '&lt;?php echo $'.$name;
$cf = '; ?&gt;';
$buket[] = '<code>&lt;?php foreach ($item->'.$name.' as $'.$name.'): ?&gt;</code><br />';
foreach ($selectionList as $value)
{
if (strpos($value,'AS') !== false)
{
list($table,$key) = explode('AS',$value);
$buket[] = '<code>'.$ur.'->'.trim($key).$cf.'</code>';
}
else
{
$buket[] = '<code>'.$ur.'->'.trim($value).$cf.'</code>';
}
}
$buket[] = '<br /><code>&lt;?php endforeach; ?&gt;</code><hr />';
}
}
}
switch ($result->gettype)
{
case 2:
case 4:
// list
$buket[] = '<br /><code>&lt;?php endforeach; ?&gt;</code>';
break;
}
return implode('&nbsp;',$buket);
}
}
return false;
// Build code lines for selection lists.
if (UtilitiesArrayHelper::check($selectionsList))
{
$outputLines[] = '<hr />';
foreach ($selectionsList as $name => $selectionList)
{
if (UtilitiesArrayHelper::check($selectionList))
{
$listPrefix = '&lt;?php echo $' . $name;
$listSuffix = '; ?&gt;';
$outputLines[] = '<code>&lt;?php foreach ($item->' . $name . ' as $' . $name . '): ?&gt;</code><br />';
foreach ($selectionList as $value)
{
$value = trim($value);
if (strpos($value, 'AS') !== false)
{
list(, $key) = explode('AS', $value);
$outputLines[] = '<code>' . $listPrefix . '->' . trim($key) . $listSuffix . '</code>';
}
else
{
$outputLines[] = '<code>' . $listPrefix . '->' . $value . $listSuffix . '</code>';
}
}
$outputLines[] = '<br /><code>&lt;?php endforeach; ?&gt;</code><hr />';
}
}
}
// For list types, add the closing foreach.
if (in_array($getType, [2, 4], true))
{
$outputLines[] = '<br /><code>&lt;?php endforeach; ?&gt;</code>';
}
return implode('&nbsp;', $outputLines);
}
/**
* Generate a list method name based on provided names and table.
*
* This method creates an array of sanitized method/variable names based on input field names,
* the table name, and an alias.
*
* @param array $names An array of field names.
* @param string $table The table name.
* @param string $as The alias.
* @param int $type The type flag (1 for view, 2 for database).
*
* @return array An array of method names.
* @since 3.0.0
*/
protected function setListMethodName($names, $table, $as, $type)
{
$methodNames = array();
$methodNames = [];
if (UtilitiesArrayHelper::check($names))
{
foreach ($names as $nr => $name)
{
if (StringHelper::check($name))
{
if (strpos($name,'.') !== false)
if (strpos($name, '.') !== false)
{
list($dump,$var) = explode('.',$name);
list(, $var) = explode('.', $name);
}
else
{
$var = $name;
}
if ($nr > 0)
{
$methodNames[] = StringHelper::safe($var,'F');
$methodNames[] = StringHelper::safe($var, 'F');
}
else
{
@ -3339,30 +3453,52 @@ class AjaxModel extends ListModel
}
}
}
switch ($type)
{
// set view name
// For view tables.
case 1:
$methodNames[] = StringHelper::safe($this->getViewName($table),'F');
break;
// set db name
$methodNames[] = StringHelper::safe($this->getViewName($table), 'F');
break;
// For database tables.
case 2:
$methodNames[] = StringHelper::safe($table,'F');
break;
$methodNames[] = StringHelper::safe($table, 'F');
break;
}
// make sure there is uniqe method names
$methodNames[] = StringHelper::safe($as,'U');
$methodNames[] = StringHelper::safe($as, 'U');
return $methodNames;
}
protected function getViewName($id)
/**
* Retrieve the view name based on a key.
*
* @param mixed $key The key used to determine the view name.
*
* @return string The view name or an empty string if not found.
* @since 3.0.0
*/
protected function getViewName($key): string
{
// Get the view name
if ($name = GetHelper::var('admin_view', (int) $id, 'id', 'name_single'))
if (GuidHelper::valid($key))
{
$target = 'guid';
}
elseif (is_numeric($key))
{
$target = 'id';
}
else
{
return '';
}
// Retrieve the view name.
if ($name = GetHelper::var('admin_view', $key, $target, 'name_single'))
{
return $name;
}
return '';
}

View File

@ -364,7 +364,7 @@ class Dynamic_getsModel extends ListModel
}
// Add the list ordering clause.
$orderCol = $this->getState('list.ordering', 'a.id');
$orderCol = $this->getState('list.ordering', '');
$orderDirn = $this->getState('list.direction', 'desc');
if ($orderCol != '')
{

View File

@ -118,7 +118,7 @@ class HtmlView extends BaseHtmlView
// Load the active filters.
$this->activeFilters = $this->get('ActiveFilters');
// Add the list ordering clause.
$this->listOrder = $this->escape($this->state->get('list.ordering', 'a.id'));
$this->listOrder = $this->escape($this->state->get('list.ordering', ''));
$this->listDirn = $this->escape($this->state->get('list.direction', 'desc'));
$this->saveOrder = $this->listOrder == 'a.ordering';
// set the return here value

View File

@ -330,40 +330,35 @@ jQuery(function() {
});
});
});
document.addEventListener("DOMContentLoaded", function () {
// Attach change event listeners to form elements
document.querySelector("#adminForm")?.addEventListener("change", function (event) {
const target = event.target;
jQuery('#adminForm').on('change', '#jform_libraries',function (e) {
e.preventDefault();
getSnippets();
});
if (target.matches("#jform_libraries")) {
event.preventDefault();
getSnippets();
} else if (target.matches("#jform_snippet")) {
event.preventDefault();
const snippetId = target.value;
if (snippetId) {
getSnippetDetails(snippetId);
}
} else if (target.matches("#jform_dynamic_get")) {
event.preventDefault();
const dynamicId = target.value;
if (dynamicId) {
getDynamicValues(dynamicId);
}
}
});
jQuery('#adminForm').on('change', '#jform_snippet',function (e) {
e.preventDefault();
// get type value
var snippetId = jQuery("#jform_snippet option:selected").val();
getSnippetDetails(snippetId);
});
const dynamicElement = document.querySelector("#jform_dynamic_get");
const dynamicElementValue = dynamicElement.value;
if (dynamicElement && dynamicElementValue) {
getDynamicValues(dynamicElementValue);
}
jQuery(document).ready(function() {
// get type value
var snippetId = jQuery("#jform_snippet option:selected").val();
getSnippetDetails(snippetId);
});
jQuery('#adminForm').on('change', '#jform_dynamic_get',function (e) {
e.preventDefault();
// get type value
var dynamicId = jQuery("#jform_dynamic_get option:selected").val();
getDynamicValues(dynamicId);
});
jQuery(document).ready(function() {
// get type value
var dynamicId = jQuery("#jform_dynamic_get option:selected").val();
getDynamicValues(dynamicId);
});
jQuery(document).ready(function() {
// get type value
getLayoutDetails(9999);
getTemplateDetails(9999);
});