Solving limitations of MVC, shared controllers
Update: I should mention that some newer frameworks like Symfony2 and Rails3 solve this issue through bundles and plugins respectively. I haven’t had the opportunity to play with these just yet, or their exact implementation specifics, but it sounds super promising for solving this issue.
One of the problems with MVC is it’s lack of flexibility when it comes to sharing “chunks” of code/logic between various parts of your project. Invariably, as the size of your project grows, you’ll be faced with the need to share these “chunks”. Without thinking outside the box just a bit, you’ll be stuck replicating code, or possibly including another helper function or file.
I’ve been faced with this issue multiple times. Usually the answer has been to just replicate the code, since there has been bits that are slightly different each time anyway, at least that’s how I justified the behavior. But, even still, it didn’t make me feel good and certainly didn’t make me feel good when edits have to be made at a later date.
So, in my latest encounter with this issue, I decided to come up with a more “proper” solution to this quandary. First, I should preface that I’m using symfony 1.x. However, most MVC archs are similar in their approach.
The issue I was faced with was the controller logic that’s shared between various applications. Each application is certainly it’s own beast, but there are a few small “chunks” that are nearly identical between these applications. In our case, our billing profiles are used the same across all applications. Therefore, the controller logic is nearly identical. So, as opposed to setting up methods for each of these routes within each applications’ specific controller, I’ve decided to create a new set of global controllers in our library. These global controllers extend the framework’s default controller class so we maintain all the same functionality as a typical controller. Then, in the controller for each “module” (read: section of a site /blog /products, etc), I just replaced what class is extended to our new global controller class. So in effect, I created an intermediary class that can then be used across any controller that needs access to the specific controller methods (routes).
In retrospect, the concept is pretty obvious and really quite simple. However, it may not be inherently obvious at first, so I wanted to share this bit with anyone else that might be facing a similar issue. Code on!