Skip to content

Commit 1ff9a66

Browse files
committed
Export flat records - testing
1 parent 397e1e3 commit 1ff9a66

5 files changed

Lines changed: 101 additions & 35 deletions

File tree

src/Command/DataExportCommand.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ public function execute(InputInterface $input, OutputInterface $output): int
154154
unlink(stream_get_meta_data($this->file)['uri']);
155155
}
156156

157+
$peakMemory = memory_get_peak_usage(true) / 1024 / 1024;
158+
$output->writeln(sprintf('<info>Peak Memory Usage: %.2f MB</info>', $peakMemory));
159+
157160
return 0;
158161
}
159162

src/Export/Data/Factory/ProductEntityFactory.php

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function __construct(
2323
PropertyFormatter $propertyFormatter,
2424
FieldsProvider $fieldsProviders,
2525
CurrencyFieldsProvider $currencyFieldsProvider,
26-
\Traversable $variantFields,
26+
\Traversable $variantFields
2727
) {
2828
$this->propertyFormatter = $propertyFormatter;
2929
$this->fieldsProvider = $fieldsProviders;
@@ -37,22 +37,27 @@ public function handle(Entity $entity): bool
3737
}
3838

3939
/**
40-
* @param Entity $entity
41-
* @param string $producedType
42-
*
43-
* @return ProductEntity[]|iterable
44-
*
45-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
40+
* @param SalesChannelProductEntity $entity
4641
*/
4742
public function createEntities(Entity $entity, string $producedType = ProductEntity::class): iterable
4843
{
49-
// @todo use spread operator?
5044
$fields = array_merge($this->fieldsProvider->getFields($producedType), $this->currencyFieldsProvider->getCurrencyFields());
51-
$parent = new $producedType($entity, new \ArrayIterator($fields), new \ArrayIterator());
52-
if ($entity->getChildCount()) {
53-
yield from $entity->getChildren()->map(fn (
54-
SalesChannelProductEntity $child) => new VariantEntity($child, $parent->toArray(), $this->propertyFormatter, iterator_to_array($this->variantFields)));
45+
46+
if ($entity->getParentId() !== null) {
47+
// To jest WARIANT.
48+
// Tworzymy bazową encję ProductEntity (odpowiednik rodzica), ponieważ wariant w
49+
// Shopware posiada w sobie dziedziczone dane od rodzica (nazwa, opis, producent).
50+
$pseudoParent = new $producedType($entity, new \ArrayIterator($fields), new \ArrayIterator());
51+
52+
yield new VariantEntity(
53+
$entity,
54+
$pseudoParent->toArray(),
55+
$this->propertyFormatter,
56+
iterator_to_array($this->variantFields)
57+
);
58+
} else {
59+
// To jest PRODUKT GŁÓWNY (Rodzic lub samodzielny produkt).
60+
yield new $producedType($entity, new \ArrayIterator($fields), new \ArrayIterator());
5561
}
56-
yield $parent;
5762
}
5863
}

