user1080697
user1080697

Reputation:

Zend Framework 2 Architecture (how to reduce coupling between modules)?

There are many components in one ZF2 system. Each component has its own presentation layer, business layer, and data layer. The problem is when component Foo has a Controller which uses component Bar's data layer.

example:

<inside modules, each module can be individually deployed or removed>
\modules
   \Foo                  ; one module (this directory) can be added or removed
     \view               ; presentation layer (view) for all subcomponents
        \Subcomponent1
            \Action1
        \Subcomponent2
            \Action2
        ...
     \src
        \Subcomponent1
            \Entity      ; data layer     (model)
            \Controller  ; business layer (controller)
            \Service     ; service layer  (service)
        \Subcomponent2
            \Entity
            \Controller
            \Service
        \Subcomponent3
            ...
  \Bar
     \view
         ...
     \src
         \Subcomponent1
            ...
  \Baz
     \src
         \Subcomponent1
            ...

Subcomponents are strongly coupled with Entities from other subcomponents, often from different components entirely. That is the case for Controllers and Services. Can this be resolved?

Foo\Subcomponent1 has a FooSub1Service which uses entity from Bar\Subcomponent1 to process passed data and import them in DB. Baz\Subcomponent1 has an AuthenticationService which uses Bar\Subcomponent1 entities to find user by ID, etc.

I am aware of dependency injection, but in this case there is EntityManager in every subcomponent, and it is instructed to find an entity by name and PK i.e. find("Bar\Subcomponent1\Entity\User", 123). And also, when persisting entities I have to instantiate anything that has a foreign key, i.e. UserAddress and add it to the User. Every time I call x = new NameOfEntity(), I tightly couple a subcomponent with some entity from a subcomponent, often from a different system module.

Upvotes: 4

Views: 1796

Answers (3)

user1080697
user1080697

Reputation:

In ZF2, coupling between modules can be reduced using the EventManager, see also here.

In addition, module/config/module.config.php serves as a Facade.

All entities can be defined ONCE in any module's module/config/module.config.php file. Other modules can then use the ServiceManager to resolve their dependencies.

The ServiceManager implements the Service Locator pattern.

With the Facade (module.config.php) and EventManager, coupling between modules was successfully reduced.

Upvotes: 7

zf2
zf2

Reputation: 1

Don't access the entities or repositories directly. Implement one or more Services per Module, you can give them a Interface to make that clearly.

If you use for the Data Layer like a ORM Doctrine 2, then every /entity folder in each Module are shared anyway. That makes it possible to make joins in one repository and get the joined entities. That's not bad.

Don't abuse the event manager only with the goal to decrease the dependencies. Use shared services and work only with those.

Use the event manager when you want call out to the entire application and collect things or need an answer.

Upvotes: 0

Jani Hartikainen
Jani Hartikainen

Reputation: 43243

You can't always remove all dependencies. For example, an auth module would generally depend on some form of user credentials.

One approach you can take to reduce coupling with specific classes is allow substituting dependencies using adapters.

For example, if you want to be able to use different types of user modules along with your authentication module, you could define an interface in the authentication module which must be implemented by an adapter in the user module in order for it to be compatible with it. Then, add a configuration option to your auth module which allows users to change which user adapter implementation is used.

Depending on the complexity, you could also simply define specific interfaces for objects themselves rather than using adapters. However, this may sometimes add unrelated functions or such into the objects, possibly making their implementation somewhat harder to understand.

Lastly, I would advise against trying to implement too much flexibility like this into your code. It's unlikely that you will need it unless you plan on sharing your modules with the world, as it would usually be much simpler to just change the few lines of code in the module which have the hard dependency, rather than writing entirely new interfaces and classes. This is obviously something you will need to evaluate yourself based on how you plan on using the modules.

Upvotes: 0

Related Questions