Update 2024-10-15 03:13:31

This commit is contained in:
Robot 2024-10-15 03:13:39 +02:00
parent 972f531ed3
commit 7effb3035a
Signed by untrusted user: Robot
GPG Key ID: 14DECD44E7E1BB95
22 changed files with 704 additions and 138 deletions

View File

@ -122,6 +122,7 @@ This repository contains an index (see below) of all the approved powers within
- **final class ChunkReadFilter** | [Details](src/9ae018a5-9064-40ed-ad69-9c1ed2a459f5) | [Code](src/9ae018a5-9064-40ed-ad69-9c1ed2a459f5/code.php) | [Settings](src/9ae018a5-9064-40ed-ad69-9c1ed2a459f5/settings.json) | SPK: `Super---9ae018a5_9064_40ed_ad69_9c1ed2a459f5---Power`
- **final class Exporter** | [Details](src/e250638e-4a50-41f9-9172-db3e7f174d26) | [Code](src/e250638e-4a50-41f9-9172-db3e7f174d26/code.php) | [Settings](src/e250638e-4a50-41f9-9172-db3e7f174d26/settings.json) | SPK: `Super---e250638e_4a50_41f9_9172_db3e7f174d26---Power`
- **final class FileReader** | [Details](src/dcb0e061-f337-44f7-87f2-f5c5fb9ce917) | [Code](src/dcb0e061-f337-44f7-87f2-f5c5fb9ce917/code.php) | [Settings](src/dcb0e061-f337-44f7-87f2-f5c5fb9ce917/settings.json) | SPK: `Super---dcb0e061_f337_44f7_87f2_f5c5fb9ce917---Power`
- **final class Header** | [Details](src/fd3f322a-082d-4579-93ad-3352c5adfc71) | [Code](src/fd3f322a-082d-4579-93ad-3352c5adfc71/code.php) | [Settings](src/fd3f322a-082d-4579-93ad-3352c5adfc71/settings.json) | SPK: `Super---fd3f322a_082d_4579_93ad_3352c5adfc71---Power`
- **final class Importer** | [Details](src/c4169332-3914-400e-b861-972b2d465963) | [Code](src/c4169332-3914-400e-b861-972b2d465963/code.php) | [Settings](src/c4169332-3914-400e-b861-972b2d465963/settings.json) | SPK: `Super---c4169332_3914_400e_b861_972b2d465963---Power`
- **Namespace**: [VDM\Joomla\Componentbuilder\Table](#vdm-joomla-componentbuilder-table)
@ -182,6 +183,10 @@ This repository contains an index (see below) of all the approved powers within
- **Namespace**: [VDM\Joomla\Componentbuilder\File\Service](#vdm-joomla-componentbuilder-file-service)
- **class File** | [Details](src/202ccd9e-dfcf-4cde-a0ce-bde1fd27f088) | [Code](src/202ccd9e-dfcf-4cde-a0ce-bde1fd27f088/code.php) | [Settings](src/202ccd9e-dfcf-4cde-a0ce-bde1fd27f088/settings.json) | SPK: `Super---202ccd9e_dfcf_4cde_a0ce_bde1fd27f088---Power`
- **Namespace**: [VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet](#vdm-joomla-componentbuilder-interfaces-spreadsheet)
- **interface FileReaderInterface** | [Details](src/61d1146f-2c2e-4e42-8492-d076f945cf35) | [Code](src/61d1146f-2c2e-4e42-8492-d076f945cf35/code.php) | [Settings](src/61d1146f-2c2e-4e42-8492-d076f945cf35/settings.json) | SPK: `Super---61d1146f_2c2e_4e42_8492_d076f945cf35---Power`
- **interface RowDataProcessorInterface** | [Details](src/9ffc54fa-a71e-412f-bc8b-064fc3b69167) | [Code](src/9ffc54fa-a71e-412f-bc8b-064fc3b69167/code.php) | [Settings](src/9ffc54fa-a71e-412f-bc8b-064fc3b69167/settings.json) | SPK: `Super---9ffc54fa_a71e_412f_bc8b_064fc3b69167---Power`
- **Namespace**: [VDM\Joomla\Componentbuilder\Utilities\Exception](#vdm-joomla-componentbuilder-utilities-exception)
- **class NoUserIdFoundException** | [Details](src/1c10a5f1-204d-4f17-ad9f-0e0684f2030d) | [Code](src/1c10a5f1-204d-4f17-ad9f-0e0684f2030d/code.php) | [Settings](src/1c10a5f1-204d-4f17-ad9f-0e0684f2030d/settings.json) | SPK: `Super---1c10a5f1_204d_4f17_ad9f_0e0684f2030d---Power`

View File

@ -0,0 +1,57 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# interface FileReaderInterface (Details)
> namespace: **VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet**
```uml
@startuml
interface FileReaderInterface #Lavender {
+ read(string $filePath, int $startRow, ...) : \Generator
}
note right of FileReaderInterface::read
Stream rows from a CSV or Excel file one by one using yield.
since: 3.2.0
return: \Generator
arguments:
string $filePath
int $startRow
int $chunkSize
end note
@enduml
```
The Power feature in JCB allows you to write PHP classes and their implementations, making it easy to include them in your Joomla project. JCB handles linking, autoloading, namespacing, and folder structure creation for you.
By using the SPK (Super Power Key) in your custom code (replacing the class name in your code with the SPK), JCB will automatically pull the power from the repository into your project. This makes it available in your JCB instance, allowing you to edit it and include the class in your generated Joomla component.
JCB uses placeholders like [[[`NamespacePrefix`]]] and [[[`ComponentNamespace`]]] in namespacing to prevent collisions and improve reusability across different JCB systems. You can also set the **JCB powers path** globally or per component under the **Dynamic Integration** tab, providing flexibility and easy maintainability.
To add this specific Power to your project in JCB:
> simply use this SPK
```
Super---61d1146f_2c2e_4e42_8492_d076f945cf35---Power
```
> remember to replace the `---` with `___` to activate this Power in your code
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,34 @@
<?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\Interfaces\Spreadsheet;
/**
* Spreadsheet File Reader Interface
*
* @since 3.2.2
*/
interface FileReaderInterface
{
/**
* Stream rows from a CSV or Excel file one by one using yield.
*
* @param string $filePath The path to the file.
* @param int $startRow The starting row index.
* @param int $chunkSize The number of rows to read per chunk.
*
* @return \Generator A generator that yields each row as an array.
* @since 3.2.0
*/
public function read(string $filePath, int $startRow, int $chunkSize): \Generator;
}

View File

@ -0,0 +1,11 @@
/**
* Stream rows from a CSV or Excel file one by one using yield.
*
* @param string $filePath The path to the file.
* @param int $startRow The starting row index.
* @param int $chunkSize The number of rows to read per chunk.
*
* @return \Generator A generator that yields each row as an array.
* @since 3.2.0
*/
public function read(string $filePath, int $startRow, int $chunkSize): \Generator;

View File

@ -0,0 +1,19 @@
{
"add_head": "0",
"add_licensing_template": "2",
"extends": "",
"guid": "61d1146f-2c2e-4e42-8492-d076f945cf35",
"implements": null,
"load_selection": null,
"name": "FileReaderInterface",
"power_version": "1.0.0",
"system_name": "JCB.Interfaces.Spreadsheet.FileReaderInterface",
"type": "interface",
"use_selection": null,
"extendsinterfaces": null,
"namespace": "[[[NamespacePrefix]]]\\Joomla\\[[[ComponentNamespace]]].Interfaces.Spreadsheet.FileReaderInterface",
"description": "Spreadsheet File Reader Interface\r\n\r\n@since 3.2.2",
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 4th September, 2022\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": "",
"composer": ""
}

View File

@ -0,0 +1,51 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# interface RowDataProcessorInterface (Details)
> namespace: **VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet**
```uml
@startuml
interface RowDataProcessorInterface #Lavender {
+ process(Row $row) : mixed
}
note right of RowDataProcessorInterface::process
Processes the given spreadsheet row and returns it in a specific format.
return: mixed
end note
@enduml
```
The Power feature in JCB allows you to write PHP classes and their implementations, making it easy to include them in your Joomla project. JCB handles linking, autoloading, namespacing, and folder structure creation for you.
By using the SPK (Super Power Key) in your custom code (replacing the class name in your code with the SPK), JCB will automatically pull the power from the repository into your project. This makes it available in your JCB instance, allowing you to edit it and include the class in your generated Joomla component.
JCB uses placeholders like [[[`NamespacePrefix`]]] and [[[`ComponentNamespace`]]] in namespacing to prevent collisions and improve reusability across different JCB systems. You can also set the **JCB powers path** globally or per component under the **Dynamic Integration** tab, providing flexibility and easy maintainability.
To add this specific Power to your project in JCB:
> simply use this SPK
```
Super---9ffc54fa_a71e_412f_bc8b_064fc3b69167---Power
```
> remember to replace the `---` with `___` to activate this Power in your code
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,34 @@
<?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\Interfaces\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Row;
/**
* Spreadsheet Row Data Processor Interface
*
* @since 3.2.2
*/
interface RowDataProcessorInterface
{
/**
* Processes the given spreadsheet row and returns it in a specific format.
*
* @param Row $row The row object from the spreadsheet to be processed.
*
* @return mixed Processed row data, could be an array, cell object, or other structures.
*/
public function process(Row $row): mixed;
}

View File

@ -0,0 +1,8 @@
/**
* Processes the given spreadsheet row and returns it in a specific format.
*
* @param Row $row The row object from the spreadsheet to be processed.
*
* @return mixed Processed row data, could be an array, cell object, or other structures.
*/
public function process(Row $row): mixed;

View File

@ -0,0 +1,28 @@
{
"add_head": "0",
"add_licensing_template": "2",
"extends": "",
"guid": "9ffc54fa-a71e-412f-bc8b-064fc3b69167",
"implements": null,
"load_selection": null,
"name": "RowDataProcessorInterface",
"power_version": "1.0.0",
"system_name": "JCB.Interfaces.Spreadsheet.RowDataProcessorInterfa",
"type": "interface",
"use_selection": null,
"extendsinterfaces": null,
"namespace": "[[[NamespacePrefix]]]\\Joomla\\[[[ComponentNamespace]]].Interfaces.Spreadsheet.RowDataProcessorInterface",
"description": "Spreadsheet Row Data Processor Interface\r\n\r\n@since 3.2.2",
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 4th September, 2022\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": "",
"composer": {
"composer0": {
"access_point": "phpspreadsheet\/vendor\/autoload.php",
"namespace": {
"namespace0": {
"use": "PhpOffice\\PhpSpreadsheet\\Worksheet\\Row"
}
}
}
}
}

View File

@ -12,10 +12,18 @@
```uml
@startuml
class Importer << (F,LightGreen) >> #RoyalBlue {
+ get(string $filePath, int $startRow = 1, ...) : \Generator
# FileReader $filereader
+ __construct(FileReader $filereader)
+ read(string $filePath, int $startRow = 1, ...) : \Generator
}
note right of Importer::get
note right of Importer::__construct
Constructor.
since: 3.0.8
end note
note right of Importer::read
Stream rows from a CSV or Excel file one by one using yield.
since: 3.2.0
@ -25,6 +33,7 @@ note right of Importer::get
string $filePath
int $startRow = 1
int $chunkSize = 100
RowDataProcessor $processor
end note
@enduml

View File

@ -12,10 +12,9 @@
namespace VDM\Joomla\Componentbuilder\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use VDM\Joomla\Componentbuilder\Spreadsheet\ChunkReadFilter;
use VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet\FileReaderInterface as FileReader;
use VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet\RowDataProcessorInterface as RowDataProcessor;
use VDM\Joomla\Abstraction\Console\Import;
/**
@ -25,74 +24,51 @@ use VDM\Joomla\Componentbuilder\Spreadsheet\ChunkReadFilter;
*/
final class Importer
{
/**
* To add the cli import abstract class into super powers
* Import
*/
/**
* The FileReader Class.
*
* @var FileReader
* @since 3.0.8
*/
protected FileReader $filereader;
/**
* Constructor.
*
* @param FileReader $filereader The FileReader Class.
*
* @since 3.0.8
*/
public function __construct(FileReader $filereader)
{
$this->filereader = $filereader;
}
/**
* Stream rows from a CSV or Excel file one by one using yield.
*
* @param string $filePath The path to the file.
* @param int $startRow The starting row index (default is 1).
* @param int $chunkSize The number of rows to read per chunk (default is 100).
* @param string $filePath The path to the file.
* @param int $startRow The starting row index (default is 1).
* @param int $chunkSize The number of rows to read per chunk (default is 100).
* @param RowDataProcessor $processor The processor used to transform the row data into the desired format.
*
* @return \Generator A generator that yields each row as an array.
* @throws \InvalidArgumentException If the file does not exist.
* @throws \OutOfRangeException If the start row is beyond the highest row, no rows can be processed.
* @throws ReaderException If there is an error identifying or reading the file.
* @throws SpreadsheetException If there is an error working with the spreadsheet.
* @since 3.2.0
*/
public function get(string $filePath, int $startRow = 1, int $chunkSize = 100): \Generator
public function read(string $filePath, int $startRow = 1, int $chunkSize = 100, RowDataProcessor $processor): \Generator
{
// Check if the file exists
if (!is_file($filePath))
foreach ($this->filereader->read($filePath, $startRow, $chunkSize) as $row)
{
throw new \InvalidArgumentException("File not found: $filePath");
}
try {
// Initialize variables for row processing
$totalRows = $startRow;
do {
// Set up a new chunk filter for the current chunk
$chunkFilter = new ChunkReadFilter($totalRows, $chunkSize);
$inputFileType = IOFactory::identify($filePath);
$reader = IOFactory::createReader($inputFileType);
$reader->setReadFilter($chunkFilter);
$reader->setReadDataOnly(true);
// Load the chunk into the spreadsheet
$spreadsheet = $reader->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
// Iterate through the rows in the current chunk
foreach ($worksheet->getRowIterator($totalRows) as $row)
{
$rowIndex = $row->getRowIndex();
$rowData = [];
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Include empty cells
// Collect all cell data in the row
foreach ($cellIterator as $cell)
{
$rowData[$cell->getColumn()] = $cell->getValue();
}
yield $rowData;
// Update the row index for the next chunk
$totalRows = $rowIndex + 1;
}
// Disconnect the spreadsheet to free memory
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
} while (!empty($rowData)); // Continue reading until no more rows are available
} catch (ReaderException $e) {
throw new ReaderException("Error reading the file: " . $e->getMessage(), $e->getCode(), $e);
} catch (SpreadsheetException $e) {
throw new SpreadsheetException("Error with the spreadsheet: " . $e->getMessage(), $e->getCode(), $e);
yield $processor->process($row);
}
}
}

View File

@ -1,70 +1,47 @@
/**
* To add the cli import abstract class into super powers
* Import
*/
/**
* The FileReader Class.
*
* @var FileReader
* @since 3.0.8
*/
protected FileReader $filereader;
/**
* Constructor.
*
* @param FileReader $filereader The FileReader Class.
*
* @since 3.0.8
*/
public function __construct(FileReader $filereader)
{
$this->filereader = $filereader;
}
/**
* Stream rows from a CSV or Excel file one by one using yield.
*
* @param string $filePath The path to the file.
* @param int $startRow The starting row index (default is 1).
* @param int $chunkSize The number of rows to read per chunk (default is 100).
* @param string $filePath The path to the file.
* @param int $startRow The starting row index (default is 1).
* @param int $chunkSize The number of rows to read per chunk (default is 100).
* @param RowDataProcessor $processor The processor used to transform the row data into the desired format.
*
* @return \Generator A generator that yields each row as an array.
* @throws \InvalidArgumentException If the file does not exist.
* @throws \OutOfRangeException If the start row is beyond the highest row, no rows can be processed.
* @throws ReaderException If there is an error identifying or reading the file.
* @throws SpreadsheetException If there is an error working with the spreadsheet.
* @since 3.2.0
*/
public function get(string $filePath, int $startRow = 1, int $chunkSize = 100): \Generator
public function read(string $filePath, int $startRow = 1, int $chunkSize = 100, RowDataProcessor $processor): \Generator
{
// Check if the file exists
if (!is_file($filePath))
foreach ($this->filereader->read($filePath, $startRow, $chunkSize) as $row)
{
throw new \InvalidArgumentException("File not found: $filePath");
}
try {
// Initialize variables for row processing
$totalRows = $startRow;
do {
// Set up a new chunk filter for the current chunk
$chunkFilter = new ChunkReadFilter($totalRows, $chunkSize);
$inputFileType = IOFactory::identify($filePath);
$reader = IOFactory::createReader($inputFileType);
$reader->setReadFilter($chunkFilter);
$reader->setReadDataOnly(true);
// Load the chunk into the spreadsheet
$spreadsheet = $reader->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
// Iterate through the rows in the current chunk
foreach ($worksheet->getRowIterator($totalRows) as $row)
{
$rowIndex = $row->getRowIndex();
$rowData = [];
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Include empty cells
// Collect all cell data in the row
foreach ($cellIterator as $cell)
{
$rowData[$cell->getColumn()] = $cell->getValue();
}
yield $rowData;
// Update the row index for the next chunk
$totalRows = $rowIndex + 1;
}
// Disconnect the spreadsheet to free memory
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
} while (!empty($rowData)); // Continue reading until no more rows are available
} catch (ReaderException $e) {
throw new ReaderException("Error reading the file: " . $e->getMessage(), $e->getCode(), $e);
} catch (SpreadsheetException $e) {
throw new SpreadsheetException("Error with the spreadsheet: " . $e->getMessage(), $e->getCode(), $e);
yield $processor->process($row);
}
}

View File

@ -11,8 +11,12 @@
"type": "final class",
"use_selection": {
"use_selection0": {
"use": "9ae018a5-9064-40ed-ad69-9c1ed2a459f5",
"as": "default"
"use": "61d1146f-2c2e-4e42-8492-d076f945cf35",
"as": "FileReader"
},
"use_selection1": {
"use": "9ffc54fa-a71e-412f-bc8b-064fc3b69167",
"as": "RowDataProcessor"
}
},
"extendsinterfaces": null,
@ -20,20 +24,5 @@
"description": "Spreadsheet Importer Class\r\n\r\n@since 3.2.0",
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 4th September, 2022\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": "",
"composer": {
"composer0": {
"access_point": "phpspreadsheet\/vendor\/autoload.php",
"namespace": {
"namespace0": {
"use": "PhpOffice\\PhpSpreadsheet\\IOFactory"
},
"namespace1": {
"use": "PhpOffice\\PhpSpreadsheet\\Reader\\Exception as ReaderException"
},
"namespace2": {
"use": "PhpOffice\\PhpSpreadsheet\\Exception as SpreadsheetException"
}
}
}
}
"composer": ""
}

View File

@ -16,6 +16,7 @@ class Spreadsheet #Gold {
+ getHeader(Container $container) : Header
+ getExporter(Container $container) : Exporter
+ getImporter(Container $container) : Importer
+ getFileReader(Container $container) : FileReader
}
note right of Spreadsheet::register
@ -45,6 +46,13 @@ note right of Spreadsheet::getImporter
since: 5.0.3
return: Importer
end note
note right of Spreadsheet::getFileReader
Get The FileReader Class.
since: 5.0.3
return: FileReader
end note
@enduml
```

View File

@ -17,6 +17,7 @@ use Joomla\DI\ServiceProviderInterface;
use VDM\Joomla\Componentbuilder\Spreadsheet\Header;
use VDM\Joomla\Componentbuilder\Spreadsheet\Exporter;
use VDM\Joomla\Componentbuilder\Spreadsheet\Importer;
use VDM\Joomla\Componentbuilder\Spreadsheet\FileReader;
/**
@ -44,6 +45,9 @@ class Spreadsheet implements ServiceProviderInterface
$container->alias(Importer::class, 'Spreadsheet.Importer')
->share('Spreadsheet.Importer', [$this, 'getImporter'], true);
$container->alias(FileReader::class, 'Spreadsheet.FileReader')
->share('Spreadsheet.FileReader', [$this, 'getFileReader'], true);
}
/**
@ -82,7 +86,22 @@ class Spreadsheet implements ServiceProviderInterface
*/
public function getImporter(Container $container): Importer
{
return new Importer();
return new Importer(
$container->get('Spreadsheet.FileReader')
);
}
/**
* Get The FileReader Class.
*
* @param Container $container The DI container.
*
* @return FileReader
* @since 5.0.3
*/
public function getFileReader(Container $container): FileReader
{
return new FileReader();
}
}

View File

@ -16,6 +16,9 @@
$container->alias(Importer::class, 'Spreadsheet.Importer')
->share('Spreadsheet.Importer', [$this, 'getImporter'], true);
$container->alias(FileReader::class, 'Spreadsheet.FileReader')
->share('Spreadsheet.FileReader', [$this, 'getFileReader'], true);
}
/**
@ -54,5 +57,20 @@
*/
public function getImporter(Container $container): Importer
{
return new Importer();
return new Importer(
$container->get('Spreadsheet.FileReader')
);
}
/**
* Get The FileReader Class.
*
* @param Container $container The DI container.
*
* @return FileReader
* @since 5.0.3
*/
public function getFileReader(Container $container): FileReader
{
return new FileReader();
}

View File

@ -23,6 +23,10 @@
"use_selection2": {
"use": "c4169332-3914-400e-b861-972b2d465963",
"as": "default"
},
"use_selection3": {
"use": "dcb0e061-f337-44f7-87f2-f5c5fb9ce917",
"as": "default"
}
},
"extendsinterfaces": null,

View File

@ -0,0 +1,57 @@
```
██████╗ ██████╗ ██╗ ██╗███████╗██████╗
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
```
# final class FileReader (Details)
> namespace: **VDM\Joomla\Componentbuilder\Spreadsheet**
```uml
@startuml
class FileReader << (F,LightGreen) >> #RoyalBlue {
+ read(string $filePath, int $startRow, ...) : \Generator
}
note right of FileReader::read
Stream rows from a CSV or Excel file one by one using yield.
since: 3.2.0
return: \Generator
arguments:
string $filePath
int $startRow
int $chunkSize
end note
@enduml
```
The Power feature in JCB allows you to write PHP classes and their implementations, making it easy to include them in your Joomla project. JCB handles linking, autoloading, namespacing, and folder structure creation for you.
By using the SPK (Super Power Key) in your custom code (replacing the class name in your code with the SPK), JCB will automatically pull the power from the repository into your project. This makes it available in your JCB instance, allowing you to edit it and include the class in your generated Joomla component.
JCB uses placeholders like [[[`NamespacePrefix`]]] and [[[`ComponentNamespace`]]] in namespacing to prevent collisions and improve reusability across different JCB systems. You can also set the **JCB powers path** globally or per component under the **Dynamic Integration** tab, providing flexibility and easy maintainability.
To add this specific Power to your project in JCB:
> simply use this SPK
```
Super---dcb0e061_f337_44f7_87f2_f5c5fb9ce917---Power
```
> remember to replace the `---` with `___` to activate this Power in your code
---
```
██╗ ██████╗██████╗
██║██╔════╝██╔══██╗
██║██║ ██████╔╝
██ ██║██║ ██╔══██╗
╚█████╔╝╚██████╗██████╔╝
╚════╝ ╚═════╝╚═════╝
```
> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)

