Release of v5.0.4-beta1

Add first classes for the new import engine.
This commit is contained in:
Robot 2024-11-07 10:55:30 +02:00
parent 147f2f4cb7
commit 703e8e0133
Signed by: Robot
GPG Key ID: 14DECD44E7E1BB95
44 changed files with 2790 additions and 121 deletions

View File

@ -1,9 +1,6 @@
# v5.0.4-alpha3
# v5.0.4-beta1
- Fix Save failed issue in dynamicGet. #1148
- Move all [TEXT, EDITOR, TEXTAREA] fields from [NOT NULL] to [NULL]
- Add the DateHelper class and improve the date methods.
- Add simple SessionHelper class.
- Add first classes for the new import engine.
# v5.0.4-alpha
@ -13,7 +10,11 @@
- Added new import powers for custom import of spreadsheets.
- Move the setDocument and _prepareDocument above the display in the site view and custom admin view.
- Update the trashhelper layout to work in Joomla 5.
- Add AllowDynamicProperties (Joomla 4+5) to view class to allow Custom Dynamic Get methods to work without issues.
- Add AllowDynamicProperties (Joomla 4+5) to view class to allow Custom Dynamic Get methods to work without issues.
- Fix Save failed issue in dynamicGet. #1148
- Move all [TEXT, EDITOR, TEXTAREA] fields from [NOT NULL] to [NULL]
- Add the DateHelper class and improve the date methods.
- Add simple SessionHelper class.
# v5.0.3

View File

@ -3270,7 +3270,7 @@ class Com_ComponentbuilderInstallerScript implements InstallerScriptInterface
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"/>
</a>
<h3>Upgrade to Version 5.0.4-alpha3 Was Successful! Let us know if anything is not working as expected.</h3></div>';
<h3>Upgrade to Version 5.0.4-beta1 Was Successful! Let us know if anything is not working as expected.</h3></div>';
// Add/Update component in the action logs extensions table.
$this->setActionLogsExtensions();

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!
You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (5.0.4-alpha3) 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 (5.0.4-beta1) 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)
@ -144,14 +144,14 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
+ *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
+ *First Build*: 30th April, 2015
+ *Last Build*: 13th October, 2024
+ *Version*: 5.0.4-alpha3
+ *Last Build*: 7th November, 2024
+ *Version*: 5.0.4-beta1
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **871857**
+ *Line count*: **890506**
+ *Field count*: **2104**
+ *File count*: **6028**
+ *Folder count*: **633**
+ *File count*: **6228**
+ *Folder count*: **636**
> This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com).
> Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io)

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!
You can install it quite easily and with no limitations. On [gitea](https://git.vdm.dev/joomla/Component-Builder/tags) is the latest release (5.0.4-alpha3) 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 (5.0.4-beta1) 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)
@ -144,14 +144,14 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
+ *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
+ *First Build*: 30th April, 2015
+ *Last Build*: 13th October, 2024
+ *Version*: 5.0.4-alpha3
+ *Last Build*: 7th November, 2024
+ *Version*: 5.0.4-beta1
+ *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt
+ *Line count*: **871857**
+ *Line count*: **890506**
+ *Field count*: **2104**
+ *File count*: **6028**
+ *Folder count*: **633**
+ *File count*: **6228**
+ *Folder count*: **636**
> This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](https://www.joomlacomponentbuilder.com).
> Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io)

View File

