In the final part of this article, we are going to join together what we created in Part 1 (the mass action that generates the file) and Part 2 (the schema and configuration for the file).
In Part 2 we put off implementation of a couple of classes and methods for later and marked them with TODO
. In our export processor class Magently\Dropshipping\ExportProcessor\Edi
we use contentGeneratorFactory
that should be injected in the constructor. Its type is Magently\Dropshipping\ContentGenerator\EdiFactory
and it will help us to create instances of Magently\Dropshipping\ContentGenerator\Edi
. The latter is a simple class:
app/code/Magently/Dropshipping/ContentGenerator/Edi.php
class Edi
{
private $ediFactory;
private $edi;
public function __construct(FileGenerator\EdiFactory $ediFactory)
{
$this->ediFactory = $ediFactory;
}
public function generate(array $orderData)
{
if (!$this->edi) {
$this->edi = $this->ediFactory->create();
}
$this->edi->writeContent($orderData);
}
public function getOutput(): string
{
return $this->edi->output();
}
}
It uses yet another factory for creating a Magently\Dropshipping\ContentGenerator\FileGenerator\Edi
instance where the actual file content is generated. In the code above you can see that the file generator object has two public methods: output
and writeContent
. Here is how they are implemented:
app/code/Magently/Dropshipping/ContentGenerator/FileGenerator/Edi.php
public function output()
{
return $this->content;
}
public function writeContent(array $orderData)
{
$this->writeOrderHeaderRow($orderData);
}
Inside writeContent
we write our order header row which contains order data and adheres to our edi_order_header.xml row definition. There could be different types of rows written there, like packaging etc. Here is the writeOrderHeaderRow
method:
app/code/Magently/Dropshipping/ContentGenerator/FileGenerator/Edi.php
private function writeOrderHeaderRow(array $orderData)
{
$config = $this->orderHeaderFieldReader->read();
$this->writeRow($config, $orderData);
}
It uses orderHeaderFieldReader
. This is the virtual type Magently\Dropshipping\ContentGenerator\FileGenerator\Edi\FieldReader\OrderHeader
that we created in Part 2 and can now inject into the file generator object through di.xml:
app/code/Magently/Dropshipping/etc/adminhtml/di.xml
<type name="Magently\Dropshipping\ContentGenerator\FileGenerator\Edi">
<arguments>
<argument name="orderHeaderFieldReader" xsi:type="object">Magently\Dropshipping\ContentGenerator\FileGenerator\Edi\FieldReader\OrderHeader</argument>
</arguments>
</type>
The writeRow
method called in writeOrderHeaderRow
does what its name implies. It’s implemented this way:
app/code/Magently/Dropshipping/ContentGenerator/FileGenerator/Edi.php
private function writeRow(array $config, array $data)
{
foreach ($config['fields'] as &$field) {
$this->mergeConfig($field, $data);
}
$values = array_column($config['fields'], 'value');
$this->content .= implode(self::DATA_SEPARATOR, $values) . "\n";
}
There are two new elements there. self::DATA_SEPARATOR
is a separator of choice, for example “;
”. mergeConfig
is a private method that handles the mapping
attribute that we used in our XML schema. Here’s its implementation:
app/code/Magently/Dropshipping/ContentGenerator/FileGenerator/Edi.php
private function mergeConfig(array &$field, array $data)
{
if (empty($field['mapping'])) {
$fieldName = $field['name'];
if (array_key_exists($fieldName, $data)) {
$field['value'] = $data[$fieldName];
}
return;
}
$pathElements = explode('\\', $field['mapping']);
$pathElements[] = $field['name'];
$currentArray = $data;
foreach ($pathElements as $element) {
if (!array_key_exists($element, $currentArray)) {
return;
}
if (is_array($currentArray[$element])) {
$currentArray = $currentArray[$element];
continue;
}
$field['value'] = $currentArray[$element];
}
}
Now you can go to the admin panel, check some orders and select Generate EDI File. The downloaded file should look similar to this:
The P1 package row has been added the same way as the header row (using edi_order_package.xml file).
We’ve covered lots of ground creating this feature. EDI files can follow many standards specific to industries and regions. You could define different kinds of rows by creating XML configuration files and injecting them by DI. The code presented was rather verbose, but it was written with extensibility in mind. You could make it even more so by leveraging more interfaces.