Comparer les révisions

...

12 Révisions

20 fichiers modifiés avec 230 ajouts et 115 suppressions

Voir le fichier

@ -61,24 +61,34 @@ class d3ActionWizard extends AdminDetailsController
public function runTask() public function runTask()
{ {
try { try {
$id = Registry::getRequest()->getRequestEscapedParameter('taskid'); $this->execute();
$action = $this->configuration->getActionById($id);
[ $queryString, $parameters ] = $action->getQuery();
if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew(
DebugException::class,
d3database::getInstance()->getPreparedStatementQuery($queryString, $parameters)
);
}
$action->run();
} catch (DataWizardException|DBALException|DatabaseErrorException $e) { } catch (DataWizardException|DBALException|DatabaseErrorException $e) {
Registry::getLogger()->error($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e); Registry::getUtilsView()->addErrorToDisplay($e);
} }
} }
/**
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
protected function execute()
{
$id = Registry::getRequest()->getRequestEscapedParameter('taskid');
$action = $this->configuration->getActionById($id);
[ $queryString, $parameters ] = $action->getQuery();
if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew(
DebugException::class,
d3database::getInstance()->getPreparedStatementQuery($queryString, $parameters)
);
}
$action->run();
}
public function getUserMessages() public function getUserMessages()
{ {
return null; return null;

Voir le fichier

@ -18,6 +18,8 @@ namespace D3\DataWizard\Application\Controller\Admin;
use D3\DataWizard\Application\Model\Configuration; use D3\DataWizard\Application\Model\Configuration;
use D3\DataWizard\Application\Model\Exceptions\DataWizardException; use D3\DataWizard\Application\Model\Exceptions\DataWizardException;
use D3\DataWizard\Application\Model\Exceptions\DebugException; use D3\DataWizard\Application\Model\Exceptions\DebugException;
use D3\DataWizard\Application\Model\Exceptions\NoSuitableRendererException;
use D3\DataWizard\Application\Model\Exceptions\TaskException;
use D3\ModCfg\Application\Model\d3database; use D3\ModCfg\Application\Model\d3database;
use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception; use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException; use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
@ -61,24 +63,40 @@ class d3ExportWizard extends AdminDetailsController
public function runTask() public function runTask()
{ {
try { try {
$id = Registry::getRequest()->getRequestEscapedParameter('taskid'); $this->execute();
$export = $this->configuration->getExportById($id);
[ $queryString, $parameters ] = $export->getQuery();
if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew(
DebugException::class,
d3database::getInstance()->getPreparedStatementQuery($queryString, $parameters)
);
}
$export->run(Registry::getRequest()->getRequestEscapedParameter('format'));
} catch (DataWizardException|DBALException|DatabaseErrorException $e) { } catch (DataWizardException|DBALException|DatabaseErrorException $e) {
Registry::getLogger()->error($e->getMessage());
Registry::getUtilsView()->addErrorToDisplay($e); Registry::getUtilsView()->addErrorToDisplay($e);
} }
} }
/**
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws StandardException
* @throws NoSuitableRendererException
* @throws TaskException
* @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/
protected function execute()
{
$id = Registry::getRequest()->getRequestEscapedParameter('taskid');
$export = $this->configuration->getExportById($id);
[ $queryString, $parameters ] = $export->getQuery();
if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew(
DebugException::class,
d3database::getInstance()->getPreparedStatementQuery($queryString, $parameters)
);
}
$export->run(Registry::getRequest()->getRequestEscapedParameter('format'));
}
public function getUserMessages() public function getUserMessages()
{ {
return null; return null;

Voir le fichier

@ -29,6 +29,7 @@ abstract class ActionBase implements QueryBase
protected $formElements = []; protected $formElements = [];
/** /**
* Ensure that the translations are equally available in the frontend and the backend
* @return string * @return string
*/ */
public function getDescription() : string public function getDescription() : string