@ -4570,6 +4570,7 @@ COM_COMPONENTBUILDER_DYNAMIC_GET_YES="Yes"
COM_COMPONENTBUILDER_DYNAMIC_GET_YY="yy"
COM_COMPONENTBUILDER_DYNAMIC_GET_Z="z"
COM_COMPONENTBUILDER_DYNAMIC_GET_ZZ="zz"
COM_COMPONENTBUILDER_D_ROWS_PROCESSED_SUCCESS_RATE_TWOF_IMPORT_SUCCESSFUL="%d rows processed. Success rate: %.2f%%. Import successful!"
COM_COMPONENTBUILDER_EDIT="Edit"
COM_COMPONENTBUILDER_EDITCREATE_SITE_VIEW="Edit/Create Site View"
COM_COMPONENTBUILDER_EDITING="Editing"
@ -5440,6 +5441,7 @@ COM_COMPONENTBUILDER_ID="id"
COM_COMPONENTBUILDER_ID_MISMATCH_WAS_DETECTED_WITH_THE_SSSS_GUI_CODE_FIELD_SO_THE_PLACEHOLDER_WAS_NOT_SET="ID mismatch was detected with the %s.%s.%s.%s GUI code field. So the placeholder was not set."
COM_COMPONENTBUILDER_IEMAILI_BSB="<i>Email:</i> <b>%s</b>"
COM_COMPONENTBUILDER_IMPORT_BY_GUID_ONLY="Import by GUID only!"
COM_COMPONENTBUILDER_IMPORT_FAILED_D_ROWS_PROCESSED_WITH_ONLY_D_SUCCESSES_ERROR_RATE_TWOF="Import failed. %d rows processed with only %d successes. Error rate: %.2f%%."
COM_COMPONENTBUILDER_IMPORT_S="Import %s"
COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_JOOMLA_COMPONENTS="Select the file to import data to joomla_components."
COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_LANGUAGE_TRANSLATIONS="Select the file to import data to language_translations."
@ -7598,6 +7600,7 @@ COM_COMPONENTBUILDER_NO_NAMESPACE_FOUND="No Namespace Found"
COM_COMPONENTBUILDER_NO_NEED_TO_GET_IT_SINCE_IT_IS_ALREADY_IN_SYNC_WITH_YOUR_LOCAL_VERSION="No need to get it since it is already in sync with your local version"
COM_COMPONENTBUILDER_NO_PATHS_FOUND="No Paths Found"
COM_COMPONENTBUILDER_NO_RESULTS_MATCH="No results match"
COM_COMPONENTBUILDER_NO_ROWS_WERE_PROCESSED="No rows were processed."
COM_COMPONENTBUILDER_NO_SELECTION_DETECTED="No selection detected"
COM_COMPONENTBUILDER_NO_SNIPPETS_WERE_SELECTED_PLEASE_MAKE_A_SELECTION_AND_TRY_AGAIN="No snippets were selected, please make a selection and try again!"
COM_COMPONENTBUILDER_NO_S_FOUND="No %s Found"

View File