View File

@ -0,0 +1,109 @@
<?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\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
use VDM\Joomla\Componentbuilder\Spreadsheet\ChunkReadFilter;
use VDM\Joomla\Componentbuilder\Interfaces\Spreadsheet\FileReaderInterface;
/**
* Spreadsheet File Reader Class
*
* @since 3.2.0
*/
final class FileReader implements FileReaderInterface
{
/**
* Stream rows from a CSV or Excel file one by one using yield.
*
* @param string $filePath The path to the file.
* @param int $startRow The starting row index.
* @param int $chunkSize The number of rows to read per chunk.
*
* @return \Generator A generator that yields each row as an array.
* @throws \InvalidArgumentException If the file does not exist.
* @throws \OutOfRangeException If the start row is beyond the highest row, no rows can be processed.
* @throws ReaderException If there is an error identifying or reading the file.
* @throws SpreadsheetException If there is an error working with the spreadsheet.
* @since 3.2.0
*/
public function read(string $filePath, int $startRow, int $chunkSize): \Generator
{
// Check if the file exists
if (!is_file($filePath))
{
throw new \InvalidArgumentException("File not found: $filePath");
}
try {
// Identify file type and create reader
$inputFileType = IOFactory::identify($filePath);
$reader = IOFactory::createReader($inputFileType);
$reader->setReadDataOnly(true);
// Load the entire spreadsheet to determine the highest row
$spreadsheet = $reader->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$highestRow = $worksheet->getHighestRow(); // Get the highest row number in the sheet
// Disconnect and free memory after fetching the highest row
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
// If the start row is beyond the highest row, no rows can be processed
if ($startRow > $highestRow)
{
throw new \OutOfRangeException("Start row ($startRow) is beyond highest row ($highestRow)");
}
// Initialize variables for row processing
$totalRows = $startRow;
do {
// Calculate the last row in the current chunk
$endRow = min($totalRows + $chunkSize - 1, $highestRow);
// Set up a new chunk filter for the current chunk
$chunkFilter = new ChunkReadFilter($totalRows, $endRow);
$reader->setReadFilter($chunkFilter);
// Reload the chunk into the spreadsheet
$spreadsheet = $reader->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
// Iterate through the rows in the current chunk
foreach ($worksheet->getRowIterator($totalRows, $endRow) as $row)
{
yield $row;
// Update the row index for the next chunk
$totalRows = $row->getRowIndex() + 1;
}
// Disconnect the spreadsheet to free memory
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
} while ($totalRows <= $highestRow); // Continue reading while within the row limit
} catch (ReaderException $e) {
throw new ReaderException("Error reading the file: " . $e->getMessage(), $e->getCode(), $e);
} catch (SpreadsheetException $e) {
throw new SpreadsheetException("Error with the spreadsheet: " . $e->getMessage(), $e->getCode(), $e);
}
}
}

