Backend

A backend for a version (for instance Magento 1.7), is represented by an instance of the Backend class.

Each connector will also create a connector.backend which allows the users to register their backends. For instance, the Magento connector has magento.backend (_inherit connector.backend_model.connector_backend). This model contains a version field which should have the same list of versions (with the exact same name) than the instances of Backend.

Example with the Magento Connector:

# in magentoerpconnect/backend.py

magento = backend.Backend('magento')
""" Generic Magento Backend """

magento1700 = backend.Backend(parent=magento, version='1.7')
""" Magento Backend for version 1.7 """

# in magentoerpconnect/magento_model.py

class MagentoBackend(models.Model):
    _name = 'magento.backend'
    _description = 'Magento Backend'
    _inherit = 'connector.backend'

    _backend_type = 'magento'

    @api.model
    def _select_versions(self):
        """ Available versions

        Can be inherited to add custom versions.
        """
        return [('1.7', 'Magento 1.7')]

    # <snip>

    version = fields.Selection(
        selection='_select_versions',
        string='Version',
        required=True,
    )
    location = fields.Char(string='Location', required=True)
    username = fields.Char(string='Username')
    password = fields.Char(string='Password')

    # <snip>

In the code above, ‘1.7’ is the matching key between the Backend instance (magento1700) and the magento_backend record.

class connector.backend.Backend(service=None, version=None, parent=None, registry=None)[source]

Bases: object

A backend represents a system to interact with, like Magento, Prestashop, Redmine, …

It owns 3 properties:

service

Name of the service, for instance ‘magento’

version

The version of the service. For instance: ‘1.7’

parent

A parent backend. When no ConnectorUnit is found for a backend, it will search it in the parent.

The Backends structure is a key part of the framework, but is rather simple.

  • A Backend instance holds a registry of ConnectorUnit classes
  • It can return the appropriate ConnectorUnit to use for a task
  • If no ConnectorUnit is registered for a task, it will ask it to its direct parent (and so on)

The Backends support 2 different extension mechanisms. One is more vertical - across the versions - and the other would be more horizontal as it allows to modify the behavior for 1 version of backend.

For the sake of the example, let’s say we have theses backend versions:

         <Magento>
             |
      -----------------
      |               |
<Magento 1.7>   <Magento 2.0>
      |
<Magento with specific>

And here is the way they are declared in Python:

magento = Backend('magento')
magento1700 = Backend(parent=magento, version='1.7')
magento2000 = Backend(parent=magento, version='2.0')

magento_specific = Backend(parent=magento1700, version='1.7-specific')

In the graph above, <Magento> will hold all the classes shared between all the versions. Each Magento version (<Magento 1.7>, <Magento 2.0>) will use the classes defined on <Magento>, excepted if they registered their own ones instead. That’s the same for <Magento with specific> but this one contains customizations which are specific to an instance (typically you want specific mappings for one instance).

Here is how you would register classes on <Magento> and another on <Magento 1.7>:

@magento
class Synchronizer(ConnectorUnit):
    _model_name = 'res.partner'

@magento
class Mapper(ConnectorUnit):
    _model_name = 'res.partner'

@magento1700
class Synchronizer1700(Synchronizer):
    _model_name = 'res.partner'

Here, the get_class() called on magento1700 would return:

magento1700.get_class(Synchronizer, session, 'res.partner')
# => Synchronizer1700
magento1700.get_class(Mapper, session, 'res.partner')
# => Mapper

This is the vertical extension mechanism, it says that each child version is able to extend or replace the behavior of its parent.

Note

when using the framework, you won’t need to call get_class(), usually, you will call connector.connector.ConnectorEnvironment.get_connector_unit().

The vertical extension is the one you will probably use the most, because most of the things you will change concern your custom adaptations or different behaviors between the versions of the backend.

However, some time, we need to change the behavior of a connector, by installing an addon. For example, say that we already have an ImportMapper for the products in the Magento Connector. We create a - generic - addon to handle the catalog in a more advanced manner. We redefine an AdvancedImportMapper, which should be used when the addon is installed. This is the horizontal extension mechanism.

Replace a ConnectorUnit by another one in a backend:

@backend(replacing=ImportMapper)
class AdvancedImportMapper(ImportMapper):
    _model_name = 'product.product'

Warning

The horizontal extension should be used sparingly and cautiously since as soon as 2 addons want to replace the same class, you’ll have a conflict (which would need to create a third addon to glue them, replacing can take a tuple of classes to replace and this is exponential). This mechanism should be used only in some well placed circumstances for generic addons.

get_class(base_class, session, model_name)[source]

Find a matching subclass of base_class in the registered classes.

Parameters:
match(service, version)[source]

Used to find the backend for a service and a version

register_class(cls, replacing=None)[source]

Register a class in the backend.

Parameters:
service

Backend Models