@ -21,6 +21,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Factory as CFactory;
use Joomla\CMS\Version;
use VDM\Joomla\Componentbuilder\File\Factory as FileFactory;
use VDM\Joomla\Componentbuilder\Import\Factory as ImportFactory;
use VDM\Joomla\Abstraction\Console\Import;
use VDM\Joomla\Utilities\ArrayHelper as UtilitiesArrayHelper;
use VDM\Joomla\Utilities\StringHelper;
use Joomla\CMS\Uri\Uri;
@ -76,6 +77,8 @@ class CompilerController extends AdminController
* FileFactory
* Adding this so that the import factory gets build for Super Powers
* ImportFactory
* Adding this so that the import cli gets build for Super Powers
* Import
*/
/**

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="5.0" method="upgrade">
<name>COM_COMPONENTBUILDER</name>
<creationDate>13th October, 2024</creationDate>
<creationDate>7th November, 2024</creationDate>
<author>Llewellyn van der Merwe</author>
<authorEmail>joomla@vdm.io</authorEmail>
<authorUrl>https://dev.vdm.io</authorUrl>
<copyright>Copyright (C) 2015 Vast Development Method. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<version>5.0.4-alpha3</version>
<version>5.0.4-beta1</version>
<description><![CDATA[
<h1>Component Builder (v.5.0.4-alpha3)</h1>
<h1>Component Builder (v.5.0.4-beta1)</h1>
<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.

View File

@ -131,13 +131,13 @@
<element>pkg_component_builder</element>
<type>package</type>
<client>site</client>
<version>5.0.4-alpha3</version>
<version>5.0.4-beta1</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/v5.0.4-alpha3.zip</downloadurl>
<downloadurl type="full" format="zip">https://git.vdm.dev/api/v1/repos/joomla/pkg-component-builder/archive/v5.0.4-beta1.zip</downloadurl>
</downloads>
<tags>
<tag>alpha</tag>
<tag>beta</tag>
</tags>
<maintainer>Llewellyn van der Merwe</maintainer>
<maintainerurl>https://dev.vdm.io</maintainerurl>

View File

@ -12,7 +12,7 @@
namespace VDM\Joomla\Abstraction;
use VDM\Joomla\Interfaces\Tableinterface;
use VDM\Joomla\Interfaces\TableInterface;
/**
@ -20,7 +20,7 @@ use VDM\Joomla\Interfaces\Tableinterface;
*
* @since 3.2.0
*/
abstract class BaseTable implements Tableinterface
abstract class BaseTable implements TableInterface
{
/**
* All areas/views/tables with their field details

View File

@ -0,0 +1,258 @@
<?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\Abstraction\Console;
use Joomla\CMS\Factory;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use VDM\Joomla\Componentbuilder\Import\Factory as ImportFactory;
use VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet\ImportCliInterface as ImportEngine;
use VDM\Joomla\Data\Items;
use VDM\Joomla\Utilities\Component\Helper;
/**
* Console Import
*
* @since 5.0.2
*/
abstract class Import extends AbstractCommand
{
/**
* The Items Class.
*
* @var Items
* @since 5.0.2
*/
protected Items $items;
/**
* The Import Class.
*
* @var ImportEngine
* @since 5.0.2
*/
protected ImportEngine $import;
/**
* The queue table name.
*
* @var string
* @since 5.0.2
*/
protected string $queueTable;
/**
* The queue status field
*
* @var string
* @since 5.0.2
*/
protected string $queueStatusField;
/**
* The queue awaiting status
*
* @var int
* @since 5.0.2
*/
protected int $queueWaitState;
/**
* The queue processing status
*
* @var int
* @since 5.0.2
*/
protected int $queueProcessingState;
/**
* The main import target name.
*
* @var string
* @since 5.0.2
*/
protected string $targetName;
/**
* The target import class.
*
* @var string
* @since 5.0.2
*/
protected string $targetImportClass;
/**
* The default command name.
*
* @var string
* @since 5.0.2
*/
protected static $defaultName;
/**
* Constructor.
*
* @param string|null $name The name of the command; if the name is empty and no default is set, a name must be set in the configure() method
*
* @since 5.0.2
*/
public function __construct(?string $name = null)
{
// make sure we know what component we are working with
Helper::setOption('com_componentbuilder');
// Load administrator language file for backend
$lang = Factory::getLanguage();
$lang->load('com_componentbuilder', JPATH_ADMINISTRATOR);
$this->items = ImportFactory::_('Data.Items');
$this->import = ImportFactory::_($this->targetImportClass);
parent::__construct($name);
}
/**
* Configures the CLI command, setting up the description and help text.
*
* This command parses the import queue and imports items that are still in the queue.
* It is useful for automatically processing pending item imports in the virtual warehouse.
*
* @return void
* @since 5.0.2
*/
protected function configure(): void
{
$this->setDescription("Processes the import queue and {$this->targetName} imports all spreadsheets that are still in the queue.");
$this->setHelp(
<<<EOF
The <info>%command.name%</info> command parses the import queue and processes all {$this->targetName} spreadsheets that are still pending import.
This is useful for keeping the system up-to-date with incoming data.
Usage:
<info>php joomla.php %command.name%</info>
EOF);
}
/**
* Executes the CLI command, processing each spreadsheet in the import queue.
*
* @param InputInterface $input The input to inject into the command.
* @param OutputInterface $output The output to inject into the command.
*
* @return int The command exit code (0 for success).
* @since 5.0.2
*/
protected function doExecute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
// Output the title for the task
$io->title("Component Builder: {$this->targetName} import status");
// Get all imports in the queue that are in waiting state
if (($queue = $this->items->table($this->queueTable)->get([$this->queueWaitState], $this->queueStatusField)) === null)
{
// Get the current date and time
$timestamp = date('Y-m-d H:i:s');
// Output the notice of no imports to be done
$io->info("No {$this->targetName} imports found in the queue. Idle at {$timestamp}.");
return 0;
}
// take spreadsheets out of queue
$this->items->table($this->queueTable)->set(array_map(function($item) {
return [
'guid' => $item->guid,
$this->queueStatusField => $this->queueProcessingState
];
}, $queue));
// size of the queue
$numberSteps = count((array) $queue);
// Output initial task information
$io->info("Initiating import for {$numberSteps} {$this->targetName} spreadsheet(s) in the queue.");
$io->newLine(2);
// Create a progress bar for the overall import process
$progressBar = $io->createProgressBar($numberSteps);
$progressBar->start();
// Track success and failure counts
$successCount = 0;
$failureCount = 0;
// Import one spreadsheet at a time
foreach ($queue as $spreadsheet)
{
$io->newLine(2);
// Output the current spreadsheet being processed
$io->section("Processing spreadsheet #{$spreadsheet->guid}...");
// Import the data found in the spreadsheet
$this->import->data($spreadsheet);
// Get the completion message
$completion = $this->import->message();
// Track success based on completion message
if ($completion->message_success)
{
$successCount++;
// Output the success message for this spreadsheet
$io->success($completion->message_success);
}
// Track failure based on completion message
if ($completion->message_error)
{
$failureCount++;
// Output the error message for this spreadsheet
$io->error($completion->message_error);
}
// Advance the main progress bar by one step
sleep(1);
$progressBar->advance();
$io->newLine(1);
}
// Finish the main progress bar
$progressBar->finish();
$io->newLine(2);
// Calculate the success and failure percentages
$totalProcessed = $successCount + $failureCount;
$successRate = ($totalProcessed > 0) ? round(($successCount / $totalProcessed) * 100) : 0;
$failureRate = ($totalProcessed > 0) ? round(($failureCount / $totalProcessed) * 100) : 0;
// Get the current date and time
$timestamp = date('Y-m-d H:i:s');
// Output the success and failure summary with the timestamp
$io->info("The {$this->targetName} import finished: {$successRate}% success, {$failureRate}% failure. Completed at {$timestamp}.");
$io->newLine(1);
return 0;
}
}

