Subjects
In most cases it is not necessary to implement entirely new functionality.
A combination of one or more subjects with observers can completely cover the requirements of a new use case for a new custom plugin.
When do I need a subject?
When is a separate plugin helpful, and when does it make sense to implement and use a Subject?::
-
A method of the Magento RESTFul API needs to be called after the product import gets completed
The Subject plugin TechDivision\Import\Plugins\SubjectPlugin
implements the observer pattern and is the first choice for most cases.
-
The Subject plugins allow registering an unlimited number of subjects, while each of them itself can have an unlimited number of observers
-
If a new file gets found that needs to get imported, the
TechDivision\Import\Plugins\SubjectPlugin
calls theprocess()
method -
With the
process()
method, all registered subjects in this file get processed in the sequence; they get registered-
It processes the contents of the files by calling all registered observers for each line of the given file
-
It is a kind of chain that a workflow engine can configure
-
This approach makes it possible to process almost any file by reading the file contents line by line
-
Implement a subject in the following cases:
-
You want to process an import file, regardless of its format?
-
You want to exchange data between observers or pass the data to the following subjects?
-
You need to customize the parsing of the file, e.g., parse a series of lines rather than a single line?
-
You should extend
TechDivision\Import\Subjects\AbstractSubject
or one of its subclassesTechDivision\Import\Subjects\AbstractEavSubject
if you want to implement an import for a new EAV entity
An |
How to implement a subject?
It is helpful to implement the interface TechDivision\Import\Subjects\SubjectInterface
because this is the minimum
requirement for a subject implementation.
Example
- Implementation of a standard requirement:
-
-
We need a subject that allows one of its observers to load a product with the specific SKU found in the import file, add the SKU
entity_id
mapping to the subject, and pass the mappings to the next subject
-
<?php
namespace TechDivision\Import\Product\Subjects;
use TechDivision\Import\Utils\RegistryKeys;
use TechDivision\Import\Subjects\AbstractSubject;
class MySubject extends AbstractSubject (1)
{
/**
* The SKU to entity_id mappings we want to pass to the next subject.
*
* @var array
*/
protedted $skuEntityIdMapping = array();
/**
* Intializes the previously loaded global data for exactly one bunch.
*
* @param string $serial The serial of the actual import
*
* @return void
*/
public function setUp($serial) (2)
{
// load the status of the actual import
$status = $this->getRegistryProcessor()->getAttribute($serial);
// load the SKU => entity_id mappings from further subjects
$this->skuEntityIdMapping = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::SKU_ENTITY_ID_MAPPING];
// invoke the parent method
parent::setUp($serial);
}
/**
* Clean up the global data after importing the bunch.
*
* @param string $serial The serial of the actual import
*
* @return void
*/
public function tearDown($serial) (3)
{
// load the registry processor and add the SKU => entity_id mappings
$this->getRegistryProcessor()->mergeAttributesRecursive(
$serial,
array(
RegistryKeys::SKU_ENTITY_ID_MAPPING => $this->skuEntityIdMapping
)
);
// invoke the parent method
parent::tearDown($serial);
}
/**
* Add the passed SKU => entity ID mapping.
*
* @param string $sku The SKU to map
* @param integer $entityId The entity ID to be mapped
*
* @return void
*/
public function addSkuEntityIdMapping($sku, $entityId) (4)
{
$this->skuEntityIdMapping[$sku] = $entityId;
}
}
1 | The custom class TechDivision\Import\Product\Subjects\MySubject |
2 | TechDivision\Import\Product\Subjects\MySubject implements the setUp() method, automatically called before and after processing the import file |
3 | TechDivision\Import\Product\Subjects\MySubject implements the tearDown() method, automatically called before and after processing the import file |
4 | The subject class TechDivision\Import\Product\Subjects\MySubject provides the method addSkuEntityIdMappping() ,
to get called by the observer with the ID import_product.observer.my to load the product based on the
SKU found in the import file |
The above methods allow us to add/load data from/to the TechDivision\Import\Services\RegistryProcessor
, which acts
as a data container for the entire import process, passing it from one subject to the next.
To make your subject accessible to the workflow engine afterward, you need to define it in your component’s Symfony DI
configuration file symfony/Resources/config/services.xml
.
- Depending on your namespace, this would look like the following XML setup:
symfony/Resources/config/services.xml
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="import_product.subject.my" class="TechDivision\Import\Product\Subjects\MySubject" shared="false"> (1)
<argument type="service" id="import.processor.registry"/>
<argument type="service" id="import.generator.core.config.data.uid"/>
<argument type="service" id="loggers"/>
<argument type="service" id="import.events.emitter"/>
</service>
<service id="import_product.observer.my" class="TechDivision\Import\Product\Observers\MyObserver"> (2)
<argument type="service" id="import_product.processor.product.bunch"/>
</service>
</services>
</container>
1 | Our defined subject ID import_product.subject.my for the custom subject class TechDivision\Import\Product\Subjects\MySubject |
2 | Our defined observer ID import_product.observer.my for the custom observer class TechDivision\Import\Product\Observers\MyObserver
|
{ "id": "import.plugin.subject", "subjects": [ { "id": "import_product.subject.my", (1) "identifier": "files", "file-resolver": { "prefix": "product-import" }, "observers": [ "import_product.observer.my" (2) ] } ] }
1 | Our configuration subject section with the ID import_product.subject.my |
2 | Our configuration observer section with the ID import_product.observer.my |