From eeab0d5850bd4acc664a564152905a397c0441a4 Mon Sep 17 00:00:00 2001 From: Dominik Rathmer Date: Wed, 26 Jul 2023 13:21:53 +0200 Subject: [PATCH] fix(PT-12973): Fixed log file flooding with continue on error enabled (#58) * fix(PT-12973): Fixed log file flooding with continue on error enabled * fix(PT-12973): Fixed log file flooding with continue on error enabled * fix(PT-12973): Fixed log file flooding with continue on error enabled * fix(PT-12973): Fixed log file flooding with continue on error enabled --- Components/Service/DataWorkflow.php | 8 +- .../Components/Service/DataWorkflowTest.php | 79 +++- .../Mock/FileIoMockWithBrokenRecords.php | 72 +++ .../Components/Service/Mock/LogMock.php | 57 +++ .../TransformerChainWithBrokenRecordsMock.php | 49 +++ .../_fixtures/DataSetBrokenProductImages.php | 416 ++++++++++++++++++ 6 files changed, 667 insertions(+), 14 deletions(-) create mode 100644 Tests/Functional/Components/Service/Mock/FileIoMockWithBrokenRecords.php create mode 100644 Tests/Functional/Components/Service/Mock/LogMock.php create mode 100644 Tests/Functional/Components/Service/Mock/TransformerChainWithBrokenRecordsMock.php create mode 100644 Tests/Functional/Components/_fixtures/DataSetBrokenProductImages.php diff --git a/Components/Service/DataWorkflow.php b/Components/Service/DataWorkflow.php index a15fc987..18a0c957 100644 --- a/Components/Service/DataWorkflow.php +++ b/Components/Service/DataWorkflow.php @@ -159,10 +159,6 @@ public function import(ImportRequest $request, Session $session): array // inserts/update data into the database $dataIo->write($data, $defaultValues); - // writes into database log table - $profileName = $request->profileEntity->getName(); - $dataIo->writeLog($request->inputFile, $profileName); - $session->progress($batchSize); if ($dataIo->supportsUnprocessedData()) { @@ -172,6 +168,10 @@ public function import(ImportRequest $request, Session $session): array } if ($session->getState() === Session::SESSION_FINISHED) { + // writes into database log table + $profileName = $request->profileEntity->getName(); + $dataIo->writeLog($request->inputFile, $profileName); + $session->close(); } diff --git a/Tests/Functional/Components/Service/DataWorkflowTest.php b/Tests/Functional/Components/Service/DataWorkflowTest.php index d822fdb7..c431624b 100644 --- a/Tests/Functional/Components/Service/DataWorkflowTest.php +++ b/Tests/Functional/Components/Service/DataWorkflowTest.php @@ -14,10 +14,11 @@ use Doctrine\DBAL\Exception; use PHPUnit\Framework\TestCase; use Shopware\Tests\Functional\Traits\DatabaseTransactionBehaviour; +use SwagImportExport\Components\DbAdapters\ProductsImagesDbAdapter; use SwagImportExport\Components\DbAdapters\ProductsPricesDbAdapter; use SwagImportExport\Components\Factories\DataTransformerFactory; use SwagImportExport\Components\Factories\ProfileFactory; -use SwagImportExport\Components\Logger\Logger; +use SwagImportExport\Components\FileIO\FileReader; use SwagImportExport\Components\Profile\Profile; use SwagImportExport\Components\Providers\DataProvider; use SwagImportExport\Components\Providers\FileIOProvider; @@ -25,13 +26,19 @@ use SwagImportExport\Components\Session\Session; use SwagImportExport\Components\Session\SessionService; use SwagImportExport\Components\Structs\ImportRequest; +use SwagImportExport\Components\Transformers\DataTransformerChain; use SwagImportExport\Models\Profile as ProfileModel; use SwagImportExport\Tests\Functional\Components\Service\Mock\FileIoMock; +use SwagImportExport\Tests\Functional\Components\Service\Mock\FileIoMockWithBrokenRecords; +use SwagImportExport\Tests\Functional\Components\Service\Mock\LogMock; use SwagImportExport\Tests\Functional\Components\Service\Mock\TransformerChainMock; +use SwagImportExport\Tests\Functional\Components\Service\Mock\TransformerChainWithBrokenRecordsMock; use SwagImportExport\Tests\Helper\ContainerTrait; +use SwagImportExport\Tests\Helper\ReflectionHelperTrait; class DataWorkflowTest extends TestCase { + use ReflectionHelperTrait; use ContainerTrait; use DatabaseTransactionBehaviour; @@ -72,9 +79,9 @@ public function testImportDoesNotOverwritePrices(): void $session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock(); $session->setTotalCount(4); - $session->method('getState')->willReturn('active'); + $session->method('getState')->willReturn('new', 'active', 'finished'); - $workflow = $this->getWorkflow(); + $workflow = $this->getWorkflow(ProductsPricesDbAdapter::class, new FileIoMock(), new TransformerChainMock(), new LogMock()); $workflow->import($importRequest, $session); @@ -93,7 +100,7 @@ public function testSaveUnprocessedDataShouldWriteHeader(): void static::assertIsResource($handle); \ftruncate($handle, 0); \fclose($handle); - $workflow = $this->getWorkflow(); + $workflow = $this->getWorkflow(ProductsPricesDbAdapter::class, new FileIoMock(), new TransformerChainMock(), new LogMock()); $workflow->saveUnprocessedData([], 'someProfileName', $file, 'old'); $expected = 'new | empty | header | test' . \PHP_EOL . 'just | another | return | value'; @@ -102,18 +109,70 @@ public function testSaveUnprocessedDataShouldWriteHeader(): void static::assertSame($expected, $result); } - private function getWorkflow(): DataWorkflow + public function testLogFileShouldHaveDistinctErrorMessages(): void { - $dbAdapter = $this->getContainer()->get(ProductsPricesDbAdapter::class); + $productsImagesDbAdapter = $this->getContainer()->get(ProductsImagesDbAdapter::class); + $value = $this->getReflectionProperty(ProductsImagesDbAdapter::class, 'importExportErrorMode'); + $value->setValue($productsImagesDbAdapter, true); + + $customerGroupInsert = __DIR__ . '/../_fixtures/customerGroupInsert.sql'; + $tree = __DIR__ . '/../_fixtures/tree.json'; + $file = __DIR__ . '/../_fixtures/emptyFile.csv'; + + static::assertFileExists($file); + static::assertFileExists($tree); + static::assertFileExists($customerGroupInsert); + + $conn = $this->getConnection(); + + $conn->executeQuery((string) file_get_contents($customerGroupInsert)); + + $profileModel = new ProfileModel(); + $profileModel->setType('articlesImages'); + $profileModel->setTree((string) file_get_contents($tree)); + $profileModel->setName('default_article_images'); + $profileEntity = new Profile($profileModel); + + $importRequest = new ImportRequest(); + $dataSet = [ + ['profileEntity' => $profileEntity], + ['format' => 'csv'], + ['inputFile' => $file], + ]; + + foreach ($dataSet as $data) { + $importRequest->setData($data); + } + + $session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock(); + $session->setTotalCount(4); + $session->method('getState')->willReturn('new', 'active', 'finished'); + + $logMock = new LogMock(); + $workflow = $this->getWorkflow(ProductsImagesDbAdapter::class, new FileIoMockWithBrokenRecords(), new TransformerChainWithBrokenRecordsMock(), $logMock); + + $workflow->import($importRequest, $session); + + $logs = $logMock->getLogs(); + + static::assertStringContainsString('Kann file:///test/testme.png nicht zum Lesen öffnen', $logs[0][1]); + static::assertStringNotContainsString('Kann file:///test/help.jpg nicht zum Lesen öffnen', $logs[0][1]); + + $value->setValue($productsImagesDbAdapter, false); + } + + private function getWorkflow(string $adapterName, FileReader $fileReader, DataTransformerChain $transformerChain, LogMock $logMock): DataWorkflow + { + $dbAdapter = $this->getContainer()->get($adapterName); $dataProvider = $this->getMockBuilder(DataProvider::class)->disableOriginalConstructor()->getMock(); $dataProvider->method('createDbAdapter')->willReturn($dbAdapter); $dataTransformationFactory = $this->getMockBuilder(DataTransformerFactory::class)->disableOriginalConstructor()->getMock(); - $dataTransformationFactory->method('createDataTransformerChain')->willReturn(new TransformerChainMock()); + $dataTransformationFactory->method('createDataTransformerChain')->willReturn($transformerChain); $fileIOProvider = $this->getMockBuilder(FileIOProvider::class)->disableOriginalConstructor()->getMock(); - $fileIOProvider->method('getFileWriter')->willReturn(new FileIoMock()); - $fileIOProvider->method('getFileReader')->willReturn(new FileIoMock()); + $fileIOProvider->method('getFileWriter')->willReturn($fileReader); + $fileIOProvider->method('getFileReader')->willReturn($fileReader); $sessionService = $this->getMockBuilder(SessionService::class)->disableOriginalConstructor()->getMock(); - $logger = $this->getMockBuilder(Logger::class)->disableOriginalConstructor()->getMock(); + $logger = $logMock; $profileFactory = $this->getMockBuilder(ProfileFactory::class)->disableOriginalConstructor()->getMock(); $profileFactory->method('loadHiddenProfile')->willReturn(new Profile(new ProfileModel())); diff --git a/Tests/Functional/Components/Service/Mock/FileIoMockWithBrokenRecords.php b/Tests/Functional/Components/Service/Mock/FileIoMockWithBrokenRecords.php new file mode 100644 index 00000000..e28ee207 --- /dev/null +++ b/Tests/Functional/Components/Service/Mock/FileIoMockWithBrokenRecords.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SwagImportExport\Tests\Functional\Components\Service\Mock; + +use SwagImportExport\Components\FileIO\FileReader; +use SwagImportExport\Components\FileIO\FileWriter; +use SwagImportExport\Tests\Functional\Components\_fixtures\DataSetBrokenProductImages; + +class FileIoMockWithBrokenRecords implements FileWriter, FileReader +{ + public function __construct() + { + } + + /** + * @param mixed|null $headerData + */ + public function writeHeader(string $fileName, $headerData): void + { + \file_put_contents($fileName, $headerData); + } + + /** + * @param mixed|null $treeData + */ + public function writeRecords(string $fileName, $treeData): void + { + \file_put_contents($fileName, $treeData, \FILE_APPEND); + } + + public function getTotalCount(string $fileName): int + { + return 0; + } + + /** + * @param array $tree + */ + public function setTree(array $tree): void + { + } + + /** + * @return array>> + */ + public function readRecords(string $fileName, int $position, int $step): array + { + return DataSetBrokenProductImages::getDataSet(); + } + + public function supports(string $format): bool + { + return true; + } + + public function writeFooter(string $fileName, ?array $footerData): void + { + } + + public function hasTreeStructure(): bool + { + return false; + } +} diff --git a/Tests/Functional/Components/Service/Mock/LogMock.php b/Tests/Functional/Components/Service/Mock/LogMock.php new file mode 100644 index 00000000..f9a3ede6 --- /dev/null +++ b/Tests/Functional/Components/Service/Mock/LogMock.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SwagImportExport\Tests\Functional\Components\Service\Mock; + +use SwagImportExport\Components\Logger\LogDataStruct; +use SwagImportExport\Components\Logger\LoggerInterface; +use SwagImportExport\Components\Session\Session; + +class LogMock implements LoggerInterface +{ + /** + * @var array|string> + */ + private array $logs; + + /** + * @param array $messages + */ + public function write(array $messages, string $status, Session $session): void + { + $this->logs[] = $messages; + } + + public function logProcessing(string $writeStatus, string $filename, string $profileName, string $logMessage, string $status, Session $session): void + { + $logDataStruct = new LogDataStruct( + \date('Y-m-d H:i:s'), + $filename, + $profileName, + $logMessage, + $status + ); + + $this->writeToFile($logDataStruct); + } + + public function writeToFile(LogDataStruct $logDataStruct): void + { + $this->logs[] = $logDataStruct->getMessages(); + } + + /** + * @return array|string> + */ + public function getLogs(): array + { + return $this->logs; + } +} diff --git a/Tests/Functional/Components/Service/Mock/TransformerChainWithBrokenRecordsMock.php b/Tests/Functional/Components/Service/Mock/TransformerChainWithBrokenRecordsMock.php new file mode 100644 index 00000000..70e7a136 --- /dev/null +++ b/Tests/Functional/Components/Service/Mock/TransformerChainWithBrokenRecordsMock.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SwagImportExport\Tests\Functional\Components\Service\Mock; + +use SwagImportExport\Components\Transformers\DataTransformerChain; +use SwagImportExport\Tests\Functional\Components\_fixtures\DataSetBrokenProductImages; + +class TransformerChainWithBrokenRecordsMock extends DataTransformerChain +{ + public function __construct() + { + // DO NOTHING + } + + /** + * @return array + */ + public function composeHeader(): array + { + return ['new | empty | header | test']; + } + + /** + * @param array> $data + * + * @return array + */ + public function transformForward($data): array + { + return [\PHP_EOL . 'just | another | return | value']; + } + + /** + * @param array $data + * + * @return array>> + */ + public function transformBackward(array $data): array + { + return DataSetBrokenProductImages::getFixedDataSet(); + } +} diff --git a/Tests/Functional/Components/_fixtures/DataSetBrokenProductImages.php b/Tests/Functional/Components/_fixtures/DataSetBrokenProductImages.php new file mode 100644 index 00000000..b8a5b02f --- /dev/null +++ b/Tests/Functional/Components/_fixtures/DataSetBrokenProductImages.php @@ -0,0 +1,416 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SwagImportExport\Tests\Functional\Components\_fixtures; + +class DataSetBrokenProductImages +{ + /** + * @return array>> + */ + public static function getDataSet(): array + { + return [ + 'default' => [ + [ + 'ordernumber' => 'SW10002.3', + 'image' => 'file:///test/help.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,5 Liter}', + ], + [ + 'ordernumber' => 'SW10002.3', + 'image' => 'file:///test/testme.png', + 'main' => '2', + 'description' => ';', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,5 Liter}&{Flascheninhalt:1,5 Liter}', + ], + [ + 'ordernumber' => 'SW10003', + 'image' => 'file:///test/logtest/log.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10004', + 'image' => 'https://shopware.dev.shop/media/image/d5/2d/07/LatteMacchiato502bc1efd65b6.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10005.1', + 'image' => 'https://shopware.dev.shop/media/image/35/44/4c/Emmelkamper_Holunderlikoer_700ml.jpg', + 'main' => '2', + 'description' => 'Emmelkamper Holunderlikör 0,7 Liter', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,7 Liter}', + ], + [ + 'ordernumber' => 'SW10006', + 'image' => 'https://shopware.dev.shop/media/image/bf/b2/1f/Cigar_Special.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10005.1', + 'image' => 'https://shopware.dev.shop/media/image/72/fa/56/Emmelkamper_Holunderlikoer_200ml-1.jpg', + 'main' => '2', + 'description' => 'Emmelkamper Holunderlikör 0,2 Liter', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,2 Liter}', + ], + [ + 'ordernumber' => 'SW10007.1', + 'image' => 'https://shopware.dev.shop/media/image/56/b0/d6/WacholderFlasche_frei.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10008', + 'image' => 'https://shopware.dev.shop/media/image/4f/c8/02/Lagerkorn_TS.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10009', + 'image' => 'https://shopware.dev.shop/media/image/22/47/f5/Lagerkorn_XO.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10010', + 'image' => 'https://shopware.dev.shop/media/image/9f/ec/b9/Glas_Muensterlaender_Aperitif_Imagefoto.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10011', + 'image' => 'https://shopware.dev.shop/media/image/13/a8/09/Muensterlaender_Aperitif-Box.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10012', + 'image' => 'https://shopware.dev.shop/media/image/fb/49/18/KobraVodka.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10013', + 'image' => 'https://shopware.dev.shop/media/image/d7/ee/cb/Tee-weiss-Pai-Mu-Tan-Dose.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10013', + 'image' => 'https://shopware.dev.shop/media/image/2e/e5/ee/Tee-weiss-Pai-Mu-Tan-Schale.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10013', + 'image' => 'https://shopware.dev.shop/media/image/2a/bf/7d/Tee-weiss-Pai-Mu-Tan.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '3', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10014', + 'image' => 'https://shopware.dev.shop/media/image/23/8d/ed/Tee-weiss-Silver-Yin-Zhen-Anbaugebiet.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10014', + 'image' => 'file:///test/non/existent/file.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10014', + 'image' => 'https://shopware.dev.shop/media/image/f9/fc/52/Tee-weiss-Silver-Yin-Zhen-Schale.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '3', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + ], + ]; + } + + /** + * @return array>> + */ + public static function getFixedDataSet(): array + { + return [ + 'default' => [ + [ + 'ordernumber' => 'SW10002.3', + 'image' => 'file:///test/help.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,5 Liter}', + ], + [ + 'ordernumber' => 'SW10002.3', + 'image' => 'file:///test/testme.png', + 'main' => '2', + 'description' => ';', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,5 Liter}&{Flascheninhalt:1,5 Liter}', + ], + [ + 'ordernumber' => 'SW10003', + 'image' => 'file:///test/logtest/log.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10004', + 'image' => 'https://shopware.dev.shop/media/image/d5/2d/07/LatteMacchiato502bc1efd65b6.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10005.1', + 'image' => 'https://shopware.dev.shop/media/image/35/44/4c/Emmelkamper_Holunderlikoer_700ml.jpg', + 'main' => '2', + 'description' => 'Emmelkamper Holunderlikör 0,7 Liter', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,7 Liter}', + ], + [ + 'ordernumber' => 'SW10006', + 'image' => 'https://shopware.dev.shop/media/image/bf/b2/1f/Cigar_Special.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10005.1', + 'image' => 'https://shopware.dev.shop/media/image/72/fa/56/Emmelkamper_Holunderlikoer_200ml-1.jpg', + 'main' => '2', + 'description' => 'Emmelkamper Holunderlikör 0,2 Liter', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => '{Flascheninhalt:0,2 Liter}', + ], + [ + 'ordernumber' => 'SW10007.1', + 'image' => 'https://shopware.dev.shop/media/image/56/b0/d6/WacholderFlasche_frei.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10008', + 'image' => 'https://shopware.dev.shop/media/image/4f/c8/02/Lagerkorn_TS.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10009', + 'image' => 'https://shopware.dev.shop/media/image/22/47/f5/Lagerkorn_XO.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10010', + 'image' => 'https://shopware.dev.shop/media/image/9f/ec/b9/Glas_Muensterlaender_Aperitif_Imagefoto.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10011', + 'image' => 'https://shopware.dev.shop/media/image/13/a8/09/Muensterlaender_Aperitif-Box.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10012', + 'image' => 'https://shopware.dev.shop/media/image/fb/49/18/KobraVodka.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10013', + 'image' => 'https://shopware.dev.shop/media/image/d7/ee/cb/Tee-weiss-Pai-Mu-Tan-Dose.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10013', + 'image' => 'https://shopware.dev.shop/media/image/2e/e5/ee/Tee-weiss-Pai-Mu-Tan-Schale.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10013', + 'image' => 'https://shopware.dev.shop/media/image/2a/bf/7d/Tee-weiss-Pai-Mu-Tan.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '3', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10014', + 'image' => 'https://shopware.dev.shop/media/image/23/8d/ed/Tee-weiss-Silver-Yin-Zhen-Anbaugebiet.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '1', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10014', + 'image' => 'file:///test/non/existent/file.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '2', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + [ + 'ordernumber' => 'SW10014', + 'image' => 'https://shopware.dev.shop/media/image/f9/fc/52/Tee-weiss-Silver-Yin-Zhen-Schale.jpg', + 'main' => '2', + 'description' => ';', + 'position' => '3', + 'width' => '0', + 'height' => '0', + 'relations' => ';', + ], + ], + ]; + } +}