View File

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

View File

@ -38,6 +38,14 @@ abstract class Database
*/
protected string $table;
/**
* Date format to return
*
* @var string
* @since 5.0.2
*/
protected string $dateFormat = 'Y-m-d H:i:s';
/**
* Constructor
*
@ -62,23 +70,32 @@ abstract class Database
**/
protected function quote($value)
{
if ($value === null) // hmm the null does pose an issue (will keep an eye on this)
if ($value === null)
{
return 'NULL';
}
if (is_numeric($value))
{
// If the value is a numeric string (e.g., "0123"), treat it as a string to preserve the format
if (is_string($value) && ltrim($value, '0') !== $value)
{
return $this->db->quote($value);
}
if (filter_var($value, FILTER_VALIDATE_INT))
{
return (int) $value;
}
elseif (filter_var($value, FILTER_VALIDATE_FLOAT))
if (filter_var($value, FILTER_VALIDATE_FLOAT))
{
return (float) $value;
}
}
elseif (is_bool($value)) // not sure if this will work well (but its correct)
// Handle boolean values
if (is_bool($value))
{
return $value ? 'TRUE' : 'FALSE';
}
@ -86,10 +103,10 @@ abstract class Database
// For date and datetime values
if ($value instanceof \DateTime)
{
return $this->db->quote($value->format('Y-m-d H:i:s'));
return $this->db->quote($value->format($this->getDateFormat()));
}
// For other data types, just escape it
// For other types of values, quote as string
return $this->db->quote($value);
}
@ -110,6 +127,17 @@ abstract class Database
}
return $table;
}
/**
* Get the date format to return in the quote
*
* @return string
* @since 5.0.2
**/
protected function getDateFormat(): string
{
return $this->dateFormat;
}
}

View File

