Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# AGENTS.md - import

## Zweck & Verantwortung

Das `import` Modul ist das **Kern-Framework** des Pacemaker Import-Systems. Es ist ein **Tier 3 Modul** und integriert alle Infrastructure-Tiers (0-2) mit Core-Logik.

**Hauptverantwortung:**
- Zentrale Orchestrierung von Import-Operationen
- Observer Pattern für Row-Level Processing
- Repository Pattern für Daten-Persistierung
- Service Layer für Business Logic
- Event-Driven Architektur für Hooks
- 30+ Listeners und 30+ Observers

## Architektur & Design Patterns

### Kern-Klassen
- **ConfigurationManagerInterface**: Zentrale Konfiguration
- **ImportProcessor**: Haupt-Orchestrator für Imports
- **RowTrait**: Gemeinsame Row-Logik
- **SystemLoggerTrait**: Gemeinsames Logging

### Observers (30+)
- **DynamicAttributeLoader**: Lädt Attribute dynamisch
- **GenericColumnCollectorObserver**: Sammelt Spalten
- **AbstractObserver**: Basis-Klasse für alle Observers
- Spezialisierte Observers für verschiedene Entity-Typen

### Listeners (30+)
- **RenderOperationReportListener**: Rendering von Reports
- **ValidateHeaderRowListener**: Validierung von Header-Zeilen
- **ImportHistoryListener**: Tracking von Import-History
- **CacheUrlRewriteListener**: Caching von URL-Rewrites
- **ArchiveListener**: Archivierung von Import-Dateien

### Verwendete Patterns
- **Observer Pattern**: Für Row-Level Processing
- **Repository Pattern**: Für Daten-Persistierung
- **Service Layer**: Für Business Logic
- **Event-Driven**: Für Hooks und Extensibility
- **Factory Pattern**: Für Object-Erstellung

### Externe Dependencies
- **psr/log** - PSR-3 Logging
- **psr/cache** - PSR-6 Caching
- **psr/container** - PSR-11 DI Container
- **monolog/monolog** - Structured Logging
- **league/event** - Event-System
- **ramsey/uuid** - UUID-Generierung
- **symfony/mailer** - Email-Versand
- **laminas/laminas-filter** - Data Filtering
- **handcraftedinthealps/goodby-csv** - CSV-Parsing
- **ext-json** - JSON-Support
- **ext-zip** - ZIP-Support

## Abhängigkeiten

### Externe Pakete
- **psr/log**, **psr/cache**, **psr/container** - PSR Standards
- **monolog/monolog** - Logging
- **league/event** - Events
- **ramsey/uuid** - UUIDs
- **symfony/mailer** - Email
- **laminas/laminas-filter** - Filtering
- **handcraftedinthealps/goodby-csv** - CSV
- **ext-json**, **ext-zip** - PHP Extensions

### TechDivision Dependencies
- **import-dbal** ^2.0 - DBAL-Interfaces
- **import-dbal-collection** ^2.1 - DBAL-Implementierung
- **import-cache** ^2.0 - Cache-Interfaces
- **import-cache-collection** ^2.0 - Cache-Implementierung
- **import-serializer** ^2.1 - Serializer-Interfaces
- **import-serializer-csv** ^2.1 - CSV-Serializer
- **import-configuration** ^6.1 - Konfiguration-Interfaces

### Abhängig von diesem Modul (9 Reverse Dependencies)
1. **import-app-simple** - Simple Application
2. **import-attribute** - Attribute Importer
3. **import-category** - Category Importer
4. **import-customer** - Customer Importer
5. **import-product** - Product Importer
6. **import-converter** - Converter Framework
7. **import-ee** - EE Functionality
8. **import-configuration-jms** - JMS Configuration
9. **import-cli-simple** - Master CLI

## Wichtige Entry Points

### Haupt-Klassen
```php
// Configuration Manager
ConfigurationManagerInterface::getConfiguration(): ConfigurationInterface
ConfigurationManagerInterface::getOperation($name): OperationConfigurationInterface

// Import Processor
ImportProcessor::process($configuration): void
ImportProcessor::execute($operation): void

// Observer
AbstractObserver::handle($row): void
AbstractObserver::getSubject(): SubjectInterface

// Listener
ListenerInterface::handle(EventInterface $event): void
```

### Verwendungsbeispiel
```php
// In Importern
$processor = new ImportProcessor($configuration);
$processor->process($configuration);

// In Observers
class CustomObserver extends AbstractObserver {
public function handle($row) {
$subject = $this->getSubject();
$subject->addRow($row);
}
}
```