src/Export/ExportProducts.php

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,39 @@ public function __construct(SalesChannelRepository $productRepository, array $cu
2525

2626
public function getByContext(SalesChannelContext $context, int $batchSize = 100): iterable
2727
{
28-
$criteria = $this->getCriteria($batchSize);
29-
$products = $this->productRepository->search($criteria, $context);
30-
while ($products->count()) {
31-
yield from $products;
32-
$criteria->setOffset($criteria->getOffset() + $criteria->getLimit());
28+
$offset = 0;
29+
30+
while (true) {
31+
$criteria = $this->getCriteria($batchSize, $offset);
3332
$products = $this->productRepository->search($criteria, $context);
33+
34+
if ($products->count() === 0) {
35+
break;
36+
}
37+
38+
foreach ($products->getElements() as $product) {
39+
yield $product;
40+
}
41+
42+
$products->clear();
43+
unset($products, $criteria);
44+
gc_collect_cycles();
45+
46+
// --- DEBUG PAMIĘCI START ---
47+
// Przeliczamy bajty na megabajty dla czytelności
48+
$memoryUsageMB = memory_get_usage(true) / 1024 / 1024;
49+
$peakMemoryMB = memory_get_peak_usage(true) / 1024 / 1024;
50+
51+
echo sprintf(
52+
"[%s] Offset: %d | Memory: %.2f MB | Peak: %.2f MB\n",
53+
date('H:i:s'),
54+
$offset,
55+
$memoryUsageMB,
56+
$peakMemoryMB
57+
);
58+
// --- DEBUG PAMIĘCI END ---
59+
60+
$offset += $batchSize;
3461
}
3562
}
3663

@@ -39,24 +66,30 @@ public function getProducedExportEntityType(): string
3966
return ExportProductEntity::class;
4067
}
4168

42-
private function getCriteria(int $batchSize): Criteria
69+
private function getCriteria(int $batchSize, int $offset): Criteria
4370
{
4471
$criteria = new Criteria();
4572
$criteria->setLimit($batchSize);
73+
$criteria->setOffset($offset);
4674
$criteria->addAssociation('categories');
4775
$criteria->addAssociation('categoriesRo');
48-
$criteria->addAssociation('children.options.group');
4976
$criteria->addAssociation('manufacturer');
50-
$criteria->addAssociation('properties');
51-
$criteria->addAssociation('customFields');
5277
$criteria->addAssociation('properties.group');
53-
$criteria->addAssociation('seoUrls');
78+
$criteria->addAssociation('options.group');
5479
$criteria->addAssociation('media');
55-
$criteria->addAssociation('children.cover.media');
80+
$criteria->addAssociation('cover.media');
81+
$criteria->addAssociation('seoUrls');
82+
$criteria->addAssociation('customFields');
83+
84+
$criteria->addAssociation('configuratorSettings.option.group');
85+
5686
foreach ($this->customAssociations as $association) {
5787
$criteria->addAssociation($association);
5888
}
59-
$criteria->addFilter(new EqualsFilter('parentId', null));
89+
90+
// UWAGA: Usunęliśmy addFilter(new EqualsFilter('parentId', null));
91+
// Chcemy eksportować płasko wszystko: zarówno rodziców jak i warianty,
92+
// więc nie filtrujemy tutaj po parentId!
6093

6194
return $criteria;
6295
}

src/Export/Feed.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,16 @@ public function generate(StreamInterface $stream, array $columns): void
2929
$stream->addEntity($columns);
3030
$emptyRecord = array_combine($columns, array_fill(0, count($columns), ''));
3131

32+
$i = 0;
33+
3234
foreach ($this->getEntities() as $entity) {
3335
$entityData = array_merge($emptyRecord, array_intersect_key($entity->toArray(), $emptyRecord));
3436
$stream->addEntity($this->prepare($entityData));
37+
38+
unset($entity, $entityData);
39+
if (++$i % 500 === 0) {
40+
gc_collect_cycles();
41+
}
3542
}
3643
}
3744

src/Export/Field/FilterAttributes.php

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,33 @@ public function getName(): string
2929

3030
/**
3131
* @param Product $entity
32-
*
33-
* @return string
3432
*/
3533
public function getValue(Entity $entity): string
3634
{
37-
$attributes = $entity->getChildren()->reduce(
38-
fn (array $result, Product $child): array => $result + array_map($this->propertyFormatter, $child->getOptions()->getElements()),
39-
array_map($this->propertyFormatter, $this->applyPropertyGroupsFilter($entity))
40-
);
41-
return $attributes ? '|' . implode('|', array_values($attributes)) . '|' : '';
35+
// 1. Bazowe właściwości (dziedziczone lub bezpośrednie)
36+
$properties = $this->applyPropertyGroupsFilter($entity);
37+
$attributes = $properties ? array_map($this->propertyFormatter, $properties) : [];
38+
39+
// 2. Pobieranie opcji bez ładowania całych encji dzieci
40+
if ($entity->getParentId() !== null) {
41+
// Jesteśmy w wariancie - pobieramy jego konkretne opcje
42+
$options = $entity->getOptions() ? $entity->getOptions()->getElements() : [];
43+
$attributes = array_merge($attributes, array_map($this->propertyFormatter, $options));
44+
} else {
45+
// Jesteśmy w produkcie głównym - pobieramy agregację opcji ze wszystkich wariantów
46+
$configuratorSettings = $entity->getConfiguratorSettings();
47+
if ($configuratorSettings) {
48+
$options = [];
49+
foreach ($configuratorSettings as $setting) {
50+
if ($setting->getOption()) {
51+
$options[] = $setting->getOption();
52+
}
53+
}
54+
$attributes = array_merge($attributes, array_map($this->propertyFormatter, $options));
55+
}
56+
}
57+
58+
return $attributes ? '|' . implode('|', array_unique(array_values($attributes))) . '|' : '';
4259
}
4360

4461
public function getCompatibleEntityTypes(): array
@@ -51,10 +68,11 @@ private function applyPropertyGroupsFilter(Product $product): array
5168
$disabledProperties = $this->exportSettings->getDisabledPropertyGroups();
5269

5370
if (!$disabledProperties) {
54-
return $product->getProperties()->getElements();
71+
return $product->getProperties() ? $product->getProperties()->getElements() : [];
5572
}
73+
5674
return $product->getProperties()
57-
->filter(fn (PropertyGroupOptionEntity $option): bool => !in_array($option->getGroupId(), $disabledProperties))
58-
->getElements();
75+
->filter(fn (PropertyGroupOptionEntity $option): bool => !in_array($option->getGroupId(), $disabledProperties))
76+
->getElements();
5977
}
6078
}

0 commit comments

Comments
 (0)