@ -14,7 +14,7 @@ namespace VDM\Joomla\Abstraction;
use VDM\Joomla\Utilities\StringHelper;
use VDM\Joomla\Utilities\ArrayHelper;
use VDM\Joomla\Interfaces\Tableinterface as Table;
use VDM\Joomla\Interfaces\TableInterface as Table;
use VDM\Joomla\Interfaces\ModelInterface;
@ -109,7 +109,7 @@ abstract class Model implements ModelInterface
/**
* Model a value of multiple items
* Example: $this->items(Array, 'value_key', 'table_name');
* Example: $this->values(Array, 'value_key', 'table_name');
*
* @param array|null $items The array of values
* @param string $field The field key

View File

@ -14,7 +14,7 @@ namespace VDM\Joomla\Abstraction;
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;

View File

@ -14,7 +14,7 @@ namespace VDM\Joomla\Abstraction;
use Joomla\CMS\Factory;
use VDM\Joomla\Interfaces\SchemaInterface as Schema;
use VDM\Joomla\Interfaces\Tableinterface as Table;
use VDM\Joomla\Interfaces\TableInterface as Table;
use VDM\Joomla\Utilities\ClassHelper;
use VDM\Joomla\Interfaces\SchemaCheckerInterface;

View File

@ -0,0 +1,130 @@
<?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\Import;
use Joomla\CMS\Language\Text;
use VDM\Joomla\Componentbuilder\Import\Data;
use VDM\Joomla\Componentbuilder\Interfaces\ImportStatusInterface as Status;
use VDM\Joomla\Componentbuilder\Interfaces\ImportMessageInterface as Message;
use VDM\Joomla\Componentbuilder\Interfaces\ImportAssessorInterface;
/**
* Import Assessor Class
*
* @since 4.0.3
*/
final class Assessor implements ImportAssessorInterface
{
/**
* The Data Class.
*
* @var Data
* @since 4.0.3
*/
protected Data $data;
/**
* The Import Status Class.
*
* @var Status
* @since 4.0.3
*/
protected Status $status;
/**
* The Import Message Class.
*
* @var Message
* @since 4.0.3
*/
protected Message $message;
/**
* Constants for defining the success threshold
* Minimum success rate to consider the import successful
*
* @since 4.0.3
*/
private const SUCCESS_THRESHOLD = 0.80;
/**
* Constructor.
*
* @param Data $data The Data Class.
* @param Status $status The Import Status Class.
* @param Message $message The Import Message Class.
*
* @since 4.0.3
*/
public function __construct(Data $data, Status $status, Message $message)
{
$this->data = $data;
$this->status = $status;
$this->message = $message;
}
/**
* Evaluates the import process and sets the success/error message based on the success rate.
*
* @param int $rowCounter Total number of rows processed.
* @param int $successCounter Number of successfully processed rows.
* @param int $errorCounter Number of rows that failed to process.
*
* @return void
* @since 4.0.3
*/
public function evaluate(int $rowCounter, int $successCounter, int $errorCounter): void
{
// No rows processed case
if ($rowCounter === 0)
{
$this->message->addError(Text::_('COM_COMPONENTBUILDER_NO_ROWS_WERE_PROCESSED'));
if (($guid = $this->data->get('import.guid')) !== null)
{
$this->status->set(4, $guid); // Status 4 => completed with errors
}
return;
}
$successRate = $successCounter / $rowCounter;
$errorRate = (1 - $successRate) * 100;
$successPercentage = $successRate * 100;
// Determine appropriate message based on success rate
if ($successRate >= self::SUCCESS_THRESHOLD)
{
$this->message->addSuccess(Text::sprintf('COM_COMPONENTBUILDER_D_ROWS_PROCESSED_SUCCESS_RATE_TWOF_IMPORT_SUCCESSFUL',
$rowCounter,
$successPercentage
));
}
else
{
$this->message->addError(Text::sprintf('COM_COMPONENTBUILDER_IMPORT_FAILED_D_ROWS_PROCESSED_WITH_ONLY_D_SUCCESSES_ERROR_RATE_TWOF',
$rowCounter,
$successCounter,
$errorRate
));
}
if (($guid = $this->data->get('import.guid')) !== null)
{
// Update import status based on success rate
$importStatus = ($successPercentage == 100) ? 3 : 4; // 3 => completed, 4 => completed with errors
$this->status->set($importStatus, $guid);
}
}
}

View File

@ -0,0 +1,26 @@
<?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\Import;
use VDM\Joomla\Abstraction\Registry;
/**
* Import Data Registry
*
* @since 3.2.0
*/
class Data extends Registry
{
}

View File

