Compare commits

...

2 Commits

17 changed files with 259 additions and 24 deletions

View File

@ -1,5 +1,10 @@
# Changelog
## 1.1.0.0 (2021-06-25)
- implement form builder
- fix key figures export
## 1.0.0.0 (2021-06-22)
- initial implementation

View File

@ -28,7 +28,8 @@
"php": ">=7.1",
"oxid-esales/oxideshop-ce": "6.3 - 6.8",
"league/csv": "^9.0",
"mathieuviossat/arraytotexttable": "^1.0"
"mathieuviossat/arraytotexttable": "^1.0",
"form-manager/form-manager": "^6.1"
},
"extra": {
"oxideshop": {

View File

@ -15,6 +15,10 @@ declare(strict_types=1);
namespace D3\DataWizard\Application\Model;
use D3\DataWizard\Application\Model\Exceptions\InputUnvalidException;
use FormManager\Inputs\Checkbox;
use FormManager\Inputs\Input;
use FormManager\Inputs\Radio;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
@ -22,6 +26,8 @@ use OxidEsales\Eshop\Core\Registry;
abstract class ActionBase implements QueryBase
{
protected $formElements = [];
/**
* @return string
*/
@ -36,6 +42,15 @@ abstract class ActionBase implements QueryBase
*/
public function run()
{
if ($this->hasFormElements()) {
/** @var Input $element */
foreach ($this->getFormElements() as $element) {
if (false === $element->isValid()) {
throw oxNew(InputUnvalidException::class, $this, $element);
}
}
}
$this->executeAction( $this->getQuery() );
}
@ -81,4 +96,38 @@ abstract class ActionBase implements QueryBase
{
return "D3_DATAWIZARD_ACTION_SUBMIT";
}
/**
* @param Input $input
*/
public function registerFormElement(Input $input)
{
switch (get_class($input)) {
case Radio::class:
case Checkbox::class:
$input->setTemplate('<p class="form-check">{{ input }} {{ label }}</p>');
$input->setAttribute('class', 'form-check-input');
break;
default:
$input->setTemplate('<p class="formElements">{{ label }} {{ input }}</p>');
$input->setAttribute('class', 'form-control');
}
$this->formElements[] = $input;
}
/**
* @return bool
*/
public function hasFormElements(): bool
{
return (bool) count($this->formElements);
}
/**
* @return array
*/
public function getFormElements(): array
{
return $this->formElements;
}
}

View File

@ -16,6 +16,7 @@ declare(strict_types=1);
namespace D3\DataWizard\Application\Model;
use D3\DataWizard\Application\Model\Actions\FixArtextendsItems;
use D3\DataWizard\Application\Model\Exceptions\DataWizardException;
use D3\DataWizard\Application\Model\Exports\InactiveCategories;
use D3\DataWizard\Application\Model\Exports\KeyFigures;
use OxidEsales\Eshop\Core\Registry;
@ -53,7 +54,7 @@ class Configuration
*/
public function registerAction($group, ActionBase $action)
{
$this->actions[$group][md5(serialize($action))] = $action;
$this->actions[$group][md5(get_class($action))] = $action;
}
/**
@ -62,7 +63,7 @@ class Configuration
*/
public function registerExport($group, ExportBase $export)
{
$this->exports[$group][md5(serialize($export))] = $export;
$this->exports[$group][md5(get_class($export))] = $export;
}
/**
@ -162,6 +163,12 @@ class Configuration
*/
public function getExportById($id) : ExportBase
{
return $this->getAllExports()[$id];
$allExports = $this->getAllExports();
if (false == $allExports[$id]) {
throw oxNew(DataWizardException::class, 'no export with id '.$id);
}
return $allExports[$id];
}
}

View File

@ -15,6 +15,8 @@ declare(strict_types=1);
namespace D3\DataWizard\Application\Model\Exceptions;
interface DataWizardException
use OxidEsales\Eshop\Core\Exception\StandardException;
class DataWizardException extends StandardException
{
}

View File

@ -19,7 +19,7 @@ use Exception;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
class DebugException extends StandardException implements DataWizardException
class DebugException extends DataWizardException
{
public function __construct($sMessage = "not set", $iCode = 0, Exception $previous = null )
{

View File

@ -0,0 +1,46 @@
<?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\Exceptions;
use D3\DataWizard\Application\Model\QueryBase;
use Exception;
use FormManager\Inputs\Input;
use OxidEsales\Eshop\Core\Exception\StandardException;
class InputUnvalidException extends DataWizardException
{
/** @var QueryBase */
public $task;
public function __construct( QueryBase $task, Input $inputElement, $iCode = 0, Exception $previous = null )
{
$messages = [];
foreach ($inputElement->getError()->getIterator() as $item) {
$messages[] = $inputElement->label->innerHTML.' -> '.$item->getMessage();
}
$sMessage = implode(
' - ',
[
$task->getTitle(),
implode(', ', $messages)
]
);
parent::__construct( $sMessage, $iCode, $previous );
$this->task = $task;
}
}

View File

@ -19,7 +19,7 @@ use Exception;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
class NoSuitableRendererException extends StandardException implements DataWizardException
class NoSuitableRendererException extends DataWizardException
{
public function __construct($sMessage = "not set", $iCode = 0, Exception $previous = null )
{

View File

@ -15,8 +15,6 @@ declare(strict_types=1);
namespace D3\DataWizard\Application\Model\Exceptions;
use OxidEsales\Eshop\Core\Exception\StandardException;
class RenderException extends StandardException implements DataWizardException
class RenderException extends DataWizardException
{
}

View File

@ -17,9 +17,8 @@ namespace D3\DataWizard\Application\Model\Exceptions;
use D3\DataWizard\Application\Model\QueryBase;
use Exception;
use OxidEsales\Eshop\Core\Exception\StandardException;
class TaskException extends StandardException implements DataWizardException
class TaskException extends DataWizardException
{
/** @var QueryBase */
public $task;

View File

@ -15,11 +15,15 @@ declare(strict_types=1);
namespace D3\DataWizard\Application\Model;
use D3\DataWizard\Application\Model\Exceptions\InputUnvalidException;
use D3\DataWizard\Application\Model\ExportRenderer\RendererBridge;
use D3\ModCfg\Application\Model\d3filesystem;
use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use Doctrine\DBAL\DBALException;
use FormManager\Inputs\Checkbox;
use FormManager\Inputs\Input;
use FormManager\Inputs\Radio;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
@ -28,6 +32,8 @@ use OxidEsales\Eshop\Core\Registry;
abstract class ExportBase implements QueryBase
{
protected $formElements = [];
/**
* @return string
*/
@ -50,6 +56,15 @@ abstract class ExportBase implements QueryBase
*/
public function run($format = RendererBridge::FORMAT_CSV)
{
if ($this->hasFormElements()) {
/** @var Input $element */
foreach ($this->getFormElements() as $element) {
if (false === $element->isValid()) {
throw oxNew(InputUnvalidException::class, $this, $element);
}
}
}
[ $rows, $fieldNames ] = $this->getExportData( $this->getQuery() );
$content = $this->renderContent($rows, $fieldNames, $format);
@ -160,4 +175,38 @@ abstract class ExportBase implements QueryBase
return [ $rows, $fieldNames ];
}
/**
* @param Input $input
*/
public function registerFormElement(Input $input)
{
switch (get_class($input)) {
case Radio::class:
case Checkbox::class:
$input->setTemplate('<p class="form-check">{{ input }} {{ label }}</p>');
$input->setAttribute('class', 'form-check-input');
break;
default:
$input->setTemplate('<p class="formElements">{{ label }} {{ input }}</p>');
$input->setAttribute('class', 'form-control');
}
$this->formElements[] = $input;
}
/**
* @return bool
*/
public function hasFormElements(): bool
{
return (bool) count($this->formElements);
}
/**
* @return array
*/
public function getFormElements(): array
{
return $this->formElements;
}
}

View File

@ -16,15 +16,45 @@
namespace D3\DataWizard\Application\Model\Exports;
use D3\DataWizard\Application\Model\ExportBase;
use FormManager\Inputs\Date;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Core\Registry;
use FormManager\Factory as FormFactory;
class KeyFigures extends ExportBase
{
const STARTDATE_NAME = 'startdate';
const ENDDATE_NAME = 'enddate';
/**
* Shopkennzahlen
*/
public function __construct()
{
/** @var Date $startDate */
$startDateValue = Registry::getRequest()->getRequestEscapedParameter(self::STARTDATE_NAME);
$startDate = FormFactory::date(
Registry::getLang()->translateString('D3_DATAWIZARD_EXPORTS_KEYFIGURES_FIELD_STARTDATE'),
[
'name' => self::STARTDATE_NAME,
'value' => $startDateValue
]
);
$this->registerFormElement($startDate);
/** @var Date $endDate */
$endDateValue = Registry::getRequest()->getRequestEscapedParameter(self::ENDDATE_NAME);
$endDate = FormFactory::date(
Registry::getLang()->translateString('D3_DATAWIZARD_EXPORTS_KEYFIGURES_FIELD_ENDDATE'),
[
'name' => self::ENDDATE_NAME,
'value' => $endDateValue
]
);
$this->registerFormElement($endDate);
}
/**
* @return string
*/
@ -43,19 +73,25 @@ class KeyFigures extends ExportBase
$basketsTitle = Registry::getLang()->translateString('D3_DATAWIZARD_EXPORTS_KEYFIGURES_BASKETSIZE');
$monthTitle = Registry::getLang()->translateString('D3_DATAWIZARD_EXPORTS_KEYFIGURES_MONTH');
$startDateValue = Registry::getRequest()->getRequestEscapedParameter(self::STARTDATE_NAME) ?: '1970-01-01';
$endDateValue = Registry::getRequest()->getRequestEscapedParameter(self::ENDDATE_NAME) ?: date('Y-m-d');
return [
'SELECT
DATE_FORMAT(oo.oxorderdate, "%Y-%m") as :monthTitle,
FORMAT(COUNT(oo.oxid), 0) AS :ordersTitle,
FORMAT(SUM(oo.OXTOTALBRUTSUM / oo.oxcurrate) / COUNT(oo.oxid), 2) as :basketsTitle
FROM '.$orderTable.' AS oo
GROUP BY :monthTitle
ORDER BY :monthTitle DESC
WHERE oo.oxorderdate >= :startDate AND oo.oxorderdate <= :endDate
GROUP BY DATE_FORMAT(oo.oxorderdate, "%Y-%m")
ORDER BY DATE_FORMAT(oo.oxorderdate, "%Y-%m") DESC
LIMIT 30',
[
'monthTitle' => $monthTitle,
'ordersTitle' => $ordersTitle,
'basketsTitle' => $basketsTitle
'startDate' => $startDateValue,
'endDate' => $endDateValue,
'monthTitle' => $monthTitle,
'ordersTitle' => $ordersTitle,
'basketsTitle' => $basketsTitle
]
];
}

View File

@ -15,6 +15,8 @@ declare(strict_types=1);
namespace D3\DataWizard\Application\Model;
use FormManager\Inputs\Input;
interface QueryBase
{
public function run();
@ -38,4 +40,19 @@ interface QueryBase
* @return array [string $query, array $parameters]
*/
public function getQuery() : array;
/**
* @param Input $input
*/
public function registerFormElement(Input $input);
/**
* @return bool
*/
public function hasFormElements(): bool;
/**
* @return array
*/
public function getFormElements(): array;
}

View File

@ -55,6 +55,8 @@ $aLang = array(
'D3_DATAWIZARD_EXPORTS_INACTIVECATEGORIES_COUNT' => 'Anzahl',
'D3_DATAWIZARD_EXPORTS_KEYFIGURES' => 'Bestellungskennzahlen nach Monat',
'D3_DATAWIZARD_EXPORTS_KEYFIGURES_FIELD_STARTDATE'=> 'Startdatum (optional)',
'D3_DATAWIZARD_EXPORTS_KEYFIGURES_FIELD_ENDDATE' => 'Enddatum (optional)',
'D3_DATAWIZARD_EXPORTS_KEYFIGURES_ORDERSPERMONTH' => 'Bestellungen pro Monat',
'D3_DATAWIZARD_EXPORTS_KEYFIGURES_BASKETSIZE' => 'Warenkorbhöhe',
'D3_DATAWIZARD_EXPORTS_KEYFIGURES_MONTH' => 'Monat',

View File

@ -23,6 +23,10 @@
h5.card-header {
font-size: 1.1rem;
}
.formElements label {
display: inline-block;
margin: .5rem 0;
}
</style>
[{capture name="d3script"}][{strip}]
@ -72,9 +76,17 @@
[{$action->getTitle()}]
</h5>
<div class="card-body">
<p class="card-text">
[{$action->getDescription()}]
</p>
[{if $action->getDescription()}]
<p class="card-text">
[{$action->getDescription()}]
</p>
[{/if}]
[{if $action->hasFormElements()}]
[{foreach from=$action->getFormElements() item="formElement"}]
[{$formElement}]
[{/foreach}]
[{/if}]
<div class="btn-group">
<button type="button" class="btn btn-primary" onclick="startAction('[{$id}]')">

View File

@ -23,6 +23,10 @@
h5.card-header {
font-size: 1.1rem;
}
.formElements label {
display: inline-block;
margin: .5rem 0;
}
</style>
[{capture name="d3script"}][{strip}]
@ -74,9 +78,17 @@
[{$export->getTitle()}]
</h5>
<div class="card-body">
<p class="card-text">
[{$export->getDescription()}]
</p>
[{if $export->getDescription()}]
<p class="card-text">
[{$export->getDescription()}]
</p>
[{/if}]
[{if $export->hasFormElements()}]
[{foreach from=$export->getFormElements() item="formElement"}]
[{$formElement}]
[{/foreach}]
[{/if}]
<div class="btn-group">
<button type="button" class="btn btn-primary" onclick="startExport('[{$id}]', 'CSV')">

View File

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