## Events & Extension Points

### Events
- **BeforeImportEvent**: Vor Import-Start
- **AfterImportEvent**: Nach Import-Ende
- **BeforeOperationEvent**: Vor Operation-Start
- **AfterOperationEvent**: Nach Operation-Ende
- **BeforeRowEvent**: Vor Row-Processing
- **AfterRowEvent**: Nach Row-Processing
- **ImportErrorEvent**: Bei Import-Fehler

### Observer-Hooks
- **BeforeCreate**: Vor Create-Operation
- **AfterCreate**: Nach Create-Operation
- **BeforeUpdate**: Vor Update-Operation
- **AfterUpdate**: Nach Update-Operation
- **BeforeDelete**: Vor Delete-Operation
- **AfterDelete**: Nach Delete-Operation

## Hints für KI-Agenten

### Wichtig zu verstehen
1. **Tier 3 Modul**: Zentral für alle Import-Operationen
2. **Observer Pattern**: Zentral für Row-Level Processing
3. **Event-Driven**: Für Extensibility und Hooks
4. **30+ Observers & Listeners**: Umfangreiche Hook-Punkte
5. **9 Dependents**: Basis für alle Entity-Importer

### Bei Änderungen
- **Breaking Changes**: Beachte alle 9 Dependents
- **Observer-Kompatibilität**: Neue Observers sollten optional sein
- **Event-Kompatibilität**: Neue Events sollten optional sein
- **Backward Compatibility**: Alte Imports sollten noch funktionieren

### Implementierungs-Hinweise
- Nutze Observer Pattern für Custom Processing
- Nutze Events für Hooks
- Beachte Observer-Reihenfolge
- Erwäge Listener-Prioritäten

## Bekannte Einschränkungen

- **Single-Threaded**: Nicht für Multi-Threaded Imports
- **Memory-Intensive**: Große Datenmengen können Memory-Probleme verursachen
- **Keine Transaktionen**: Transaktions-Handling erfolgt in Implementierungen
- **Keine Rollback**: Fehler können zu Daten-Inkonsistenzen führen

## Zusammenfassung

`import` ist das **Kern-Framework** des Pacemaker-Systems. Es bietet die zentrale Orchestrierung, Observer Pattern für Row-Level Processing, und Event-Driven Architektur für Extensibility. Es ist die Basis für alle Entity-Importer.

**Für Agenten:** Verstehe dieses Modul als **Kern-Framework** mit Observer Pattern, Repository Pattern, Service Layer, und Event-Driven Architektur.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Version 18.2.0

## Features

### PHP 8.5 Compatibility

* Update dependencies
* Remove PHP 8.2 support

## Bugfixes

* Fix deprecated fputcsv() warning by explicitly passing $escape parameter

# Version 18.1.0

## Features
Expand Down
18 changes: 9 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
"description": "A library supporting generic Magento 2 import functionality",
"license": "MIT",
"require": {
"php": "^8.1",
"php": "^8.3",
"psr/log": "^1.0|^2.0|^3.0",
"psr/cache" : "^2.0|^3.0",
"psr/container": "^1.1.2",
"handcraftedinthealps/goodby-csv": "^1.4",
"monolog/monolog": "^2.9|^3.7",
"league/event": "^2.2",
"ramsey/uuid": "^4.2|^4.7",
"symfony/mailer": "^5.4|^6.4",
"symfony/mailer": "^5.4|^6.4|^7.4",
"laminas/laminas-filter": "^2.31",
"techdivision/import-dbal": "^2.0",
"techdivision/import-dbal-collection": "^2.1",
"techdivision/import-cache": "^2.0",
"techdivision/import-cache-collection": "^2.0",
"techdivision/import-serializer": "^2.1",
"techdivision/import-serializer-csv": "^2.1",
"techdivision/import-configuration": "^6.1",
"techdivision/import-dbal": "^2.1",
"techdivision/import-dbal-collection": "^2.2",
"techdivision/import-cache": "^2.1",
"techdivision/import-cache-collection": "^2.1",
"techdivision/import-serializer": "^2.2",
"techdivision/import-serializer-csv": "^2.2",
"techdivision/import-configuration": "^6.2",
"ext-json": "*",
"ext-zip": "*"
},
Expand Down
4 changes: 2 additions & 2 deletions src/Adapter/Goodby/Exporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,13 @@ public function export($filename, $rows)
// export the header
if (count($columnHeaders) > 0) {
$this->checkRowConsistency($columnHeaders);
$csv->fputcsv($columnHeaders, $delimiter, $enclosure);
$csv->fputcsv($columnHeaders, $delimiter, $enclosure, "\\");
}

