Release of v3.2.1-beta3

Fix version_update column size. Improved the Schema Table update engine.
This commit is contained in:
Robot 2024-04-24 21:10:42 +02:00
parent ebbcf2bea5
commit f99eae901a
Signed by untrusted user: Robot
GPG Key ID: 14DECD44E7E1BB95
15 changed files with 403 additions and 163 deletions

View File

@ -1,3 +1,8 @@
# v3.2.1-beta3
- Fix version_update column size.
- Improved the Schema Table update engine.
# v3.2.1-beta2 # v3.2.1-beta2
- Fix the media field size limitation. #1109 - Fix the media field size limitation. #1109

View File

@ -9,7 +9,7 @@ The Component Builder for [Joomla](https://extensions.joomla.org/extension/compo
Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have! Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have!
You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (3.2.1-beta2) with **ALL** its features and **ALL** concepts totally open-source and free! You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (3.2.1-beta3) with **ALL** its features and **ALL** concepts totally open-source and free!
> Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) > Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45)
@ -144,13 +144,13 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io) + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
+ *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder) + *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
+ *First Build*: 30th April, 2015 + *First Build*: 30th April, 2015
+ *Last Build*: 22nd April, 2024 + *Last Build*: 24th April, 2024
+ *Version*: 3.2.1-beta2 + *Version*: 3.2.1-beta3
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved. + *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt + *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **764243** + *Line count*: **764955**
+ *Field count*: **2097** + *Field count*: **2097**
+ *File count*: **5381** + *File count*: **5382**
+ *Folder count*: **471** + *Folder count*: **471**
> This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com). > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com).

View File

@ -9,7 +9,7 @@ The Component Builder for [Joomla](https://extensions.joomla.org/extension/compo
Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have! Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will save you lots of time and money. A real must have!
You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (3.2.1-beta2) with **ALL** its features and **ALL** concepts totally open-source and free! You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (3.2.1-beta3) with **ALL** its features and **ALL** concepts totally open-source and free!
> Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) > Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45)
@ -144,13 +144,13 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io) + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
+ *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder) + *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
+ *First Build*: 30th April, 2015 + *First Build*: 30th April, 2015
+ *Last Build*: 22nd April, 2024 + *Last Build*: 24th April, 2024
+ *Version*: 3.2.1-beta2 + *Version*: 3.2.1-beta3
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved. + *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt + *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **764243** + *Line count*: **764955**
+ *Field count*: **2097** + *Field count*: **2097**
+ *File count*: **5381** + *File count*: **5382**
+ *Folder count*: **471** + *Folder count*: **471**
> This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com). > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com).

View File

