Crosscutting concepts
Naming conventions for entities of API pages
There are only two hard things in Computer Science: cache invalidation and naming things.
Every time an external API shall be implemented, the same question comes up, how should the interfaces and classes in charge be named. Every time a new, apparently brilliant solution is found, leading to multiple diverging naming conventions over the lifespan of a project, which in turn makes it virtually impossible to identify entities that deal with external APIs. The following naming conventions were developed in order to counteract this problem:
-
Whenever an external API shall be implemented, the prefix
Remote
must be used. This way, when looking at the class or interface, it is clear that they deal with remote (external) data. -
The repository pattern must be used and be suffixed by the keyword
Repository
. Magento uses the repository design pattern to abstract CRUD operations on data. The purpose of this design pattern is to make data access independent of its actual location (local database, remote service, etc.) and is thus ideal for accessing remote APIs.
When this naming convention is used, the following regular expression suffices to find all entities dealing with remote APIs:
/Remote.*Repository/
Reuse of Magento repositories
The logical consequence of using the repository design pattern as an abstraction for remote CRUD operations, is to reuse / implement the repository interfaces provided by Magento. Experience has shown though, that this leads to many unwanted side effects. Most plugins are registered on interface level, not for concrete classes. Thus executing custom implementations will also execute all the plugins, which is neither wanted nor reasonable. Nevertheless, it is a good idea to stick as close as possible to the repository interfaces provided by Magento, as it simplifies understanding and dealing with the code for developers. The preferred solution is to create a copy of the repository interface provided by Magento. A benefit of this solution is, that the copy can be stronger typed than the original interface, which improves code quality. In order to set the copy apart from the original, the naming convention described above must be used.
Since it is possible, that Dynamics BC does not provide endpoints for all CRUD operations, yet the repository interface does imply and force that all operations exist, the following strategy has proven successful in solving the issue:
-
Implement all methods for which Dynamics BC provides an endpoint
-
Let all other methods throw a
\TechDivision\DynamicsBcApiClient\Exception\NoApiAvailableException
Transformation of data objects
When communicating with Dynamics BC the need will arise to transform native Magento objects (e.g. \Magento\Customer\Api\Data\CustomerInterface
) into data objects expected by Dynamics BC and vice versa. Usually the data structure expected / provided by Dynamics BC will diverge from the one expected / provided by Magento.
Since the client module makes use of DTOs for transport purposes, which are capable of de-/serializing raw data and are meant to reflect the data structure as well as the field labels used by Dynamics BC endpoints, a transformation of native Magento data objects into such payload DTOs and vice versa is required.
Classes that perform such transformations are to be suffixed with the keyword Transformer
.
The following conventions have to be used when implementing transformers:
-
Class names must be suffixed with the keyword
Transformer
. This allows for visual and automated identification of the classes. -
Every transformer may only be responsible for a single object type.
-
Transformers may be bidirectional but they are not forced to be. In case the transformation is only needed in one direction, the opposite direction may be omitted.
-
All public methods of a transformer have to be strongly typed in order to enforce rule 2.
-
The method that is responsible for transforming a native Magento object into a DTO has to be named
getPayload
. -
The method that is responsible for transforming a DTO in a native Magento object has to be prefixed with the keyword
get
and use a specking suffix (e.g.getCustomer
for transforming a DTO into\Magento\Customer\Api\Data\CustomerInterface
).
Applying the rules above leads to a transformer for \Magento\Customer\Api\Data\CustomerInterface
being defined as follows:
use \Magento\Customer\Api\Data\CustomerInterface;
use \Vendor\Module\Api\Data\CustomerPayloadInterface;
interface CustomerTransformerInterface
{
public function getPayload(CustomerInterface): CustomerPayloadInterface;
public function getCustomer(CustomerPayloadInterface): CustomerInterface;
}