// export the rows
foreach ($rows as $row) {
$this->checkRowConsistency($row);
$csv->fputcsv($row, $delimiter, $enclosure);
$csv->fputcsv($row, $delimiter, $enclosure, "\\");
}

// flush the CSV file
Expand Down
2 changes: 1 addition & 1 deletion src/Callbacks/AbstractBooleanCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function handle(?AttributeCodeAndValueAwareObserverInterface $observer =

// query whether or not, the passed value can be mapped to a boolean representation
if (isset($this->booleanValues[strtolower($attributeValue)])) {
return (boolean)$this->booleanValues[strtolower($attributeValue)];
return (bool)$this->booleanValues[strtolower($attributeValue)];
}

// query whether or not we're in debug mode
Expand Down
6 changes: 2 additions & 4 deletions src/HeaderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,14 @@ public function addHeader($name)
*/
public function mapAttributeCodeByHeaderMapping($attributeCode)
{

// load the header mappings
$headerMappings = $this->getHeaderMappings();

// query weather or not we've a mapping, if yes, map the attribute code
$attributeCode = $attributeCode ?? '';

if (isset($headerMappings[$attributeCode])) {
$attributeCode = $headerMappings[$attributeCode];
}

// return the (mapped) attribute code
return $attributeCode;
}
}
2 changes: 1 addition & 1 deletion src/Listeners/ImportHistoryListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ public function handle(EventInterface $event, ?ApplicationInterface $application
$errorMessages[] = $metadata[RegistryKeys::ERROR_MESSAGE];
}
// count the number of processed rows
$processedRows += (integer) $metadata[RegistryKeys::PROCESSED_ROWS];
$processedRows += (int)$metadata[RegistryKeys::PROCESSED_ROWS];
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Loaders/SortedLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ public function getSorters() : array
*/
public function load(?string $pattern = null) : \ArrayAccess
{
$data = $this->getLoader()->load($pattern);

// sort the files loaded by the parent loader instance
$this->getSorterImpl()->sort($data = $this->getLoader()->load($pattern));
$this->getSorterImpl()->sort($data);

// return the sorted files
return $data;
Expand Down
2 changes: 1 addition & 1 deletion src/Subjects/AbstractEavSubject.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public function castValueByBackendType($backendType, $value)

// cast the value to an integer
if ($backendType === BackendTypeKeys::BACKEND_TYPE_INT) {
return (integer) $value;
return (int)$value;
}

// we don't need to cast strings
Expand Down
2 changes: 1 addition & 1 deletion src/Subjects/AbstractSubject.php
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@ public function getStoreId($storeViewCode)

// query whether or not, the requested store is available
if (isset($this->stores[$storeViewCode])) {
return (integer) $this->stores[$storeViewCode][MemberNames::STORE_ID];
return (int)$this->stores[$storeViewCode][MemberNames::STORE_ID];
}

// throw an exception, if not
Expand Down
3 changes: 2 additions & 1 deletion src/Subjects/ExportableTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ protected function overrideArtefacts($type, array $artefacts)
protected function appendArtefacts($type, array $artefacts)
{
foreach ($artefacts as $artefact) {
$this->artefacts[$type][$this->getLastEntityId()][] = $artefact;
$lastEntityId = $this->getLastEntityId() ?? '';
$this->artefacts[$type][$lastEntityId][] = $artefact;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Utils/UrlKeyUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public function loadUrlKey(UrlKeyAwareSubjectInterface $subject, $primaryKeyId)

// initialize the entity type ID
$entityType = $subject->getEntityType();
$entityTypeId = (integer) $entityType[MemberNames::ENTITY_TYPE_ID];
$entityTypeId = (int)$entityType[MemberNames::ENTITY_TYPE_ID];

// initialize the store view ID, use the admin store view if no store view has
// been set, because the default url_key value has been set in admin store view
Expand Down
6 changes: 3 additions & 3 deletions symfony/DependencyInjection/ImportExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use TechDivision\Import\DependencyInjection\Loader\XmlFileLoader;

/**
* The symfony extension implementation for the M2IF import library.
Expand All @@ -30,14 +30,14 @@
*/
class ImportExtension extends Extension
{

/**
* Load's the bundles DI configuration.
*
* @param array $configs The array with the configuration
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container The container instance
* @return void
*/
public function load(array $configs, ContainerBuilder $container)
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__) . '/Resources/config'));
$loader->load('services.xml');
Expand Down
Loading
Loading