add exceptions for better error handling

This commit is contained in:
Daniel Seifert 2021-04-20 09:50:49 +02:00
parent e052d44e59
commit 2c8ef877cc
Signed by: DanielS
GPG Key ID: 8A7C4C6ED1915C6F
14 changed files with 265 additions and 43 deletions

View File

@ -25,6 +25,7 @@
"proprietary" "proprietary"
], ],
"require": { "require": {
"php": ">=7.1",
"oxid-esales/oxideshop-ce": "~6.3", "oxid-esales/oxideshop-ce": "~6.3",
"league/csv": "^9.0", "league/csv": "^9.0",
"mathieuviossat/arraytotexttable": "^1.0" "mathieuviossat/arraytotexttable": "^1.0"

View File

@ -16,10 +16,14 @@
namespace D3\DataWizard\Application\Controller\Admin; 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\DebugException;
use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use League\Csv\CannotInsertRecord;
use League\Csv\Exception;
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController; use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Exception\StandardException; use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
@ -48,9 +52,10 @@ class d3ExportWizard extends AdminDetailsController
} }
/** /**
* @throws CannotInsertRecord * @throws DatabaseConnectionException
* @throws DBALException * @throws StandardException
* @throws Exception * @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/ */
public function doExport() public function doExport()
{ {
@ -60,13 +65,13 @@ class d3ExportWizard extends AdminDetailsController
if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) { if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew( throw oxNew(
StandardException::class, DebugException::class,
$export->getQuery() $export->getQuery()
); );
} }
$export->run(Registry::getRequest()->getRequestEscapedParameter('exportformat')); $export->run(Registry::getRequest()->getRequestEscapedParameter('exportformat'));
} catch (StandardException $e) { } catch (DataWizardException|DBALException|DatabaseErrorException $e) {
Registry::getUtilsView()->addErrorToDisplay($e); Registry::getUtilsView()->addErrorToDisplay($e);
} }
} }

View File

@ -35,17 +35,27 @@ class Configuration
} }
/**
* @param $group
* @param ExportBase $export
*/
public function registerExport($group, ExportBase $export) public function registerExport($group, ExportBase $export)
{ {
$this->exports[$group][md5(serialize($export))] = $export; $this->exports[$group][md5(serialize($export))] = $export;
} }
public function getGroupedExports() /**
* @return array
*/
public function getGroupedExports(): array
{ {
return $this->exports; return $this->exports;
} }
public function getGroups() /**
* @return array
*/
public function getGroups(): array
{ {
return array_keys($this->exports); return array_keys($this->exports);
} }

View File

@ -0,0 +1,20 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\DataWizard\Application\Model\Exceptions;
interface DataWizardException
{
}

View File