View File

@ -0,0 +1,79 @@
/**
* Stream rows from a CSV or Excel file one by one using yield.
*
* @param string $filePath The path to the file.
* @param int $startRow The starting row index.
* @param int $chunkSize The number of rows to read per chunk.
*
* @return \Generator A generator that yields each row as an array.
* @throws \InvalidArgumentException If the file does not exist.
* @throws \OutOfRangeException If the start row is beyond the highest row, no rows can be processed.
* @throws ReaderException If there is an error identifying or reading the file.
* @throws SpreadsheetException If there is an error working with the spreadsheet.
* @since 3.2.0
*/
public function read(string $filePath, int $startRow, int $chunkSize): \Generator
{
// Check if the file exists
if (!is_file($filePath))
{
throw new \InvalidArgumentException("File not found: $filePath");
}
try {
// Identify file type and create reader
$inputFileType = IOFactory::identify($filePath);
$reader = IOFactory::createReader($inputFileType);
$reader->setReadDataOnly(true);
// Load the entire spreadsheet to determine the highest row
$spreadsheet = $reader->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$highestRow = $worksheet->getHighestRow(); // Get the highest row number in the sheet
// Disconnect and free memory after fetching the highest row
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
// If the start row is beyond the highest row, no rows can be processed
if ($startRow > $highestRow)
{
throw new \OutOfRangeException("Start row ($startRow) is beyond highest row ($highestRow)");
}
// Initialize variables for row processing
$totalRows = $startRow;
do {
// Calculate the last row in the current chunk
$endRow = min($totalRows + $chunkSize - 1, $highestRow);
// Set up a new chunk filter for the current chunk
$chunkFilter = new ChunkReadFilter($totalRows, $endRow);
$reader->setReadFilter($chunkFilter);
// Reload the chunk into the spreadsheet
$spreadsheet = $reader->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
// Iterate through the rows in the current chunk
foreach ($worksheet->getRowIterator($totalRows, $endRow) as $row)
{
yield $row;
// Update the row index for the next chunk
$totalRows = $row->getRowIndex() + 1;
}
// Disconnect the spreadsheet to free memory
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
} while ($totalRows <= $highestRow); // Continue reading while within the row limit
} catch (ReaderException $e) {
throw new ReaderException("Error reading the file: " . $e->getMessage(), $e->getCode(), $e);
} catch (SpreadsheetException $e) {
throw new SpreadsheetException("Error with the spreadsheet: " . $e->getMessage(), $e->getCode(), $e);
}
}