Voir le fichier

@ -36,6 +36,7 @@ abstract class ExportBase implements QueryBase
protected $formElements = []; protected $formElements = [];
/** /**
* Ensure that the translations are equally available in the frontend and the backend
* @return string * @return string
*/ */
public function getDescription() : string public function getDescription() : string
@ -103,7 +104,15 @@ abstract class ExportBase implements QueryBase
*/ */
public function getRenderer($format): ExportRenderer\RendererInterface public function getRenderer($format): ExportRenderer\RendererInterface
{ {
return oxNew(RendererBridge::class)->getRenderer($format); return $this->getRendererBridge()->getRenderer($format);
}
/**
* @return RendererBridge
*/
public function getRendererBridge()
{
return oxNew(RendererBridge::class);
} }
/** /**
@ -177,7 +186,7 @@ abstract class ExportBase implements QueryBase
throw oxNew( throw oxNew(
Exceptions\TaskException::class, Exceptions\TaskException::class,
$this, $this,
Registry::getLang()->translateString( 'D3_DATAWIZARD_ERR_NOEXPORTCONTENT' ) Registry::getLang()->translateString( 'D3_DATAWIZARD_ERR_NOEXPORTCONTENT', null, true )
); );
} }

Voir le fichier

@ -36,13 +36,12 @@ class Csv implements RendererInterface
$csv = $this->getCsv(); $csv = $this->getCsv();
$csv->insertOne( $fieldNames ); $csv->insertOne( $fieldNames );
$csv->insertAll( $rows ); $csv->insertAll( $rows );
return method_exists($csv, 'getContent') ? $csv->getContent() : (string) $csv;
} catch (Exception $e) { } catch (Exception $e) {
/** @var RenderException $newException */ /** @var RenderException $newException */
$newException = oxNew(RenderException::class, $e->getMessage(), $e->getCode(), $e ); $newException = oxNew(RenderException::class, $e->getMessage(), $e->getCode(), $e );
throw $newException; throw $newException;
} }
return $csv->getContent();
} }
public function getFileExtension(): string public function getFileExtension(): string
@ -74,4 +73,12 @@ class Csv implements RendererInterface
return $csv; return $csv;
} }
/**
* @return string
*/
public function getTitleTranslationId(): string
{
return 'D3_DATAWIZARD_EXPORT_FORMAT_CSV';
}
} }

Voir le fichier

@ -0,0 +1,51 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\DataWizard\Application\Model\ExportRenderer;
use D3\DataWizard\Application\Model\Exceptions\RenderException;
class Json implements RendererInterface
{
/**
* @param $rows
* @param $fieldNames
*
* @return string
* @throws RenderException
*/
public function getContent($rows, $fieldNames): string
{
$flags = JSON_PRETTY_PRINT;
$json = json_encode( $rows, $flags );
if ( $json === false ) {
throw oxNew( RenderException::class, json_last_error_msg(), json_last_error());
}
return $json;
}
public function getFileExtension(): string
{
return 'json';
}
/**
* @return string
*/
public function getTitleTranslationId(): string
{
return "D3_DATAWIZARD_EXPORT_FORMAT_JSON";
}
}

Voir le fichier

@ -38,4 +38,12 @@ class Pretty implements RendererInterface
{ {
return 'txt'; return 'txt';
} }
/**
* @return string
*/
public function getTitleTranslationId(): string
{
return "D3_DATAWIZARD_EXPORT_FORMAT_PRETTY";
}
} }

Voir le fichier