@ -1525,7 +1525,7 @@ CREATE TABLE IF NOT EXISTS `#__componentbuilder_component_updates` (
`id` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL AUTO_INCREMENT,
`asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.',
`joomla_component` INT(11) NOT NULL DEFAULT 0, `joomla_component` INT(11) NOT NULL DEFAULT 0,
`version_update` TEXT NOT NULL, `version_update` MEDIUMTEXT NOT NULL,
`params` TEXT NULL, `params` TEXT NULL,
`published` TINYINT(3) NOT NULL DEFAULT 1, `published` TINYINT(3) NOT NULL DEFAULT 1,
`created_by` INT(10) unsigned NOT NULL DEFAULT 0, `created_by` INT(10) unsigned NOT NULL DEFAULT 0,
@ -1905,7 +1905,7 @@ CREATE TABLE IF NOT EXISTS `#__componentbuilder_joomla_module_updates` (
`id` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL AUTO_INCREMENT,
`asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.',
`joomla_module` INT(11) NOT NULL DEFAULT 0, `joomla_module` INT(11) NOT NULL DEFAULT 0,
`version_update` TEXT NOT NULL, `version_update` MEDIUMTEXT NOT NULL,
`params` TEXT NULL, `params` TEXT NULL,
`published` TINYINT(3) NOT NULL DEFAULT 1, `published` TINYINT(3) NOT NULL DEFAULT 1,
`created_by` INT(10) unsigned NOT NULL DEFAULT 0, `created_by` INT(10) unsigned NOT NULL DEFAULT 0,
@ -1988,7 +1988,7 @@ CREATE TABLE IF NOT EXISTS `#__componentbuilder_joomla_plugin_updates` (
`id` INT(11) NOT NULL AUTO_INCREMENT, `id` INT(11) NOT NULL AUTO_INCREMENT,
`asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.',
`joomla_plugin` INT(11) NOT NULL DEFAULT 0, `joomla_plugin` INT(11) NOT NULL DEFAULT 0,
`version_update` TEXT NOT NULL, `version_update` MEDIUMTEXT NOT NULL,
`params` TEXT NULL, `params` TEXT NULL,
`published` TINYINT(3) NOT NULL DEFAULT 1, `published` TINYINT(3) NOT NULL DEFAULT 1,
`created_by` INT(10) unsigned NOT NULL DEFAULT 0, `created_by` INT(10) unsigned NOT NULL DEFAULT 0,

View File

@ -1,13 +1,15 @@
UPDATE `#__componentbuilder_admin_view`
SET `alias_builder_type` = 0
WHERE `alias_builder_type` = '';
UPDATE `#__componentbuilder_dynamic_get`
SET `addcalculation` = 0
WHERE `addcalculation` = '';
ALTER TABLE `#__componentbuilder_joomla_component` CHANGE `image` `image` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE `#__componentbuilder_joomla_component` CHANGE `image` `image` VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE `#__componentbuilder_admin_view` CHANGE `alias_builder_type` `alias_builder_type` TINYINT(1) NOT NULL DEFAULT 0; ALTER TABLE `#__componentbuilder_admin_view` CHANGE `alias_builder_type` `alias_builder_type` TINYINT(1) NOT NULL DEFAULT 0;
ALTER TABLE `#__componentbuilder_admin_view` CHANGE `icon` `icon` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE `#__componentbuilder_admin_view` CHANGE `icon` `icon` VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE `#__componentbuilder_admin_view` CHANGE `icon_add` `icon_add` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE `#__componentbuilder_admin_view` CHANGE `icon_add` `icon_add` VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE `#__componentbuilder_admin_view` CHANGE `icon_category` `icon_category` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE `#__componentbuilder_admin_view` CHANGE `icon_category` `icon_category` VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE `#__componentbuilder_custom_admin_view` CHANGE `icon` `icon` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE `#__componentbuilder_custom_admin_view` CHANGE `icon` `icon` VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE `#__componentbuilder_dynamic_get` CHANGE `addcalculation` `addcalculation` TINYINT(1) NOT NULL DEFAULT 0; ALTER TABLE `#__componentbuilder_dynamic_get` CHANGE `addcalculation` `addcalculation` TINYINT(1) NOT NULL DEFAULT 0;

View File

@ -0,0 +1,3 @@
ALTER TABLE `#__componentbuilder_component_updates` CHANGE `version_update` `version_update` MEDIUMTEXT NOT NULL;
ALTER TABLE `#__componentbuilder_joomla_module_updates` CHANGE `version_update` `version_update` MEDIUMTEXT NOT NULL;
ALTER TABLE `#__componentbuilder_joomla_plugin_updates` CHANGE `version_update` `version_update` MEDIUMTEXT NOT NULL;

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.10" method="upgrade"> <extension type="component" version="3.10" method="upgrade">
<name>COM_COMPONENTBUILDER</name> <name>COM_COMPONENTBUILDER</name>
<creationDate>22nd April, 2024</creationDate> <creationDate>24th April, 2024</creationDate>
<author>Llewellyn van der Merwe</author> <author>Llewellyn van der Merwe</author>
<authorEmail>joomla@vdm.io</authorEmail> <authorEmail>joomla@vdm.io</authorEmail>
<authorUrl>https://dev.vdm.io</authorUrl> <authorUrl>https://dev.vdm.io</authorUrl>
<copyright>Copyright (C) 2015 Vast Development Method. All rights reserved.</copyright> <copyright>Copyright (C) 2015 Vast Development Method. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license> <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<version>3.2.1-beta2</version> <version>3.2.1-beta3</version>
<description><![CDATA[ <description><![CDATA[
<h1>Component Builder (v.3.2.1-beta2)</h1> <h1>Component Builder (v.3.2.1-beta3)</h1>
<div style="clear: both;"></div> <div style="clear: both;"></div>
<p>The Component Builder for [Joomla](https://extensions.joomla.org/extension/component-builder/) is highly advanced tool that is truly able to build extremely complex components in a fraction of the time. <p>The Component Builder for [Joomla](https://extensions.joomla.org/extension/component-builder/) is highly advanced tool that is truly able to build extremely complex components in a fraction of the time.

View File

@ -1667,4 +1667,22 @@
<maintainerurl>https://dev.vdm.io</maintainerurl> <maintainerurl>https://dev.vdm.io</maintainerurl>
<targetplatform name="joomla" version="3.*"/> <targetplatform name="joomla" version="3.*"/>
</update> </update>
<update>
<name>Component Builder</name>
<description>Builds Complex Joomla Components</description>
<element>pkg_component_builder</element>
<type>package</type>
<client>site</client>
<version>3.2.1-beta3</version>
<infourl title="Component Builder!">https://dev.vdm.io</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.vdm.dev/api/v1/repos/joomla/pkg-component-builder/archive/v3.2.1-beta3.zip</downloadurl>
</downloads>
<tags>
<tag>beta</tag>
</tags>
<maintainer>Llewellyn van der Merwe</maintainer>
<maintainerurl>https://dev.vdm.io</maintainerurl>
<targetplatform name="joomla" version="3.*"/>
</update>
</updates> </updates>

View File

@ -48,7 +48,7 @@ abstract class BaseTable implements Tableinterface
'tab_name' => NULL, 'tab_name' => NULL,
'db' => [ 'db' => [
'type' => 'INT(11)', 'type' => 'INT(11)',
'default' => '', 'default' => 'EMPTY',
'auto_increment' => true, 'auto_increment' => true,
'primary_key' => true, 'primary_key' => true,
'null_switch' => 'NOT NULL' 'null_switch' => 'NOT NULL'
@ -227,7 +227,7 @@ abstract class BaseTable implements Tableinterface
'tab_name' => NULL, 'tab_name' => NULL,
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'TEXT',
'default' => '', 'default' => 'EMPTY',
'null_switch' => 'NULL' 'null_switch' => 'NULL'
] ]
] ]

View File

@ -12,7 +12,8 @@
namespace VDM\Joomla\Abstraction; namespace VDM\Joomla\Abstraction;
use Joomla\CMS\Factory; use Joomla\CMS\Factory;
use Joomla\CMS\Version;
use VDM\Joomla\Interfaces\Tableinterface as Table; use VDM\Joomla\Interfaces\Tableinterface as Table;
use VDM\Joomla\Interfaces\SchemaInterface; use VDM\Joomla\Interfaces\SchemaInterface;
@ -87,6 +88,14 @@ abstract class Schema implements SchemaInterface
*/ */
private array $success; private array $success;
/**
* Current Joomla Version We are IN
*
* @var int
* @since 3.2.1
**/
protected $currentVersion;
/** /**
* Constructor. * Constructor.
* *
@ -108,8 +117,11 @@ abstract class Schema implements SchemaInterface
// set the component table // set the component table
$this->prefix = $this->db->getPrefix() . $this->getCode(); $this->prefix = $this->db->getPrefix() . $this->getCode();
// set the current version
$this->currentVersion = Version::MAJOR_VERSION;
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception("Error: failed to initialize schema class due to a database error.", 0, $e); throw new \Exception("Error: failed to initialize schema class due to a database error.");
} }
} }
@ -141,7 +153,7 @@ abstract class Schema implements SchemaInterface
} }
} }
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception("Error: updating database schema.", 0, $e); throw new \Exception("Error: updating database schema. " . $e->getMessage());
} }
if (count($this->success) == 1) if (count($this->success) == 1)
@ -156,6 +168,63 @@ abstract class Schema implements SchemaInterface
return $this->success; return $this->success;
} }
/**
* Get the targeted component code
*
* @return string
* @since 3.2.1
*/
abstract protected function getCode(): string;
/**
* Check if a table exists in the database.
*
* @param string $table The name of the table to check.
*
* @return bool True if table exists, False otherwise.
* @since 3.2.1
*/
protected function tableExists(string $table): bool
{
return in_array($this->getTable($table), $this->tables);
}
/**
* Update the schema of an existing table.
*
* @param string $table The table to update.
*
* @return void
* @since 3.2.1
* @throws \Exception If there is an error while updating the schema.
*/
public function updateSchema(string $table): void
{
try {
$existingColumns = $this->getExistingColumns($table);
$expectedColumns = $this->table->fields($table, true);
$missingColumns = array_diff($expectedColumns, $existingColumns);
if (!empty($missingColumns))
{
$this->addMissingColumns($table, $missingColumns);
}
$this->checkColumnsDataType($table, $expectedColumns);
} catch (\Exception $e) {
throw new \Exception("Error: updating schema for $table table. " . $e->getMessage());
}
if (!empty($missingColumns))
{
$column_s = (count($missingColumns) == 1) ? 'column' : 'columns';
$missingColumns = implode(', ', $missingColumns);
$this->success[] = "Success: added missing ($missingColumns) $column_s to $table table.";
}
}
/** /**
* Create a table with all necessary fields. * Create a table with all necessary fields.
* *
@ -189,56 +258,27 @@ abstract class Schema implements SchemaInterface
$this->db->setQuery($createTableSql); $this->db->setQuery($createTableSql);
$this->db->execute(); $this->db->execute();
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception("Error: failed to create missing $table table.", 0, $e); throw new \Exception("Error: failed to create missing $table table. " . $e->getMessage());
} }
$this->success[] = "Success: created missing $table table."; $this->success[] = "Success: created missing $table table.";
} }
/** /**
* Update the schema of an existing table. * Fetch existing columns from a database table.
* *
* @param string $table The table to update. * @param string $table The name of the table.
* *
* @return void * @return array An array of column names.
* @since 3.2.1 * @since 3.2.1
* @throws \Exception If there is an error while updating the schema.
*/ */
public function updateSchema(string $table): void protected function getExistingColumns(string $table): array
{ {
try { $this->columns = $this->db->getTableColumns($this->getTable($table), false);
$existingColumns = $this->getExistingColumns($table);
$expectedColumns = $this->table->fields($table, true);
$missingColumns = array_diff($expectedColumns, $existingColumns); return array_keys($this->columns);
if (!empty($missingColumns))
{
$this->addMissingColumns($table, $missingColumns);
}
$this->checkColumnsDataType($table, $expectedColumns);
} catch (\Exception $e) {
throw new \Exception("Error: updating schema for $table table.", 0, $e);
}
if (!empty($missingColumns))
{
$column_s = (count($missingColumns) == 1) ? 'column' : 'columns';
$missingColumns = implode(', ', $missingColumns);
$this->success[] = "Success: added missing ($missingColumns) $column_s to $table table.";
}
} }
/**
* Get the targeted component code
*
* @return string
* @since 3.2.1
*/
abstract protected function getCode(): string;
/** /**
* Add missing columns to a table. * Add missing columns to a table.
* *
@ -270,7 +310,7 @@ abstract class Schema implements SchemaInterface
} catch (\Exception $e) { } catch (\Exception $e) {
$column_s = (count($columns) == 1) ? 'column' : 'columns'; $column_s = (count($columns) == 1) ? 'column' : 'columns';
$columns = implode(', ', $columns); $columns = implode(', ', $columns);
throw new \Exception("Error: failed to add ($columns) $column_s to $table table.", 0, $e); throw new \Exception("Error: failed to add ($columns) $column_s to $table table. " . $e->getMessage());
} }
} }
@ -291,18 +331,20 @@ abstract class Schema implements SchemaInterface
$current = $this->columns[$column] ?? null; $current = $this->columns[$column] ?? null;
if ($current === null || ($expected = $this->table->get($table, $column, 'db')) === null) if ($current === null || ($expected = $this->table->get($table, $column, 'db')) === null)
{ {
// this field is no longer part of the component and can be ignored
continue; continue;
} }
// check if the data type and size match // check if the data type and size match
if (strcasecmp($current->Type, $expected['type']) != 0) if ($this->isDataTypeChangeSignificant($current->Type, $expected['type']))
{ {
$requireUpdate[$column] = [ $requireUpdate[$column] = [
'column' => $column, 'column' => $column,
'current' => $current->Type, 'current' => $current->Type,
'expected' => $expected['type'] 'expected' => $expected['type']
]; ];
// check if update of default values is needed
$this->checkDefault($table, $column);
} }
} }
@ -312,6 +354,89 @@ abstract class Schema implements SchemaInterface
} }
} }
/**
* Generates a SQL snippet for defining a table column, incorporating column type,
* default value, nullability, and auto-increment properties.
*
* @param string $table The table name to be used.
* @param string $field The field name in the table to generate SQL for.
*
* @return string|null The SQL snippet for the column definition.
* @since 3.2.1
* @throws \Exception If the schema details cannot be retrieved or the SQL statement cannot be constructed properly.
*/
protected function getColumnDefinition(string $table, string $field): ?string
{
try {
// Retrieve the database schema details for the specified table and field
if (($db = $this->table->get($table, $field, 'db')) === null)
{
return null;
}
// Prepare the column name
$column_name = $this->db->quoteName($field);
$db['name'] = $field;
// Prepare the type and default value SQL statement
$type = $db['type'] ?? 'TEXT';
$db_default = isset($db['default']) ? $db['default'] : null;
$default = $this->getDefaultValue($type, $db_default);
// Prepare the null switch, and auto increment statement
$null_switch = !empty($db['null_switch']) ? " " . $db['null_switch'] : '';
$auto_increment = !empty($db['auto_increment']) ? " AUTO_INCREMENT" : '';
$this->setKeys($db);
// Assemble the SQL snippet for the column definition
return "{$column_name} {$type}{$null_switch}{$default}{$auto_increment}";
} catch (\Exception $e) {
throw new \Exception("Error: failed to generate column definition for ($table.$field). " . $e->getMessage());
}
}
/**
* Check and Update the default values if needed, including existing data adjustments
*
* @param string $table The table to update.
* @param string $column The column/field to check.
*
* @return void
* @since 3.2.1
*/
protected function checkDefault(string $table, string $column): void
{
// Retrieve the expected column configuration
$expected = $this->table->get($table, $column, 'db');
// Skip updates if the column is auto_increment
if (isset($expected['auto_increment']) && $expected['auto_increment'])
{
return;
}
// Retrieve the current column configuration
$current = $this->columns[$column];
// Check if default should be empty and current default is null, skip processing
if (strtoupper($expected['default']) === 'EMPTY' && $current->Default === NULL)
{
return;
}
// Determine the new default value based on the expected settings
$type = $expected['type'] ?? 'TEXT';
$db_default = isset($expected['default']) ? $expected['default'] : null;
$newDefault = $this->getDefaultValue($type, $db_default, true);
// First, adjust existing rows to conform to the new default if necessary
if (is_numeric($newDefault) && $this->adjustExistingDefaults($table, $column, $current->Default, $newDefault))
{
$this->success[] = "Success: updated the ($column) defaults in $table table.";
}
}
/** /**
* Update the data type of the given fields. * Update the data type of the given fields.
* *
@ -336,13 +461,120 @@ abstract class Schema implements SchemaInterface
if ($this->updateColumnDataType($alterQuery, $table, $column)) if ($this->updateColumnDataType($alterQuery, $table, $column))
{ {
$current = (string) $types['current'] ?? 'error'; $current = $types['current'] ?? 'error';
$expected = (string) $types['expected'] ?? 'error'; $expected = $types['expected'] ?? 'error';
$this->success[] = "Success: updated ($column) column datatype $current to $expected in $table table."; $this->success[] = "Success: updated ($column) column datatype $current to $expected in $table table.";
} }
} }
} }
/**
* Add the component name to get the full table name.
*
* @param string $table The table name.
*
* @return void
* @since 3.2.1
*/
protected function getTable(string $table): string
{
return $this->prefix . '_' . $table;
}
/**
* Determines if the change in data type between two definitions is significant.
*
* This function checks if there's a significant difference between the current
* data type and the expected data type that would require updating the database schema.
* It ignores size and other modifiers for certain data types where MySQL considers
* these attributes irrelevant for storage.
*
* @param string $currentType The current data type from the database schema.
* @param string $expectedType The expected data type to validate against.
*
* @return bool Returns true if the data type change is significant, otherwise false.
* @since 3.2.1
*/
function isDataTypeChangeSignificant(string $currentType, string $expectedType): bool
{
// we only do this for Joomla 4+
if ($this->currentVersion != 3)
{
// Normalize both input types to lowercase for case-insensitive comparison
$currentType = strtolower($currentType);
$expectedType = strtolower($expectedType);
// Define types where size or other modifiers are irrelevant
$sizeIrrelevantTypes = [
'int', 'tinyint', 'smallint', 'mediumint', 'bigint', // Standard integer types
'int unsigned', 'tinyint unsigned', 'smallint unsigned', 'mediumint unsigned', 'bigint unsigned', // Unsigned integer types
];
// Check if the type involves size-irrelevant types
foreach ($sizeIrrelevantTypes as $type)
{
if (strpos($expectedType, $type) !== false)
{
// Remove any numeric sizes and modifiers for comparison
$pattern = '/\(\d+\)|unsigned|\s*/';
$cleanCurrentType = preg_replace($pattern, '', $currentType);
$cleanExpectedType = preg_replace($pattern, '', $expectedType);
// Compare the cleaned types
if ($cleanCurrentType === $cleanExpectedType)
{
return false; // No significant change
}
}
}
}
// Perform a standard case-insensitive comparison for other types
if (strcasecmp($currentType, $expectedType) == 0)
{
return false; // No significant change
}
return true; // Significant datatype change detected
}
/**
* Updates existing rows in a column to a new default value
*
* @param string $table The table to update.
* @param string $column The column to update.
* @param mixed $currentDefault Current default value.
* @param mixed $newDefault The new default value to be set.
*
* @return void
* @since 3.2.1
* @throws \Exception If there is an error updating column defaults.
*/
protected function adjustExistingDefaults(string $table, string $column, $currentDefault, $newDefault): bool
{
// Determine if adjustment is needed based on new and current defaults
if ($newDefault !== $currentDefault)
{
try {
// Format the new default for SQL use
$sqlDefault = $this->db->quote($newDefault);
$updateTable = 'UPDATE ' . $this->db->quoteName($this->getTable($table));
$dbField = $this->db->quoteName($column);
// Update SQL to set new default on existing rows where the default is currently the old default
$sql = $updateTable . " SET $dbField = $sqlDefault WHERE $dbField IS NULL OR $dbField = ''";
// Execute the update
$this->db->setQuery($sql);
return $this->db->execute();
} catch (\Exception $e) {
throw new \Exception("Error: failed to update ($column) column defaults in $table table. " . $e->getMessage());
}
}
return false;
}
/** /**
* Update the data type of the given field. * Update the data type of the given field.
* *
@ -360,7 +592,7 @@ abstract class Schema implements SchemaInterface
$this->db->setQuery($updateString); $this->db->setQuery($updateString);
return $this->db->execute(); return $this->db->execute();
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception("Error: failed to update the datatype of ($field) column in $table table.", 0, $e); throw new \Exception("Error: failed to update the datatype of ($field) column in $table table. " . $e->getMessage());
} }
} }
@ -388,6 +620,20 @@ abstract class Schema implements SchemaInterface
return implode(', ', $keys); return implode(', ', $keys);
} }
/**
* Function to set the view keys
*
* @param string $column The field column database array values
*
* @return void
* @since 3.2.1
*/
protected function setKeys(array $column): void
{
$this->setUniqueKey($column);
$this->setKey($column);
}
/** /**
* Function to set the unique key * Function to set the unique key
* *
@ -423,97 +669,34 @@ abstract class Schema implements SchemaInterface
} }
/** /**
* Add the component name to get the full table name. * Adjusts the default value SQL fragment for a database field based on its type and specific rules.
* *
* @param string $table The table name. * If the field is of type DATETIME and the Joomla version is not 3, it sets the default to CURRENT_TIMESTAMP
* if not explicitly specified otherwise. For all other types, or when a 'EMPTY' default is specified, it handles
* defaults by either leaving them unset or applying the provided default, properly quoted for SQL safety.
* *
* @return void * @param string $type The type of the database field (e.g., 'DATETIME').
* @since 3.2.1 * @param string|null $defaultValue Optional default value for the field, null if not provided.
*/ * @param bool $pure Optional to add the 'DEFAULT' string or not.
protected function getTable(string $table): string
{
return $this->prefix . '_' . $table;
}
/**
* Check if a table exists in the database.
* *
* @param string $table The name of the table to check. * @return string The SQL fragment to set the default value for a field.
*
* @return bool True if table exists, False otherwise.
* @since 3.2.1
*/
private function tableExists(string $table): bool
{
return in_array($this->getTable($table), $this->tables);
}
/**
* Fetch existing columns from a database table.
*
* @param string $table The name of the table.
*
* @return array An array of column names.
* @since 3.2.1
*/
private function getExistingColumns(string $table): array
{
$this->columns = $this->db->getTableColumns($this->getTable($table), false);
return array_keys($this->columns);
}
/**
* Generates a SQL snippet for defining a table column, incorporating column type,
* default value, nullability, and auto-increment properties.
*
* @param string $table The table name to be used.
* @param string $field The field name in the table to generate SQL for.
*
* @return string|null The SQL snippet for the column definition.
* @since 3.2.1 * @since 3.2.1
* @throws \Exception If the schema details cannot be retrieved or the SQL statement cannot be constructed properly.
*/ */
private function getColumnDefinition(string $table, string $field): ?string protected function getDefaultValue(string $type, ?string $defaultValue, bool $pure = false): string
{ {
try { if ($defaultValue === null || strtoupper($defaultValue) === 'EMPTY')
// Retrieve the database schema details for the specified table and field {
if (($db = $this->table->get($table, $field, 'db')) === null) return '';
{
return null;
}
// Prepare the column name
$column_name = $this->db->quoteName($field);
$db['name'] = $field;
// Prepare the default value SQL, null switch, and auto increment statement
$default = !empty($db['default']) ? " DEFAULT " . $this->db->quote($db['default']) : '';
$null_switch = !empty($db['null_switch']) ? " " . $db['null_switch'] : '';
$auto_increment = !empty($db['auto_increment']) ? " AUTO_INCREMENT" : '';
$type = !empty($db['type']) ? $db['type'] : 'TEXT';
$this->setKeys($db);
// Assemble the SQL snippet for the column definition
return "{$column_name} {$type}{$default}{$null_switch}{$auto_increment}";
} catch (\Exception $e) {
throw new \Exception("Error: failed to generate column definition for $table.$field", 0, $e);
} }
}
/** // Set default for DATETIME fields in Joomla versions above 3
* Function to set the view keys if (strtoupper($type) === 'DATETIME' && $this->currentVersion != 3)
* {
* @param string $column The field column database array values return $pure ? "CURRENT_TIMESTAMP" : " DEFAULT CURRENT_TIMESTAMP";
* }
* @return void
* @since 3.2.1 // Apply and quote the default value
*/ return $pure ? $defaultValue : " DEFAULT " . $this->db->quote($defaultValue);
private function setKeys(array $column): void
{
$this->setUniqueKey($column);
$this->setKey($column);
} }
} }

View File

@ -433,6 +433,22 @@ class Data
} }
unset($view->addtables); unset($view->addtables);
// Make sure the icon is only an icon path
if (strpos($view->icon, '#') !== false)
{
$view->icon = strstr($view->icon, '#', true);
}
// Make sure the icon_add is only an icon_add path
if (strpos($view->icon_add, '#') !== false)
{
$view->icon_add = strstr($view->icon_add, '#', true);
}
// Make sure the icon_add is only an icon_add path
if (strpos($view->icon_category, '#') !== false)
{
$view->icon_category = strstr($view->icon_category, '#', true);
}
// set custom tabs // set custom tabs
$this->customtabs->set($view); $this->customtabs->set($view);

