4

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.

2
  • If ZF2 was aspect-oriented, I'd decouple these cross-cutting concerns such as persistence into aspects. Trouble is, it's only OOP. Is the loss of modularity inevitable? en.wikipedia.org/wiki/Cross-cutting_concern Commented Nov 25, 2012 at 20:09
  • if you're following a factory pattern, you shouldn't find there to be dependencies between modules, and from an architecture standpoint shared components probably should be in a library folder that all modules have access to. Commented Nov 26, 2012 at 1:21

3 Answers 3

7

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

2 Comments

Adapters and interfaces are already used to decouple some dependencies. The problem is specifically with entities because many different modules / subcomponents access entities from elsewhere. It is a cross-cutting concern which makes the system less modular. i.e. we change one entity and everything needs to change. Do you see the problem? There should be some facade, perhaps. Does ZF2 have any solution?
@MarekCruz I don't think ZF2 really provides anything for that. You could probably consider using some aop library to help you out if that's something you're familiar with using. There shouldn't be any reason why it wouldn't work with ZF2.
0

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.

Comments