View File

@ -0,0 +1,41 @@
{
"add_head": "0",
"add_licensing_template": "2",
"extends": "",
"guid": "dcb0e061-f337-44f7-87f2-f5c5fb9ce917",
"implements": [
"61d1146f-2c2e-4e42-8492-d076f945cf35"
],
"load_selection": null,
"name": "FileReader",
"power_version": "1.0.0",
"system_name": "JCB.Spreadsheet.FileReader",
"type": "final class",
"use_selection": {
"use_selection0": {
"use": "9ae018a5-9064-40ed-ad69-9c1ed2a459f5",
"as": "default"
}
},
"extendsinterfaces": null,
"namespace": "[[[NamespacePrefix]]]\\Joomla\\[[[ComponentNamespace]]].Spreadsheet.FileReader",
"description": "Spreadsheet File Reader Class\r\n\r\n@since 3.2.0",
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 4th September, 2022\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": "",
"composer": {
"composer0": {
"access_point": "phpspreadsheet\/vendor\/autoload.php",
"namespace": {
"namespace0": {
"use": "PhpOffice\\PhpSpreadsheet\\IOFactory"
},
"namespace1": {
"use": "PhpOffice\\PhpSpreadsheet\\Reader\\Exception as ReaderException"
},
"namespace2": {
"use": "PhpOffice\\PhpSpreadsheet\\Exception as SpreadsheetException"
}
}
}
}
}