View File

@ -404,6 +404,12 @@ final class Data
) )
); );
// Make sure the image is only an image path
if (strpos($component->image, '#') !== false)
{
$component->image = strstr($component->image, '#', true);
}
// set the website and autor for global use (default to VDM if not found) // set the website and autor for global use (default to VDM if not found)
$this->config->set('project_website', $component->website ?? 'https://dev.vdm.io'); $this->config->set('project_website', $component->website ?? 'https://dev.vdm.io');
$this->config->set('project_author', $component->author ?? 'VDM'); $this->config->set('project_author', $component->author ?? 'VDM');

View File

@ -243,6 +243,12 @@ class Data
'jcb_ce_onBeforeModelCustomViewData', [&$item, &$id, &$table] 'jcb_ce_onBeforeModelCustomViewData', [&$item, &$id, &$table]
); );
// Make sure the icon is only an icon path
if (strpos($item->icon, '#') !== false)
{
$item->icon = strstr($item->icon, '#', true);
}
// set GUI mapper // set GUI mapper
$guiMapper = [ $guiMapper = [
'table' => $table, 'table' => $table,

View File

@ -9598,7 +9598,7 @@ class Table extends BaseTable implements Tableinterface
'store' => 'json', 'store' => 'json',
'tab_name' => 'Updates', 'tab_name' => 'Updates',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'MEDIUMTEXT',
'default' => 'EMPTY', 'default' => 'EMPTY',
'null_switch' => 'NOT NULL', 'null_switch' => 'NOT NULL',
'unique_key' => false, 'unique_key' => false,
@ -10526,7 +10526,7 @@ class Table extends BaseTable implements Tableinterface
'store' => 'json', 'store' => 'json',
'tab_name' => 'Updates', 'tab_name' => 'Updates',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'MEDIUMTEXT',
'default' => 'EMPTY', 'default' => 'EMPTY',
'null_switch' => 'NOT NULL', 'null_switch' => 'NOT NULL',
'unique_key' => false, 'unique_key' => false,
@ -10734,7 +10734,7 @@ class Table extends BaseTable implements Tableinterface
'store' => 'json', 'store' => 'json',
'tab_name' => 'Updates', 'tab_name' => 'Updates',
'db' => [ 'db' => [
'type' => 'TEXT', 'type' => 'MEDIUMTEXT',
'default' => 'EMPTY', 'default' => 'EMPTY',
'null_switch' => 'NOT NULL', 'null_switch' => 'NOT NULL',
'unique_key' => false, 'unique_key' => false,

View File

@ -9810,7 +9810,7 @@ class Com_ComponentbuilderInstallerScript
echo '<div style="background-color: #fff;" class="alert alert-info"><a target="_blank" href="https://dev.vdm.io" title="Component Builder"> echo '<div style="background-color: #fff;" class="alert alert-info"><a target="_blank" href="https://dev.vdm.io" title="Component Builder">
<img src="components/com_componentbuilder/assets/images/vdm-component.jpg"/> <img src="components/com_componentbuilder/assets/images/vdm-component.jpg"/>
</a> </a>
<h3>Upgrade to Version 3.2.1-beta2 Was Successful! Let us know if anything is not working as expected.</h3></div>'; <h3>Upgrade to Version 3.2.1-beta3 Was Successful! Let us know if anything is not working as expected.</h3></div>';
// Set db if not set already. // Set db if not set already.
if (!isset($db)) if (!isset($db))
@ -11780,16 +11780,17 @@ class Com_ComponentbuilderInstallerScript
/** /**
* Ensures that a class in the namespace is available. * Ensures that a class in the namespace is available.
* If the class is not already loaded, it attempts to load it. * If the class is not already loaded, it attempts to load it via the power autoloader.
* *
* @param mixed $className The class name to load. * @param mixed $nameClass The name::class we are looking for.
* *
* @return void * @return void
* @since 3.2.1 * @since 3.2.1
* @throws \Exception If the class could not be loaded.
*/ */
protected function ensureClassExists($className): void protected function ensureClassExists($nameClass): void
{ {
if (!class_exists($className, true)) if (!class_exists($nameClass, true))
{ {
// The power autoloader for this project admin area. // The power autoloader for this project admin area.
$power_autoloader = JPATH_ADMINISTRATOR . '/componenents/com_componentbuilder/helpers/powerload.php'; $power_autoloader = JPATH_ADMINISTRATOR . '/componenents/com_componentbuilder/helpers/powerload.php';
@ -11799,9 +11800,9 @@ class Com_ComponentbuilderInstallerScript
} }
// Check again if the class now exists after requiring it // Check again if the class now exists after requiring it
if (!class_exists($className, true)) if (!class_exists($nameClass, true))
{ {
throw new \Exception($errorMessage); throw new \Exception("We failed to find/load the $nameClass");
} }
} }
} }