@ -12,10 +12,12 @@
namespace VDM\Joomla\Componentbuilder\Import;
use Joomla\DI\Container;
use VDM\Joomla\Service\Table;
use VDM\Joomla\Service\Database;
use VDM\Joomla\Service\Model;
use VDM\Joomla\Service\Data;
use VDM\Joomla\Componentbuilder\Import\Service\Import;
use VDM\Joomla\Componentbuilder\File\Service\File;
use VDM\Joomla\Componentbuilder\Service\Spreadsheet;
use VDM\Joomla\Interfaces\FactoryInterface;
@ -50,6 +52,7 @@ abstract class Factory extends ExtendingFactory implements FactoryInterface
->registerServiceProvider(new Database())
->registerServiceProvider(new Model())
->registerServiceProvider(new Data())
->registerServiceProvider(new Import())
->registerServiceProvider(new File())
->registerServiceProvider(new Spreadsheet());
}

View File

@ -0,0 +1,270 @@
<?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\Import;
use VDM\Joomla\Interfaces\TableValidatorInterface as Validator;
use VDM\Joomla\Interfaces\Data\ItemInterface as DataItem;
use VDM\Joomla\Componentbuilder\Interfaces\ImportRowInterface as Row;
use VDM\Joomla\Utilities\GuidHelper;
use VDM\Joomla\Componentbuilder\Interfaces\ImportItemInterface;
/**
* Import Item Class
*
* @since 4.0.3
*/
final class Item implements ImportItemInterface
{
/**
* The Table Validator Class.
*
* @var Validator
* @since 4.0.3
*/
protected Validator $validator;
/**
* The Item Class.
*
* @var Item
* @since 4.0.3
*/
protected DataItem $item;
/**
* The Import Row Class.
*
* @var Row
* @since 4.0.3
*/
protected Row $row;
/**
* Constructor.
*
* @param Validator $validator The Table ValidatorI Class.
* @param DataItem $item The Item Class.
* @param Row $row The Import Row Class.
*
* @since 4.0.3
*/
public function __construct(Validator $validator, DataItem $item, Row $row)
{
$this->validator = $validator;
$this->item = $item;
$this->row = $row;
}
/**
* Get the item from the import row values and ensure it is valid
*
* @param string $table The table these columns belongs to.
* @param array $columns The columns to extract.
*
* @return array|null
* @since 4.0.3
*/
public function get(string $table, array $columns): ?array
{
$item = [];
foreach ($columns as $column => $map)
{
if (($value = $this->row->getValue($column)) !== null && !isset($item[$map['name']]))
{
// get the valid importable value
$item[$map['name']] = $this->getImportValue($value, $map['name'], $table, $map['link'] ?? null);
// remove value from global row values set
$this->row->unsetValue($column);
}
}
return $item ?? null;
}
/**
* Get the correct value needed for the import of the related row (item).
*
* @param mixed $value The value from the row.
* @param string $field The field name where the value is being stored.
* @param string $table The table this field belongs to.
* @param array $link The field link values.
*
* @return mixed
* @since 4.0.3
*/
private function getImportValue($value, string $field, string $table, ?array $link)
{
// Validate the link array and return the original value if invalid
if (empty($link) || $link['type'] !== 1 || empty($link['table']) || empty($link['key']) || empty($link['value']))
{
return $this->validImportValue($value, $field, $table);
}
// Handle GUID key with validation via GuidHelper
if ($link['key'] === 'guid' && GuidHelper::item($value, $link['table']))
{
return $value;
}
// Handle numeric ID with validation
if ($link['key'] === 'id' && is_numeric($value) && $this->isValueExists($value, $link))
{
return (int) $value;
}
// Attempt to retrieve the local value
$local_value = $this->getLocalValue($value, $link);
// If no local value exists, create it if necessary
if ($local_value === null)
{
$local_value = $this->setLocalValue($value, $link);
}
return $this->validImportValue($local_value, $field, $table);
}
/**
* Make sure we have a valid import value
*
* @param mixed $value The value.
* @param string $field The field name where the value is being stored.
* @param string $table The table this field belongs to.
*
* @return mixed
* @since 4.0.3
*/
private function validImportValue($value, string $field, string $table)
{
// make sure our value will fit in the database table datatype
return $this->validator->getValid($value, $field, $table);
}
/**
* Helper function to get the local value from the database table.
*
* @param mixed $value The value to search for.
* @param array $link The field link details.
*
* @return mixed|null The local value or null if not found.
* @since 4.0.3
*/
private function getLocalValue($value, array $link)
{
// Attempt to retrieve the value based on the link['value'] and link['key']
$local_value = $this->item->table($link['table'])->value($value, $link['value'], $link['key']);
// If not found, try retrieving by link['key'] and link['key']
if ($local_value === null && $this->isValueExists($value, $link))
{
return $value;
}
return $local_value;
}
/**
* Check if the value exists in the table for the given link.
*
* @param mixed $value The value to check.
* @param array $link The field link details.
*
* @return bool True if the value exists, false otherwise.
* @since 4.0.3
*/
private function isValueExists($value, array $link): bool
{
return $this->item->table($link['table'])->value($value, $link['key'], $link['key']) !== null;
}
/**
* Create a new value in the database table if it doesn't already exist.
*
* @param mixed $value The value to create.
* @param array $link The field link details.
*
* @return mixed|null The newly created value or null if creation failed.
* @since 4.0.3
*/
private function setLocalValue($value, array $link)
{
// Handle GUID creation if the provided value is not valid
if ($link['key'] === 'guid')
{
if (!GuidHelper::valid($value))
{
return $this->insertItemWithGuid($value, $link);
}
return null;
}
// Handle ID creation
if ($link['key'] === 'id')
{
if (!is_numeric($value))
{
return $this->insertItemWithId($value, $link);
}
return null;
}
// could not create local item (we don't have enough details)
return null;
}
/**
* Insert a new item with a GUID.
*
* @param mixed $value The value to insert.
* @param array $link The field link details.
*
* @return string|null The new GUID or null if insertion failed.
* @since 4.0.3
*/
private function insertItemWithGuid($value, array $link): ?string
{
$guid = GuidHelper::get();
$item = (object) [$link['value'] => $value, $link['key'] => $guid];
if ($this->item->table($link['table'])->set($item, $link['key'], 'insert'))
{
return $guid;
}
return null;
}
/**
* Insert a new item with a non-numeric ID.
*
* @param mixed $value The value to insert.
* @param array $link The field link details.
*
* @return mixed|null The new ID or null if insertion failed.
* @since 4.0.3
*/
private function insertItemWithId($value, array $link)
{
$item = (object) [$link['key'] => 0, $link['value'] => $value];
if ($this->item->table($link['table'])->set($item, $link['key'], 'insert'))
{
return $this->item->table($link['table'])->value($value, $link['value'], $link['key']);
}
return null;
}
}