View File

@ -483,6 +483,17 @@
"spk": "Super---5f0205fa_5c43_424a_af7d_abc943c17c8c---Power",
"guid": "5f0205fa-5c43-424a-af7d-abc943c17c8c"
},
"61d1146f-2c2e-4e42-8492-d076f945cf35": {
"name": "FileReaderInterface",
"type": "interface",
"namespace": "VDM\\Joomla\\Componentbuilder\\Interfaces\\Spreadsheet",
"code": "src\/61d1146f-2c2e-4e42-8492-d076f945cf35\/code.php",
"power": "src\/61d1146f-2c2e-4e42-8492-d076f945cf35\/code.power",
"settings": "src\/61d1146f-2c2e-4e42-8492-d076f945cf35\/settings.json",
"path": "src\/61d1146f-2c2e-4e42-8492-d076f945cf35",
"spk": "Super---61d1146f_2c2e_4e42_8492_d076f945cf35---Power",
"guid": "61d1146f-2c2e-4e42-8492-d076f945cf35"
},
"640b5352-fb09-425f-a26e-cd44eda03f15": {
"name": "Helper",
"type": "abstract class",
@ -813,6 +824,17 @@
"spk": "Super---9ef0eb24_aae4_4f5a_99af_d724db44808f---Power",
"guid": "9ef0eb24-aae4-4f5a-99af-d724db44808f"
},
"9ffc54fa-a71e-412f-bc8b-064fc3b69167": {
"name": "RowDataProcessorInterface",
"type": "interface",
"namespace": "VDM\\Joomla\\Componentbuilder\\Interfaces\\Spreadsheet",
"code": "src\/9ffc54fa-a71e-412f-bc8b-064fc3b69167\/code.php",
"power": "src\/9ffc54fa-a71e-412f-bc8b-064fc3b69167\/code.power",
"settings": "src\/9ffc54fa-a71e-412f-bc8b-064fc3b69167\/settings.json",
"path": "src\/9ffc54fa-a71e-412f-bc8b-064fc3b69167",
"spk": "Super---9ffc54fa_a71e_412f_bc8b_064fc3b69167---Power",
"guid": "9ffc54fa-a71e-412f-bc8b-064fc3b69167"
},
"a223b31e-ea1d-4cdf-92ae-5f9becffaff0": {
"name": "FileHelper",
"type": "abstract class",
@ -1099,6 +1121,17 @@
"spk": "Super---db87c339_5bb6_4291_a7ef_2c48ea1b06bc---Power",
"guid": "db87c339-5bb6-4291-a7ef-2c48ea1b06bc"
},
"dcb0e061-f337-44f7-87f2-f5c5fb9ce917": {
"name": "FileReader",
"type": "final class",
"namespace": "VDM\\Joomla\\Componentbuilder\\Spreadsheet",
"code": "src\/dcb0e061-f337-44f7-87f2-f5c5fb9ce917\/code.php",
"power": "src\/dcb0e061-f337-44f7-87f2-f5c5fb9ce917\/code.power",
"settings": "src\/dcb0e061-f337-44f7-87f2-f5c5fb9ce917\/settings.json",
"path": "src\/dcb0e061-f337-44f7-87f2-f5c5fb9ce917",
"spk": "Super---dcb0e061_f337_44f7_87f2_f5c5fb9ce917---Power",
"guid": "dcb0e061-f337-44f7-87f2-f5c5fb9ce917"
},
"e0198c3f-777a-4a0b-87b7-e6a198afc8f9": {
"name": "MultiSubform",
"type": "final class",