@ -21,6 +21,7 @@ class RendererBridge
{ {
const FORMAT_CSV = 'CSV'; const FORMAT_CSV = 'CSV';
const FORMAT_PRETTY = 'Pretty'; const FORMAT_PRETTY = 'Pretty';
const FORMAT_JSON = 'JSON';
/** /**
* @return array * @return array
@ -29,10 +30,26 @@ class RendererBridge
{ {
return [ return [
self::FORMAT_CSV => oxNew(Csv::class), self::FORMAT_CSV => oxNew(Csv::class),
self::FORMAT_PRETTY => oxNew(Pretty::class) self::FORMAT_PRETTY => oxNew(Pretty::class),
self::FORMAT_JSON => oxNew(Json::class)
]; ];
} }
public function getTranslatedRendererIdList()
{
$rendererList = $this->getRendererList();
array_walk($rendererList, [$this, 'translateRendererId']);
return $rendererList;
}
/**
* @param RendererInterface $instance
*/
protected function translateRendererId(RendererInterface &$instance)
{
$instance = $instance->getTitleTranslationId();
}
/** /**
* @param string $format * @param string $format
* *

Voir le fichier

@ -29,4 +29,9 @@ interface RendererInterface
* @return string * @return string
*/ */
public function getFileExtension() : string; public function getFileExtension() : string;
/**
* @return string
*/
public function getTitleTranslationId() : string;
} }

Voir le fichier

@ -22,11 +22,13 @@ interface QueryBase
public function run(); public function run();
/** /**
* Ensure that the translations are equally available in the frontend and the backend
* @return string * @return string
*/ */
public function getTitle() : string; public function getTitle() : string;
/** /**
* Ensure that the translations are equally available in the frontend and the backend
* @return string * @return string
*/ */
public function getDescription() : string; public function getDescription() : string;

Voir le fichier