View File

@ -0,0 +1,154 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 4th September, 2022
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Joomla\Componentbuilder\Import;
use VDM\Joomla\Interfaces\TableInterface as Table;
use VDM\Joomla\Componentbuilder\Interfaces\ImportMapperInterface;
/**
* Import Mapper Class
*
* @since 4.0.3
*/
final class Mapper implements ImportMapperInterface
{
/**
* The Table Class.
*
* @var Table
* @since 4.0.3
*/
protected Table $table;
/**
* The current parent table map.
*
* @var array
* @since 4.0.3
*/
private array $parent = [];
/**
* The current join tables map.
*
* @var array
* @since 4.0.3
*/
private array $join = [];
/**
* Constructor.
*
* @param Table $table The Table Class.
*
* @since 4.0.3
*/
public function __construct(Table $table)
{
$this->table = $table;
}
/**
* Set the tables mapper
*
* @param object $map The import file map.
* @param string $parentTable The parent table name.
*
* @return void
* @since 4.0.3
*/
public function set(object $map, string $parentTable): void
{
// always reset these
$this->parent = [];
$this->join = [];
foreach ($map as $row)
{
$target = $row->target ?? null;
if (empty($target))
{
continue;
}
if (($tm = $this->getTableField($target)) !== null)
{
$field = $this->table->get($tm->table, $tm->field);
if ($tm->table === $parentTable)
{
$this->parent[$row->column] = $field;
}
else
{
$this->join[$tm->table][$row->column] = $field;
}
}
}
}
/**
* Get the parent table keys
*
* @return array
* @since 4.0.3
*/
public function getParent(): array
{
return $this->parent;
}
/**
* Get the join tables keys
*
* @return array
* @since 4.0.3
*/
public function getJoin(): array
{
return $this->join;
}
/**
* Get the table and field name
*
* @param string $key The import file key.
*
* @return object|null
* @since 4.0.3
*/
private function getTableField(string $key): ?object
{
// Find the position of the first dot
$dotPosition = strpos($key, '.');
// If no dot is found, return the whole string
if ($dotPosition === false)
{
return null;
}
// Extract the table (before the dot) and the field (after the dot)
$table = substr($key, 0, $dotPosition);
$field = substr($key, $dotPosition + 1);
if ($this->table->exist($table ?? '_error', $field))
{
return (object) ['table' => $table, 'field' => $field];
}
return null;
}
}

