update 2024-05-23 10:43:13 #7
@ -12,7 +12,7 @@
|
|||||||
namespace VDM\Joomla\Utilities;
|
namespace VDM\Joomla\Utilities;
|
||||||
|
|
||||||
|
|
||||||
use Joomla\CMS\Filter\InputFilter;
|
use Joomla\Filter\InputFilter;
|
||||||
use Joomla\CMS\Language\Language;
|
use Joomla\CMS\Language\Language;
|
||||||
use VDM\Joomla\Utilities\Component\Helper;
|
use VDM\Joomla\Utilities\Component\Helper;
|
||||||
|
|
||||||
|
@ -22,6 +22,6 @@
|
|||||||
"namespace": "[[[NamespacePrefix]]]\\Joomla\\Utilities.StringHelper",
|
"namespace": "[[[NamespacePrefix]]]\\Joomla\\Utilities.StringHelper",
|
||||||
"description": "Some string tricks\r\n\r\n@since 3.0.9",
|
"description": "Some string tricks\r\n\r\n@since 3.0.9",
|
||||||
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 3rd September, 2020\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git Joomla Component Builder <https:\/\/git.vdm.dev\/joomla\/Component-Builder>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
|
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 3rd September, 2020\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git Joomla Component Builder <https:\/\/git.vdm.dev\/joomla\/Component-Builder>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
|
||||||
"head": "use Joomla\\CMS\\Filter\\InputFilter;\r\nuse Joomla\\CMS\\Language\\Language;",
|
"head": "use Joomla\\Filter\\InputFilter;\r\nuse Joomla\\CMS\\Language\\Language;",
|
||||||
"composer": ""
|
"composer": ""
|
||||||
}
|
}
|
@ -13,6 +13,7 @@
|
|||||||
abstract ActiveRegistry #Orange {
|
abstract ActiveRegistry #Orange {
|
||||||
# array $active
|
# array $active
|
||||||
# bool $addAsArray
|
# bool $addAsArray
|
||||||
|
# bool $uniqueArray
|
||||||
+ isActive() : bool
|
+ isActive() : bool
|
||||||
+ allActive() : array
|
+ allActive() : array
|
||||||
+ setActive(mixed $value, $keys) : void
|
+ setActive(mixed $value, $keys) : void
|
||||||
|
@ -40,6 +40,14 @@ abstract class ActiveRegistry implements Activeregistryinterface
|
|||||||
**/
|
**/
|
||||||
protected bool $addAsArray = false;
|
protected bool $addAsArray = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base switch to keep array values unique
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
* @since 3.2.2
|
||||||
|
**/
|
||||||
|
protected bool $uniqueArray = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the registry has any content.
|
* Check if the registry has any content.
|
||||||
*
|
*
|
||||||
@ -157,7 +165,16 @@ abstract class ActiveRegistry implements Activeregistryinterface
|
|||||||
// Convert to array if it's not already an array
|
// Convert to array if it's not already an array
|
||||||
$array = [$array];
|
$array = [$array];
|
||||||
}
|
}
|
||||||
$array[] = $value;
|
|
||||||
|
if ($this->uniqueArray && in_array($value, $array))
|
||||||
|
{
|
||||||
|
// we do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$array[] = $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,14 @@
|
|||||||
**/
|
**/
|
||||||
protected bool $addAsArray = false;
|
protected bool $addAsArray = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base switch to keep array values unique
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
* @since 3.2.2
|
||||||
|
**/
|
||||||
|
protected bool $uniqueArray = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the registry has any content.
|
* Check if the registry has any content.
|
||||||
*
|
*
|
||||||
@ -131,7 +139,16 @@
|
|||||||
// Convert to array if it's not already an array
|
// Convert to array if it's not already an array
|
||||||
$array = [$array];
|
$array = [$array];
|
||||||
}
|
}
|
||||||
$array[] = $value;
|
|
||||||
|
if ($this->uniqueArray && in_array($value, $array))
|
||||||
|
{
|
||||||
|
// we do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$array[] = $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -30,10 +30,10 @@ abstract Schema #Orange {
|
|||||||
# addMissingColumns(string $table, array $columns) : void
|
# addMissingColumns(string $table, array $columns) : void
|
||||||
# checkColumnsDataType(string $table, array $columns) : void
|
# checkColumnsDataType(string $table, array $columns) : void
|
||||||
# getColumnDefinition(string $table, string $field) : ?string
|
# getColumnDefinition(string $table, string $field) : ?string
|
||||||
# checkDefault(string $table, string $column) : void
|
# checkDefault(string $table, string $column) : bool
|
||||||
# updateColumnsDataType(string $table, array $columns) : void
|
# updateColumnsDataType(string $table, array $columns) : void
|
||||||
# getTable(string $table) : string
|
# getTable(string $table) : string
|
||||||
isDataTypeChangeSignificant(string $currentType, string $expectedType) : bool
|
# isDataTypeChangeSignificant(string $currentType, string $expectedType) : bool
|
||||||
# adjustExistingDefaults(string $table, string $column, ...) : bool
|
# adjustExistingDefaults(string $table, string $column, ...) : bool
|
||||||
# updateColumnDataType(string $updateString, string $table, ...) : bool
|
# updateColumnDataType(string $updateString, string $table, ...) : bool
|
||||||
# getTableKeys() : string
|
# getTableKeys() : string
|
||||||
@ -41,6 +41,7 @@ abstract Schema #Orange {
|
|||||||
# setUniqueKey(array $column) : void
|
# setUniqueKey(array $column) : void
|
||||||
# setKey(array $column) : void
|
# setKey(array $column) : void
|
||||||
# getDefaultValue(string $type, ?string $defaultValue, ...) : string
|
# getDefaultValue(string $type, ?string $defaultValue, ...) : string
|
||||||
|
# quote(mixed $value) : mixed
|
||||||
}
|
}
|
||||||
|
|
||||||
note right of Schema::__construct
|
note right of Schema::__construct
|
||||||
@ -117,7 +118,7 @@ note right of Schema::checkDefault
|
|||||||
Check and Update the default values if needed, including existing data adjustments
|
Check and Update the default values if needed, including existing data adjustments
|
||||||
|
|
||||||
since: 3.2.1
|
since: 3.2.1
|
||||||
return: void
|
return: bool
|
||||||
end note
|
end note
|
||||||
|
|
||||||
note left of Schema::updateColumnsDataType
|
note left of Schema::updateColumnsDataType
|
||||||
@ -138,8 +139,8 @@ note left of Schema::isDataTypeChangeSignificant
|
|||||||
Determines if the change in data type between two definitions is significant.
|
Determines if the change in data type between two definitions is significant.
|
||||||
This function checks if there's a significant difference between the current
|
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.
|
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
|
It ignores display width for numeric types where MySQL considers these attributes
|
||||||
these attributes irrelevant for storage.
|
irrelevant for storage but considers size and other modifiers for types like VARCHAR.
|
||||||
|
|
||||||
since: 3.2.1
|
since: 3.2.1
|
||||||
return: bool
|
return: bool
|
||||||
@ -213,6 +214,13 @@ defaults by either leaving them unset or applying the provided default, properly
|
|||||||
bool $pure = false
|
bool $pure = false
|
||||||
end note
|
end note
|
||||||
|
|
||||||
|
note left of Schema::quote
|
||||||
|
Set a value based on data type
|
||||||
|
|
||||||
|
since: 3.2.0
|
||||||
|
return: mixed
|
||||||
|
end note
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -342,9 +342,16 @@ abstract class Schema implements SchemaInterface
|
|||||||
'current' => $current->Type,
|
'current' => $current->Type,
|
||||||
'expected' => $expected['type']
|
'expected' => $expected['type']
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// check if update of default values is needed
|
// check if update of default values is needed
|
||||||
$this->checkDefault($table, $column);
|
if ($this->checkDefault($table, $column) && !isset($requireUpdate[$column]))
|
||||||
|
{
|
||||||
|
$requireUpdate[$column] = [
|
||||||
|
'column' => $column,
|
||||||
|
'current' => $current->Type,
|
||||||
|
'expected' => $expected['type']
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,29 +409,23 @@ abstract class Schema implements SchemaInterface
|
|||||||
* @param string $table The table to update.
|
* @param string $table The table to update.
|
||||||
* @param string $column The column/field to check.
|
* @param string $column The column/field to check.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return bool
|
||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
protected function checkDefault(string $table, string $column): void
|
protected function checkDefault(string $table, string $column): bool
|
||||||
{
|
{
|
||||||
// Retrieve the expected column configuration
|
// Retrieve the expected column configuration
|
||||||
$expected = $this->table->get($table, $column, 'db');
|
$expected = $this->table->get($table, $column, 'db');
|
||||||
|
|
||||||
// Skip updates if the column is auto_increment
|
// Skip updates if the column is auto_increment
|
||||||
if (isset($expected['auto_increment']) && $expected['auto_increment'])
|
if (isset($expected['auto_increment']) && $expected['auto_increment'] === true)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the current column configuration
|
// Retrieve the current column configuration
|
||||||
$current = $this->columns[$column];
|
$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
|
// Determine the new default value based on the expected settings
|
||||||
$type = $expected['type'] ?? 'TEXT';
|
$type = $expected['type'] ?? 'TEXT';
|
||||||
$db_default = isset($expected['default']) ? $expected['default'] : null;
|
$db_default = isset($expected['default']) ? $expected['default'] : null;
|
||||||
@ -434,7 +435,17 @@ abstract class Schema implements SchemaInterface
|
|||||||
if (is_numeric($newDefault) && $this->adjustExistingDefaults($table, $column, $current->Default, $newDefault))
|
if (is_numeric($newDefault) && $this->adjustExistingDefaults($table, $column, $current->Default, $newDefault))
|
||||||
{
|
{
|
||||||
$this->success[] = "Success: updated the ($column) defaults in $table table.";
|
$this->success[] = "Success: updated the ($column) defaults in $table table.";
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_string($expected['default']) && strtoupper($expected['default']) === 'EMPTY' &&
|
||||||
|
is_string($current->Default) && strpos($current->Default, 'EMPTY') !== false)
|
||||||
|
{
|
||||||
|
return true; // little fix
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -486,56 +497,52 @@ abstract class Schema implements SchemaInterface
|
|||||||
*
|
*
|
||||||
* This function checks if there's a significant difference between the current
|
* 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.
|
* 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
|
* It ignores display width for numeric types where MySQL considers these attributes
|
||||||
* these attributes irrelevant for storage.
|
* irrelevant for storage but considers size and other modifiers for types like VARCHAR.
|
||||||
*
|
*
|
||||||
* @param string $currentType The current data type from the database schema.
|
* @param string $currentType The current data type from the database schema.
|
||||||
* @param string $expectedType The expected data type to validate against.
|
* @param string $expectedType The expected data type to validate against.
|
||||||
*
|
*
|
||||||
* @return bool Returns true if the data type change is significant, otherwise false.
|
* @return bool Returns true if the data type change is significant, otherwise false.
|
||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
function isDataTypeChangeSignificant(string $currentType, string $expectedType): bool
|
protected function isDataTypeChangeSignificant(string $currentType, string $expectedType): bool
|
||||||
{
|
{
|
||||||
// we only do this for Joomla 4+
|
// Normalize both input types to lowercase for case-insensitive comparison
|
||||||
if ($this->currentVersion != 3)
|
$currentType = strtolower($currentType);
|
||||||
|
$expectedType = strtolower($expectedType);
|
||||||
|
|
||||||
|
// Regex to extract the base data type and numeric parameters with named groups
|
||||||
|
$typePattern = '/^(?<datatype>\w+)(\((?<params>\d+(,\d+)?)\))?/';
|
||||||
|
|
||||||
|
// Match types and parameters
|
||||||
|
preg_match($typePattern, $currentType, $currentMatches);
|
||||||
|
preg_match($typePattern, $expectedType, $expectedMatches);
|
||||||
|
|
||||||
|
// Compare base types
|
||||||
|
if ($currentMatches['datatype'] !== $expectedMatches['datatype'])
|
||||||
{
|
{
|
||||||
// Normalize both input types to lowercase for case-insensitive comparison
|
return true; // Base types differ
|
||||||
$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
|
// Define types where size and other modifiers are irrelevant
|
||||||
if (strcasecmp($currentType, $expectedType) == 0)
|
$sizeIrrelevantTypes = [
|
||||||
|
'int', 'tinyint', 'smallint', 'mediumint', 'bigint',
|
||||||
|
'float', 'double', 'decimal', 'numeric' // Numeric types where display width is irrelevant
|
||||||
|
];
|
||||||
|
|
||||||
|
// If the type is not in the size irrelevant list, compare full definitions
|
||||||
|
if (!in_array($currentMatches['datatype'], $sizeIrrelevantTypes))
|
||||||
{
|
{
|
||||||
return false; // No significant change
|
return $currentType !== $expectedType; // Use full definition for types where size matters
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // Significant datatype change detected
|
// For size irrelevant types, only compare base type, ignoring size and unsigned
|
||||||
|
$currentBaseType = preg_replace('/\(\d+(,\d+)?\)|unsigned/', '', $currentType);
|
||||||
|
$expectedBaseType = preg_replace('/\(\d+(,\d+)?\)|unsigned/', '', $expectedType);
|
||||||
|
|
||||||
|
// Perform a final comparison for numeric types ignoring size
|
||||||
|
return $currentBaseType !== $expectedBaseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -684,7 +691,7 @@ abstract class Schema implements SchemaInterface
|
|||||||
*/
|
*/
|
||||||
protected function getDefaultValue(string $type, ?string $defaultValue, bool $pure = false): string
|
protected function getDefaultValue(string $type, ?string $defaultValue, bool $pure = false): string
|
||||||
{
|
{
|
||||||
if ($defaultValue === null || strtoupper($defaultValue) === 'EMPTY')
|
if ($defaultValue === null)
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@ -696,7 +703,52 @@ abstract class Schema implements SchemaInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply and quote the default value
|
// Apply and quote the default value
|
||||||
return $pure ? $defaultValue : " DEFAULT " . $this->db->quote($defaultValue);
|
$sql_default = $this->quote($defaultValue);
|
||||||
|
return $pure ? $defaultValue : " DEFAULT $sql_default";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a value based on data type
|
||||||
|
*
|
||||||
|
* @param mixed $value The value to set
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @since 3.2.0
|
||||||
|
**/
|
||||||
|
protected function quote($value)
|
||||||
|
{
|
||||||
|
if ($value === null) // hmm the null does pose an issue (will keep an eye on this)
|
||||||
|
{
|
||||||
|
return 'NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($value) && strtoupper($value) === 'EMPTY')
|
||||||
|
{
|
||||||
|
return "''";
|
||||||
|
}
|
||||||
|
elseif (is_numeric($value))
|
||||||
|
{
|
||||||
|
if (filter_var($value, FILTER_VALIDATE_INT))
|
||||||
|
{
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
elseif (filter_var($value, FILTER_VALIDATE_FLOAT))
|
||||||
|
{
|
||||||
|
return (float) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (is_bool($value)) // not sure if this will work well (but its correct)
|
||||||
|
{
|
||||||
|
return $value ? 'TRUE' : 'FALSE';
|
||||||
|
}
|
||||||
|
// For date and datetime values
|
||||||
|
elseif ($value instanceof \DateTime)
|
||||||
|
{
|
||||||
|
return $this->db->quote($value->format('Y-m-d H:i:s'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For other data types, just escape it
|
||||||
|
return $this->db->quote($value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,9 +315,16 @@
|
|||||||
'current' => $current->Type,
|
'current' => $current->Type,
|
||||||
'expected' => $expected['type']
|
'expected' => $expected['type']
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// check if update of default values is needed
|
// check if update of default values is needed
|
||||||
$this->checkDefault($table, $column);
|
if ($this->checkDefault($table, $column) && !isset($requireUpdate[$column]))
|
||||||
|
{
|
||||||
|
$requireUpdate[$column] = [
|
||||||
|
'column' => $column,
|
||||||
|
'current' => $current->Type,
|
||||||
|
'expected' => $expected['type']
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,29 +382,23 @@
|
|||||||
* @param string $table The table to update.
|
* @param string $table The table to update.
|
||||||
* @param string $column The column/field to check.
|
* @param string $column The column/field to check.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return bool
|
||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
protected function checkDefault(string $table, string $column): void
|
protected function checkDefault(string $table, string $column): bool
|
||||||
{
|
{
|
||||||
// Retrieve the expected column configuration
|
// Retrieve the expected column configuration
|
||||||
$expected = $this->table->get($table, $column, 'db');
|
$expected = $this->table->get($table, $column, 'db');
|
||||||
|
|
||||||
// Skip updates if the column is auto_increment
|
// Skip updates if the column is auto_increment
|
||||||
if (isset($expected['auto_increment']) && $expected['auto_increment'])
|
if (isset($expected['auto_increment']) && $expected['auto_increment'] === true)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the current column configuration
|
// Retrieve the current column configuration
|
||||||
$current = $this->columns[$column];
|
$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
|
// Determine the new default value based on the expected settings
|
||||||
$type = $expected['type'] ?? 'TEXT';
|
$type = $expected['type'] ?? 'TEXT';
|
||||||
$db_default = isset($expected['default']) ? $expected['default'] : null;
|
$db_default = isset($expected['default']) ? $expected['default'] : null;
|
||||||
@ -407,7 +408,17 @@
|
|||||||
if (is_numeric($newDefault) && $this->adjustExistingDefaults($table, $column, $current->Default, $newDefault))
|
if (is_numeric($newDefault) && $this->adjustExistingDefaults($table, $column, $current->Default, $newDefault))
|
||||||
{
|
{
|
||||||
$this->success[] = "Success: updated the ($column) defaults in $table table.";
|
$this->success[] = "Success: updated the ($column) defaults in $table table.";
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_string($expected['default']) && strtoupper($expected['default']) === 'EMPTY' &&
|
||||||
|
is_string($current->Default) && strpos($current->Default, 'EMPTY') !== false)
|
||||||
|
{
|
||||||
|
return true; // little fix
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -459,56 +470,52 @@
|
|||||||
*
|
*
|
||||||
* This function checks if there's a significant difference between the current
|
* 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.
|
* 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
|
* It ignores display width for numeric types where MySQL considers these attributes
|
||||||
* these attributes irrelevant for storage.
|
* irrelevant for storage but considers size and other modifiers for types like VARCHAR.
|
||||||
*
|
*
|
||||||
* @param string $currentType The current data type from the database schema.
|
* @param string $currentType The current data type from the database schema.
|
||||||
* @param string $expectedType The expected data type to validate against.
|
* @param string $expectedType The expected data type to validate against.
|
||||||
*
|
*
|
||||||
* @return bool Returns true if the data type change is significant, otherwise false.
|
* @return bool Returns true if the data type change is significant, otherwise false.
|
||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
function isDataTypeChangeSignificant(string $currentType, string $expectedType): bool
|
protected function isDataTypeChangeSignificant(string $currentType, string $expectedType): bool
|
||||||
{
|
{
|
||||||
// we only do this for Joomla 4+
|
// Normalize both input types to lowercase for case-insensitive comparison
|
||||||
if ($this->currentVersion != 3)
|
$currentType = strtolower($currentType);
|
||||||
|
$expectedType = strtolower($expectedType);
|
||||||
|
|
||||||
|
// Regex to extract the base data type and numeric parameters with named groups
|
||||||
|
$typePattern = '/^(?<datatype>\w+)(\((?<params>\d+(,\d+)?)\))?/';
|
||||||
|
|
||||||
|
// Match types and parameters
|
||||||
|
preg_match($typePattern, $currentType, $currentMatches);
|
||||||
|
preg_match($typePattern, $expectedType, $expectedMatches);
|
||||||
|
|
||||||
|
// Compare base types
|
||||||
|
if ($currentMatches['datatype'] !== $expectedMatches['datatype'])
|
||||||
{
|
{
|
||||||
// Normalize both input types to lowercase for case-insensitive comparison
|
return true; // Base types differ
|
||||||
$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
|
// Define types where size and other modifiers are irrelevant
|
||||||
if (strcasecmp($currentType, $expectedType) == 0)
|
$sizeIrrelevantTypes = [
|
||||||
|
'int', 'tinyint', 'smallint', 'mediumint', 'bigint',
|
||||||
|
'float', 'double', 'decimal', 'numeric' // Numeric types where display width is irrelevant
|
||||||
|
];
|
||||||
|
|
||||||
|
// If the type is not in the size irrelevant list, compare full definitions
|
||||||
|
if (!in_array($currentMatches['datatype'], $sizeIrrelevantTypes))
|
||||||
{
|
{
|
||||||
return false; // No significant change
|
return $currentType !== $expectedType; // Use full definition for types where size matters
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // Significant datatype change detected
|
// For size irrelevant types, only compare base type, ignoring size and unsigned
|
||||||
|
$currentBaseType = preg_replace('/\(\d+(,\d+)?\)|unsigned/', '', $currentType);
|
||||||
|
$expectedBaseType = preg_replace('/\(\d+(,\d+)?\)|unsigned/', '', $expectedType);
|
||||||
|
|
||||||
|
// Perform a final comparison for numeric types ignoring size
|
||||||
|
return $currentBaseType !== $expectedBaseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -657,7 +664,7 @@
|
|||||||
*/
|
*/
|
||||||
protected function getDefaultValue(string $type, ?string $defaultValue, bool $pure = false): string
|
protected function getDefaultValue(string $type, ?string $defaultValue, bool $pure = false): string
|
||||||
{
|
{
|
||||||
if ($defaultValue === null || strtoupper($defaultValue) === 'EMPTY')
|
if ($defaultValue === null)
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@ -669,5 +676,50 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply and quote the default value
|
// Apply and quote the default value
|
||||||
return $pure ? $defaultValue : " DEFAULT " . $this->db->quote($defaultValue);
|
$sql_default = $this->quote($defaultValue);
|
||||||
|
return $pure ? $defaultValue : " DEFAULT $sql_default";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a value based on data type
|
||||||
|
*
|
||||||
|
* @param mixed $value The value to set
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @since 3.2.0
|
||||||
|
**/
|
||||||
|
protected function quote($value)
|
||||||
|
{
|
||||||
|
if ($value === null) // hmm the null does pose an issue (will keep an eye on this)
|
||||||
|
{
|
||||||
|
return 'NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($value) && strtoupper($value) === 'EMPTY')
|
||||||
|
{
|
||||||
|
return "''";
|
||||||
|
}
|
||||||
|
elseif (is_numeric($value))
|
||||||
|
{
|
||||||
|
if (filter_var($value, FILTER_VALIDATE_INT))
|
||||||
|
{
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
elseif (filter_var($value, FILTER_VALIDATE_FLOAT))
|
||||||
|
{
|
||||||
|
return (float) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (is_bool($value)) // not sure if this will work well (but its correct)
|
||||||
|
{
|
||||||
|
return $value ? 'TRUE' : 'FALSE';
|
||||||
|
}
|
||||||
|
// For date and datetime values
|
||||||
|
elseif ($value instanceof \DateTime)
|
||||||
|
{
|
||||||
|
return $this->db->quote($value->format('Y-m-d H:i:s'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For other data types, just escape it
|
||||||
|
return $this->db->quote($value);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user