@ -0,0 +1,33 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\DataWizard\Application\Model\Exceptions;
use Exception;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
class DebugException extends StandardException implements DataWizardException
{
public function __construct($sMessage = "not set", $iCode = 0, Exception $previous = null )
{
$sMessage = sprintf(
Registry::getLang()->translateString('D3_DATAWIZARD_DEBUG'),
$sMessage
);
parent::__construct($sMessage, $iCode, $previous );
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\DataWizard\Application\Model\Exceptions;
use Exception;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
class NoSuitableRendererException extends StandardException implements DataWizardException
{
public function __construct($sMessage = "not set", $iCode = 0, Exception $previous = null )
{
$sMessage = sprintf(
Registry::getLang()->translateString('D3_DATAWIZARD_ERR_NOSUITABLERENDERER'),
$sMessage
);
parent::__construct($sMessage, $iCode, $previous );
}
}

View File

@ -0,0 +1,22 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\DataWizard\Application\Model\Exceptions;
use OxidEsales\Eshop\Core\Exception\StandardException;
class RenderException extends StandardException implements DataWizardException
{
}

View File

@ -0,0 +1,40 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
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
{
/** @var QueryBase */
public $task;
public function __construct( QueryBase $task, $sMessage = "not set", $iCode = 0, Exception $previous = null )
{
$sMessage = implode(
' - ',
[
$task->getTitle(),
$sMessage
]
);
parent::__construct( $sMessage, $iCode, $previous );
$this->task = $task;
}
}

View File

@ -20,8 +20,6 @@ use D3\ModCfg\Application\Model\d3filesystem;
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;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use League\Csv\CannotInsertRecord;
use League\Csv\Exception;
use OxidEsales\Eshop\Core\DatabaseProvider; use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
@ -36,6 +34,8 @@ abstract class ExportBase implements QueryBase
* @throws DBALException * @throws DBALException
* @throws DatabaseConnectionException * @throws DatabaseConnectionException
* @throws DatabaseErrorException * @throws DatabaseErrorException
* @throws Exceptions\NoSuitableRendererException
* @throws Exceptions\TaskException
* @throws StandardException * @throws StandardException
* @throws d3ShopCompatibilityAdapterException * @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception * @throws d3_cfg_mod_exception
@ -44,24 +44,7 @@ abstract class ExportBase implements QueryBase
{ {
$query = trim($this->getQuery()); $query = trim($this->getQuery());
if (strtolower(substr($query, 0, 6)) !== 'select') { list( $rows, $fieldNames ) = $this->executeQuery( $query );
/** @var StandardException $e */
throw oxNew(
StandardException::class,
$this->getTitle().' - '.Registry::getLang()->translateString('D3_DATAWIZARD_EXPORT_NOSELECT')
);
}
$rows = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC)->getAll($query);
if (count($rows) <= 0) {
throw oxNew(
StandardException::class,
Registry::getLang()->translateString('D3_DATAWIZARD_ERR_NOEXPORTCONTENT')
);
}
$fieldNames = array_keys($rows[0]);
$content = $this->renderContent($rows, $fieldNames, $format); $content = $this->renderContent($rows, $fieldNames, $format);
@ -73,6 +56,9 @@ abstract class ExportBase implements QueryBase
); );
} }
/**
* @return string
*/
public function getButtonText() : string public function getButtonText() : string
{ {
return "D3_DATAWIZARD_EXPORT_SUBMIT"; return "D3_DATAWIZARD_EXPORT_SUBMIT";
@ -82,13 +68,20 @@ abstract class ExportBase implements QueryBase
* @param $format * @param $format
* *
* @return ExportRenderer\RendererInterface * @return ExportRenderer\RendererInterface
* @throws Exceptions\NoSuitableRendererException
*/ */
public function getRenderer($format): ExportRenderer\RendererInterface public function getRenderer($format): ExportRenderer\RendererInterface
{ {
return oxNew(RendererBridge::class)->getRenderer($format); return oxNew(RendererBridge::class)->getRenderer($format);
} }
public function getFileExtension($format) /**
* @param $format
*
* @return string
* @throws Exceptions\NoSuitableRendererException
*/
public function getFileExtension($format): string
{ {
return $this->getRenderer($format)->getFileExtension(); return $this->getRenderer($format)->getFileExtension();
} }
@ -98,9 +91,10 @@ abstract class ExportBase implements QueryBase
* @param $fieldnames * @param $fieldnames
* @param $format * @param $format
* *
* @return mixed * @return string
* @throws Exceptions\NoSuitableRendererException
*/ */
public function renderContent($rows, $fieldnames, $format) public function renderContent($rows, $fieldnames, $format): string
{ {
$renderer = $this->getRenderer($format); $renderer = $this->getRenderer($format);
return $renderer->getContent($rows, $fieldnames); return $renderer->getContent($rows, $fieldnames);
@ -110,9 +104,42 @@ abstract class ExportBase implements QueryBase
* @param $format * @param $format
* *
* @return string * @return string
* @throws Exceptions\NoSuitableRendererException
*/ */
public function getExportFileName($format) : string public function getExportFileName($format) : string
{ {
return $this->getExportFilenameBase().'_'.date('Y-m-d_H-i-s').'.'.$this->getFileExtension($format); return $this->getExportFilenameBase().'_'.date('Y-m-d_H-i-s').'.'.$this->getFileExtension($format);
} }
/**
* @param string $query
*
* @return array
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
protected function executeQuery( string $query ): array
{
if ( strtolower( substr( $query, 0, 6 ) ) !== 'select' ) {
throw oxNew(
Exceptions\TaskException::class,
$this,
Registry::getLang()->translateString( 'D3_DATAWIZARD_ERR_NOEXPORTSELECT' )
);
}
$rows = DatabaseProvider::getDb( DatabaseProvider::FETCH_MODE_ASSOC )->getAll( $query );
if ( count( $rows ) <= 0 ) {
throw oxNew(
Exceptions\TaskException::class,
$this,
Registry::getLang()->translateString( 'D3_DATAWIZARD_ERR_NOEXPORTCONTENT' )
);
}
$fieldNames = array_keys( $rows[0] );
return [ $rows, $fieldNames ];
}
} }

View File

@ -15,7 +15,7 @@
namespace D3\DataWizard\Application\Model\ExportRenderer; namespace D3\DataWizard\Application\Model\ExportRenderer;
use League\Csv\CannotInsertRecord; use D3\DataWizard\Application\Model\Exceptions\RenderException;
use League\Csv\EncloseField; use League\Csv\EncloseField;
use League\Csv\Exception; use League\Csv\Exception;
use League\Csv\Writer; use League\Csv\Writer;
@ -28,14 +28,19 @@ class Csv implements RendererInterface
* @param $fieldNames * @param $fieldNames
* *
* @return string * @return string
* @throws Exception * @throws RenderException
* @throws CannotInsertRecord
*/ */
public function getContent($rows, $fieldNames): string public function getContent($rows, $fieldNames): string
{ {
$csv = $this->getCsv(); try {
$csv->insertOne($fieldNames); $csv = $this->getCsv();
$csv->insertAll($rows); $csv->insertOne( $fieldNames );
$csv->insertAll( $rows );
} catch (Exception $e) {
/** @var RenderException $newException */
$newException = oxNew(RenderException::class, $e->getMessage(), $e->getCode(), $e );
throw $newException;
}
return $csv->getContent(); return $csv->getContent();
} }

View File

@ -19,12 +19,21 @@ use MathieuViossat\Util\ArrayToTextTable;
class Pretty implements RendererInterface class Pretty implements RendererInterface
{ {
/**
* @param $rows
* @param $fieldNames
*
* @return string
*/
public function getContent($rows, $fieldNames) : string public function getContent($rows, $fieldNames) : string
{ {
$renderer = oxNew(ArrayToTextTable::class, $rows); $renderer = oxNew(ArrayToTextTable::class, $rows);
return $renderer->getTable(); return $renderer->getTable();
} }
/**
* @return string
*/
public function getFileExtension(): string public function getFileExtension(): string
{ {
return 'txt'; return 'txt';

View File

@ -15,6 +15,8 @@
namespace D3\DataWizard\Application\Model\ExportRenderer; namespace D3\DataWizard\Application\Model\ExportRenderer;
use D3\DataWizard\Application\Model\Exceptions\NoSuitableRendererException;
class RendererBridge class RendererBridge
{ {
const FORMAT_CSV = 'CSV'; const FORMAT_CSV = 'CSV';
@ -23,16 +25,20 @@ class RendererBridge
/** /**
* @param string $format * @param string $format
* *
* @throws NoSuitableRendererException
* @return RendererInterface * @return RendererInterface
*/ */
public function getRenderer($format = self::FORMAT_CSV): RendererInterface public function getRenderer($format = self::FORMAT_CSV): RendererInterface
{ {
switch ($format) { switch ($format) {
case self::FORMAT_CSV:
return oxNew(Csv::class);
case self::FORMAT_PRETTY: case self::FORMAT_PRETTY:
return oxNew(Pretty::class); return oxNew(Pretty::class);
case self::FORMAT_CSV:
default:
return oxNew(Csv::class);
} }
/** @var NoSuitableRendererException $e */
$e = oxNew(NoSuitableRendererException::class, $format);
throw $e;
} }
} }

View File

@ -17,7 +17,16 @@ namespace D3\DataWizard\Application\Model\ExportRenderer;
interface RendererInterface interface RendererInterface
{ {
/**
* @param $rows
* @param $fieldNames
*
* @return string
*/
public function getContent($rows, $fieldNames) : string; public function getContent($rows, $fieldNames) : string;
/**
* @return string
*/
public function getFileExtension() : string; public function getFileExtension() : string;
} }

View File

@ -39,10 +39,12 @@ $aLang = array(
'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_NOSELECT' => 'Export kann nicht ausgeführt werden. Exporte erfordern SELECT Query.', 'D3_DATAWIZARD_DEBUG' => 'Debug: %1$s',
'D3_DATAWIZARD_ERR_NOEXPORTSELECT' => 'Export kann nicht ausgeführt werden. Exporte erfordern SELECT Query.',
'D3_DATAWIZARD_ERR_NOEXPORT_INSTALLED' => 'Es sind keine Exporte installiert oder aktiviert.', 'D3_DATAWIZARD_ERR_NOEXPORT_INSTALLED' => 'Es sind keine Exporte installiert oder aktiviert.',
'D3_DATAWIZARD_ERR_NOEXPORTCONTENT' => 'Export ist leer, kein Inhalt zum Download verfügbar' 'D3_DATAWIZARD_ERR_NOEXPORTCONTENT' => 'Export ist leer, kein Inhalt zum Download verfügbar',
'D3_DATAWIZARD_ERR_NOSUITABLERENDERER' => 'kein Renderer für Format "%1$s" registriert'
// Abracadata // Abracadata
// Harry Potter // Harry Potter