View File

@ -0,0 +1,307 @@
<?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\Import;
use VDM\Joomla\Interfaces\Data\UpdateInterface as Update;
use VDM\Joomla\Interfaces\Data\InsertInterface as Insert;
use VDM\Joomla\Utilities\GuidHelper;
use VDM\Joomla\Componentbuilder\Interfaces\ImportMessageInterface;
/**
* Import Messages Class
*
* @since 5.0.2
*/
final class Message implements ImportMessageInterface
{
/**
* The Update Class.
*
* @var Update
* @since 5.0.2
*/
protected Update $update;
/**
* The Insert Class.
*
* @var Insert
* @since 5.0.2
*/
protected Insert $insert;
/**
* The success message bus.
*
* @var array
* @since 5.0.2
*/
private array $success = [];
/**
* The info message bus.
*
* @var array
* @since 5.0.2
*/
private array $info = [];
/**
* The error message bus.
*
* @var array
* @since 5.0.2
*/
private array $error = [];
/**
* The entity GUID value.
*
* @var string
* @since 5.0.2
*/
private ?string $guid = null;
/**
* The entity type value.
*
* @var string|null
* @since 5.0.2
*/
private ?string $entity = null;
/**
* The entity table value.
*
* @var string|null
* @since 5.0.2
*/
private ?string $table = null;
/**
* Constructor.
*
* @param Update $update The Update Class.
* @param Insert $insert The Insert Class.
*
* @since 5.0.2
*/
public function __construct(Update $update, Insert $insert)
{
$this->update = $update;
$this->insert = $insert;
}
/**
* Load an entity that these message belong to
*
* @param string $guid The entity guid these messages must be linked to.
* @param string $entity The entity type these messages must be linked to.
* @param string $table The messages table where these message must be stored.
*
* @return self
* @throws \InvalidArgumentException if any of the parameters are null or empty.
* @since 5.0.2
*/
public function load(string $guid, string $entity, string $table): self
{
if (empty($guid) || empty($entity) || empty($table))
{
throw new \InvalidArgumentException('GUID, entity, and table must not be null or empty.');
}
// set entity details
$this->guid = $guid;
$this->entity = $entity;
$this->table = $table;
return $this;
}
/**
* Get the messages of the last import event
*
* @return object
* @since 5.0.2
*/
public function get(): object
{
return (object) [
'message_success' => $this->success ?? null,
'message_info' => $this->info ?? null,
'message_error' => $this->error ?? null
];
}
/**
* Reset the messages of the last import event
*
* @return void
* @since 5.0.2
*/
public function reset(): void
{
// clear the message bus
$this->success = [];
$this->info = [];
$this->error = [];
$this->guid = null;
$this->entity = null;
$this->table = null;
}
/**
* Archive the messages in the DB of the last import event
*
* @return self
* @throws \InvalidArgumentException if GUID, entity, or table is null.
* @since 5.0.2
*/
public function archive(): self
{
if (empty($this->guid) || empty($this->entity) || empty($this->table))
{
throw new \InvalidArgumentException('GUID, entity, and table must not be null or empty.');
}
// trash all messages from the past
$this->update->table($this->table)->rows([['entity' => $this->guid, 'published' => -2]], 'entity');
return $this;
}
/**
* Set the messages in the DB of the last import event
*
* @return self
* @throws \InvalidArgumentException if GUID, entity, or table is null.
* @since 5.0.2
*/
public function set(): self
{
if (empty($this->guid) || empty($this->entity) || empty($this->table))
{
throw new \InvalidArgumentException('GUID, entity, and table must not be null or empty.');
}
// start message bucket
$messages = [];
// set the success messages
if (!empty($this->success))
{
foreach ($this->success as $message)
{
$message