@ -39,6 +39,7 @@ $aLang = array(
'D3_DATAWIZARD_EXPORT_SUBMIT' => 'Export starten', 'D3_DATAWIZARD_EXPORT_SUBMIT' => 'Export starten',
'D3_DATAWIZARD_EXPORT_FORMAT_CSV' => 'CSV-Format', 'D3_DATAWIZARD_EXPORT_FORMAT_CSV' => 'CSV-Format',
'D3_DATAWIZARD_EXPORT_FORMAT_PRETTY' => 'Pretty-Format', 'D3_DATAWIZARD_EXPORT_FORMAT_PRETTY' => 'Pretty-Format',
'D3_DATAWIZARD_EXPORT_FORMAT_JSON' => 'JSON-Format',
'D3_DATAWIZARD_ACTION_SUBMIT' => 'Aktion starten', 'D3_DATAWIZARD_ACTION_SUBMIT' => 'Aktion starten',

Voir le fichier

@ -39,6 +39,7 @@ $aLang = array(
'D3_DATAWIZARD_EXPORT_SUBMIT' => 'generate export', 'D3_DATAWIZARD_EXPORT_SUBMIT' => 'generate export',
'D3_DATAWIZARD_EXPORT_FORMAT_CSV' => 'CSV format', 'D3_DATAWIZARD_EXPORT_FORMAT_CSV' => 'CSV format',
'D3_DATAWIZARD_EXPORT_FORMAT_PRETTY' => 'Pretty format', 'D3_DATAWIZARD_EXPORT_FORMAT_PRETTY' => 'Pretty format',
'D3_DATAWIZARD_EXPORT_FORMAT_JSON' => 'JSON format',
'D3_DATAWIZARD_ACTION_SUBMIT' => 'run action', 'D3_DATAWIZARD_ACTION_SUBMIT' => 'run action',

Voir le fichier

@ -101,7 +101,9 @@
[{/foreach}] [{/foreach}]
[{/if}] [{/if}]
[{include file=$submit}] [{block name="exportSubmit"}]
[{include file=$submit}]
[{/block}]
</div> </div>
</div> </div>
</div> </div>

Voir le fichier

@ -1,6 +1,8 @@
<div class="btn-group"> [{block name="submitElements"}]
<button type="button" class="btn btn-primary" onclick="startTask('[{$id}]')"> <div class="btn-group">
<i class="fas fa-magic"></i> <button type="button" class="btn btn-primary" onclick="startTask('[{$id}]')">
[{oxmultilang ident=$item->getButtonText()}] <i class="fas fa-fw fa-magic"></i>
</button> [{oxmultilang ident=$item->getButtonText()}]
</div> </button>
</div>
[{/block}]

Voir le fichier

@ -1,22 +1,24 @@
<div class="btn-group"> [{block name="submitElements"}]
<button type="button" class="btn btn-primary" onclick="startTask('[{$id}]', 'CSV')"> <div class="btn-group">
<i class="fas fa-magic"></i> <button type="button" class="btn btn-primary" onclick="startTask('[{$id}]', 'CSV')">
[{oxmultilang ident=$item->getButtonText()}] <i class="fas fa-fw fa-magic"></i>
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="sr-only">
<i class="fas fa-magic"></i>
[{oxmultilang ident=$item->getButtonText()}] [{oxmultilang ident=$item->getButtonText()}]
</span> </button>
</button> <button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<div class="dropdown-menu"> <span class="sr-only">
[{block name="dataWizardFormat"}] <i class="fas fa-fw fa-magic"></i>
<button class="dropdown-item" onclick="startTask('[{$id}]', 'CSV')"> [{oxmultilang ident=$item->getButtonText()}]
[{oxmultilang ident="D3_DATAWIZARD_EXPORT_FORMAT_CSV"}] </span>
</button> </button>
<button class="dropdown-item" onclick="startTask('[{$id}]', 'Pretty')"> <div class="dropdown-menu">
[{oxmultilang ident="D3_DATAWIZARD_EXPORT_FORMAT_PRETTY"}] [{block name="dataWizardFormat"}]
</button> [{assign var="rendererBridge" value=$item->getRendererBridge()}]
[{/block}] [{foreach from=$rendererBridge->getTranslatedRendererIdList() key="key" item="translationId"}]
<button class="dropdown-item" onclick="startTask('[{$id}]', '[{$key}]')">
[{oxmultilang ident=$translationId}]
</button>
[{/foreach}]
[{/block}]
</div>
</div> </div>
</div> [{/block}]

Voir le fichier

@ -1,5 +1,25 @@
# Changelog # Changelog
## 1.4.0.0 (2021-11-11)
#### Added
- add JSON export renderer
- add tpl block for easier extension
- enable controller based exception handling
#### Changed
- change deprecated CSV export code
- show registered export renderers in admin submit without required tpl block extension
- force get translations from admin
---
## 1.3.1.0 (2021-09-10)
- installable in OXID 6.3.1
---
## 1.3.0.0 (2021-07-29) ## 1.3.0.0 (2021-07-29)
- can handle long task description text - can handle long task description text

Voir le fichier

@ -7,7 +7,7 @@ The module `DataWizard` offers a framework for the simple integration of exports
The exports are defined via database queries or ready-made data lists. Various export formats are available. The generation is possible at any time and always recurring (within the system limits). These are offered as downloads in the browser. The exports are defined via database queries or ready-made data lists. Various export formats are available. The generation is possible at any time and always recurring (within the system limits). These are offered as downloads in the browser.
All exports are grouped together for better clarity. All exports and tasks are grouped together for better clarity.
Sample exports are included in the package d3/datawizardtasks. These are intended to serve as an implementation reference for individual exports. Sample exports are included in the package d3/datawizardtasks. These are intended to serve as an implementation reference for individual exports.
@ -27,38 +27,17 @@ Activate the module in the admin area of the shop in "Extensions -> Modules".
The module represents the technical basic framework of the exports and does not claim to be complete. In order to adapt the scope to individual requirements, the following extensions are prepared: The module represents the technical basic framework of the exports and does not claim to be complete. In order to adapt the scope to individual requirements, the following extensions are prepared:
- Add exports - Add exports or tasks
- Use existing and new groups - Use existing and new groups
- Add export formats - Add export formats
Independently of this, all extension options are available that the OXID Shop provides for modules. Independently of this, all extension options are available that the OXID Shop provides for modules.
### Add exports ## Extension packages
#### Define export - `d3/datawizardtasks` - provides sample exports and their implementation reference
- `d3/datawizardcli` - provides the execution of exports or tasks via the command prompt (e.g. as cronjobs)
Each export is defined in a separate class. This export class must extend the class `D3\DataWizard\Application\Model\ExportBase`. All necessary functions are predefined in it. The following methods are available: - `d3/datawizardlink` - provides URLs to generate exports from third party systems
##### mandatory method calls:
- getTitle() - defines the title in the admin area and the base of the later export file name.
- getQuery() - contains the query as a prepared statement that defines the data to be exported
##### optional method calls:
- getDescription() - contains a short additional description of the export, this will be shown in the admin area
- getButtonText() - defines the text of the submit button in the admin area
- getExportFilenameBase() - defines the base of the later export filename
- executeQuery() - returns the compiled export data
- further methods, the adaptation of which, however, can lead to changed module behaviour and should therefore only be changed with caution
#### Register exports
In order to be able to use the created export in the module, it must be registered. For this purpose there is the class `D3\DataWizard\Application\Model\Configuration`. This is to be overloaded with the possibilities of the OXID shop and the method `configure()` contained therein is to be supplemented. The following call is available for registering an export:
```
$this->registerExport(self::GROUP_CATEGORY, oxNew(myCustomExport::class));
```
The first parameter contains the language identifier for the export group. Typical identifiers are already prepared in constants of the configuration class. The instance of the export class is expected as the 2nd parameter.
## Changelog ## Changelog

Voir le fichier

@ -3,11 +3,11 @@
# D³ Data Wizard für OXID eShop # D³ Data Wizard für OXID eShop
Das Modul `DataWizard` bietet ein Framework zur einfachen Integration von Exporten über den Adminbereich des OXID Shops. Das Modul `DataWizard` bietet ein Framework zur einfachen Integration von Exporten und ausführbaren Tasks über den Adminbereich des OXID Shops.
Die Exporte werden über Datenbankabfragen oder fertige Datenlisten definiert. Es stehen verschiedene Exportformate zur Verfügung. Die Generierung ist jederzeit und immer wiederkehrend möglich (im Rahmen der Systemgrenzen). Diese werden im Browser als Download angeboten. Die Exporte werden über Datenbankabfragen oder fertige Datenlisten definiert. Es stehen verschiedene Exportformate zur Verfügung. Die Generierung ist jederzeit und immer wiederkehrend möglich (im Rahmen der Systemgrenzen). Diese werden im Browser als Download angeboten.
Alle Exporte sind für eine bessere Übersichtlichkeit in Gruppen zusammengefasst. Alle Exporte bzw. Tasks sind für eine bessere Übersichtlichkeit in Gruppen zusammengefasst.
Im Paket d3/datawizardtasks sind Beispielexporte enthalten. Diese sollen als Implementierungsreferenz für individuelle Exporte dienen. Im Paket d3/datawizardtasks sind Beispielexporte enthalten. Diese sollen als Implementierungsreferenz für individuelle Exporte dienen.
@ -27,38 +27,17 @@ Aktivieren Sie das Modul im Shopadmin unter "Erweiterungen -> Module".
Das Modul stellt das technische Grundgerüst der Exporte dar und erhebt keinen Anspruch auf Vollständigkeit. Um den Umfang an die individuellen Anforderungen anzupassen, sind folgende Erweiterungen vorbereitet: Das Modul stellt das technische Grundgerüst der Exporte dar und erhebt keinen Anspruch auf Vollständigkeit. Um den Umfang an die individuellen Anforderungen anzupassen, sind folgende Erweiterungen vorbereitet:
- Exporte hinzufügen - Exporte oder Tasks hinzufügen
- Verwendung bestehender und neuer Gruppen - Verwendung bestehender und neuer Gruppen
- Exportformate ergänzen - Exportformate ergänzen
Unabhängig dessen stehen alle Erweiterungsmöglichkeiten zur Verfügung, die der OXID Shop für Module bereitstellt. Unabhängig dessen stehen alle Erweiterungsmöglichkeiten zur Verfügung, die der OXID Shop für Module bereitstellt.
### Exporte hinzufügen ## Erweiterungspakete
#### Export definieren - `d3/datawizardtasks` - liefert Beispielexporte und deren Implementierungsreferenz
- `d3/datawizardcli` - ermöglicht die Ausführung der Exporte oder Tasks über die Eingabeaufforderung (z.B. als Cronjobs)
Jeder Export wird in einer separaten Klasse definiert. Diese Exportklasse muss die Klasse `D3\DataWizard\Application\Model\ExportBase` erweitern. Darin sind alle nötigen Funktionen vordefiniert. Folgende Methoden stehen hierbei zur Verfügung: - `d3/datawizardlink` - stellt URLs zur Verfügung, um Exporte von Drittsystemen generieren zu lassen
##### verpflichtende Methodenaufrufe:
- getTitle() - definiert den Titel im Adminbereich und die Basis des späteren Exportdateinamens
- getQuery() - enthält den Abfragequery als prepared statement, der die zu exportierenden Daten definiert
##### optionale Methodenaufrufe:
- getDescription() - enthält eine kurze zusätzliche Beschreibung des Exports, dieser wird im Adminbereich gezeigt
- getButtonText() - definiert den Text des Absenden-Buttons im Adminbereich
- getExportFilenameBase() - definiert die Basis des späteren Exportdateinamens
- executeQuery() - liefert die zusammengestellten Exportdaten
- weitere Methoden, deren Anpassung jedoch zum geänderten Modulverhalten führen können und daher nur mit Vorsicht zu verändern sind
#### Exporte registrieren
Um den erstellten Export auch im Modul verwenden zu können, muss dieser noch registriert werden. Hierzu gibt des die Klasse `D3\DataWizard\Application\Model\Configuration`. Diese ist mit den Möglichkeiten des OXID Shops zu überladen und die darin enthaltene Methode `configure()` zu ergänzen. Für die Registrierung eines Exportes steht Ihnen dazu folgender Aufruf zur Verfügung:
```
$this->registerExport(self::GROUP_CATEGORY, oxNew(myCustomExport::class));
```
Der erste Parameter enthält den Sprachident für die Exportgruppe. In Konstanten der configuration-Klasse sind schon typische Idents vorbereitet. Als 2. Parameter wird die Instanz der Exportklasse erwartet.
## Changelog ## Changelog

Voir le fichier

@ -42,7 +42,8 @@
}, },
"suggest": { "suggest": {
"d3/datawizardtasks": "useful example tasks for Data Wizard", "d3/datawizardtasks": "useful example tasks for Data Wizard",
"d3/datawizardcli": "command line implementation for fully automated Data Wizard tasks" "d3/datawizardcli": "command line implementation for fully automated Data Wizard tasks",
"d3/datawizardlink": "remote http link for Data Wizard module exports"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

Voir le fichier

@ -32,7 +32,7 @@ $aModule = [
'en' => '', 'en' => '',
], ],
'thumbnail' => '', 'thumbnail' => '',
'version' => '1.3.0.0', 'version' => '1.4.0.0',
'author' => 'D&sup3; Data Development (Inh.: Thomas Dartsch)', 'author' => 'D&sup3; Data Development (Inh.: Thomas Dartsch)',
'email' => 'support@shopmodule.com', 'email' => 'support@shopmodule.com',
'url' => 'https://www.oxidmodule.com/', 'url' => 'https://www.oxidmodule.com/',