I'm following a tutorial which I think is written by someone who doesn't know what he's doing (already caught 2 obvious mistakes and the rest of code is messy). But I don't want to discredit the guy completely, so I'm asking here about something else that I don't understand.
First of all, I will send 100 brownie points,
my 2 pets, and a box of chocolate to
whoever can explain to me what is
going on with this code.
He's using module-based architecture. Module name is frontmodule. Module has MVC. And module has an internal library of its own.
/modules/
/frontmodule/
/models/
/views/
/controllers/ -- the /module controller is here (undestandable)
/library/
/Controller/ -- the /module/library controller is here (why?!)
/Action/
First comes the confusing part. Why each module has an internal library, and why that intenal library has its own controllers and actions. Is this a best practice? I'm thinking this library could be moved to a plugin that the module can use. Not sure..
Now comes the interesting part.... in addition to each module having its own internal library, there's also a Common library shared by all modules (see it below at the same folder level as /modules) and that Common library also has its own controllers and actions (just like each internal libraries have their own controllers and actions)
/modules
/library/
/Common/
/Controller/ -- the /common/library controller is here (why?!)
/Action/
/Helper/
/Plugin/
So we have 3 controllers:
the module controller
the module internal library's controller
the common library's controller
Now here's the insane part that I think is over-complicating life
He says: A module controller extends the
module’s library parent controller
which also extends the Common library
controller.
class IndexController
extends Frontoffice_Library_Controller_Action_Abstract { ... }
abstract class Frontoffice_Library_Controller_Action_Abstract
extends Custom_Controller_Action_Abstract { ... }
So I guess:
the module controller = IndexController
the module internal library's controller = Frontoffice_Library_Controller_Action_Abstract
the common library's controller = Custom_Controller_Action_Abstract
where module controller extends module internal library's controller
and module internal library's controller extends common library's controller
Has anyone seen anything like this before? My guess is that this code won't be easy to maintain, but maybe those more experienced with zend can tell me what this guy is trying to achieve. The app structure is a little too messy. I think he's abusing MVC instead of using it to simplifying the app and its maintainability.
The great thing about Zend Framework is that it is use-at-will which means you can use a single component or you can use them all. Most components are also very flexible either via configuration or extension (inheritance or composition, with ZF favoring the latter).
Zend Framework MVC is extremely flexible...even to the point where many have accused it of being over-engineered or bloated itself. This is subjective.
Sure, you probably won't want to use Zend Framework for a simple contact form; however, there is nothing stopping you from utilizing just Zend_Mail and Zend_Form without Zend MVC/Application. With flexibility in mind, there is currently no single methodology which is touted as the best in terms of organizing an application into modules. This is a task best left up to the implementer.
This brings us to the tutorial at hand. The tutorial writer has come up with a strategy for re-use. This is a good thing; however, there are some flaws with his approach.
A library per module.
This is not necessarily bad; however, it is in most cases not necessary. Lets explore what options we have just in case such a structure is needed for some reason.
a. Build a general library (you most likely already do this) namespaced (pseudo if < 5.3 or actual namespaces if >= 5.3).
b. Utilize the intrinsic "Resource Autoloader"
http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html
NOTE: I personally haven't used the resource autoloading much. The one time that I did use it, I found that I could have just moved those items to my library. That being said, there are uses for this. It seems to shine when you expect to mix and match modules across projects or for distribution. ZF2 will address this in a less hacky way IMHO.
Base controllers for re-use.
Again, reuse is great; however, Zend Framework provides better alternatives to sub-classing (inheritance) controllers. First, here are some reasons NOT to use controller inheritance:
a. Keeping things DRY is defeated when you have multiple modules that differ enough to need a base-class per module but functionality is copied/pasted across each module's base controller class.
b. It becomes hard to manage inherited properties as it is harder to visualize what inherited functionality is being utilized by each controller/action
c. With PHP allowing only single class inheritance, you blow your one chance at inheritance here -- use this only if there are no other options left
Alternatives:
a. Front-Controller Plug-ins
Use these when the functionality/logic needs to run on every request regardless of module/controller/action
b. Action helpers
As mentioned by the ZF project lead, "They're a built-in mechanism in Zend Framework to allow you to extend your action controllers in a way that uses composition instead of inheritance."
There isn't anything that you can do in a controller that you can't do via an action helper.
Use these when the functionality needs to happen on a per controller and/or action basis.
So, was the example in the tutorial over-engineered? Not necessarily; however, it is certainly a candidate for incorrectly-engineered as it relates to best practices and provisions given by Zend Framework.
I need to digress for a moment and discuss the terms over-engineered and bloated for just a moment
When someone tells you that something is over-engineered and/or bloated without stating a context please take it with a grain of salt.
The Wikipedia article - http://en.wikipedia.org/wiki/Overengineering reads in part "...when a product is more robust or complicated than necessary for its application...".
So, when referring to something as Over-engineered/bloated one should be careful to qualify the context or application at hand. Blanket statements should be taken with a grain of salt and in most cases, not taken at all. This is akin to saying something like "I'd never use a 'Circular Saw' for woodworking since it has way too many features and those features confuse me". Sure, this tool may be over-kill for small home/side projects; however, since it is super flexible you will be happy you have this tool when you find yourself in situations where you never thought you'd find yourself.
Yes, most web frameworks are over-kill for a simple CRUD application such as a contact page or even a simple blogging application. It is unfortunate that most web frameworks use the blog example as their introductory example - go figure.
Extra Info:
If you wanted to switch layouts based on the module/controller/action, you could write a Front-Controller Plug-in. Just call "Zend_Layout::startMvc" and pass it a layout name and a path.
Switching the actual view script based on the Accept header (or URL parameter or X-HTTP-METHOD-OVERRIDE header) can be done with the context switch action helper (intrinsic to Zend Framework) - http://framework.zend.com/manual/en/zend.controller.actionhelpers.html
Feel free to pass a model instance to an action helper. You can also configure your action helpers with configuration from the bootstrap. This way, there is no need to store things in the global registry which is just a glorified global variable. This is a hidden dependency that you don't need. For the best re-use, you can create your own custom plug-in resources by extending Zend_Application_Resource_ResourceAbstract - http://framework.zend.com/manual/en/zend.application.core-functionality.html#zend.application.core-functionality.resource-resourceabstract
This is insane. You're making web pages, right? This isn't hard. I'd say the stuff you posted is the very definition of overengineering:
http://en.wikipedia.org/wiki/Overengineering
Not insane at all. Perhaps badly or overly engineered, but it could be a useful setup.
It's just two "extra" levels of inheritance, which in some cases might make perfect sense.
properties or methods that should be available in every controller in the system go in the "common library controller".
properties or methods that should be
available in every controller in a
particular module go in the "module
internal library's controller"-
properties or methods required by a
single, concrete controller, live in
that concrete controller.
But generally, this suggests packing an awful lot of logic into the controllers, which is generally bad design.
In this way, you can have logic applied to:
a) a particular controller
b) all controllers in one module
c) all application controllers
Related
I am making my own MVC framework (please do not downvote me because everyone wants to make a framework.) and so.. I want to make a bootstrapping class like I have seen in many frameworks. I am making this because I have decided to move to the next level by started learning a framework from the inside. But I am facing few problems getting through them. But I will separate them in different questions. Now to clarify my question:
What features should a Bootstrapping class have? And Can you give me articles that could help me?
There should not be a "bootstrap class". It is a straightforward process, which can be contain in a simple script, which would serve as entry point for your application. PHP is not Java, therefore you are not require to contain everything within a class.
Usually bootstrap stage of application would have following responsibilities:
set up the autoloader
initialize routing mechanism
configure storage abstractions (db, cache, etc.)
handle the user request (using the routing)
dispatch to MVC
The bootstrap stage in you application is where all the wiring between objects should be set up. It would also be the place where you set up such things as loggers, access control and error handling structures.
You could say that front controller is a part or bootstrapping.
P.S.: also, you might find this answer of mine relevant, since it also contains an example of bootstrap file.
List of recommended articles:
GUI Architectures by Martin Fowler
Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler
A Description of the Model-View-Controller User Interface Paradigm in the Smalltalk-80 System
Understanding JavaServer Pages Model 2 architecture
MVP: Model-View-Presenter The Taligent Programming Model for C++ and Java
The last two links cover two of 3 major MVC-inspired patterns (Model2 MVC and MVP), since classical MVC is actually highly impractical (and actually, almost impossible) to be used for web applications.
Bootstrapping is just a piece of code that will by executed for each requests.
You can place a function or an object whenever you like more according to your framework dir structure.
It must not have some particular features
I have almost completed a PHP project, using MVC, jQuery and Ajax. It is pure PHP project. I don't use any frameworks in the code right know. I would like to change that.
Doing some research, I found, that Yii turns out to be one of the best frameworks out there.
Is it possible to somehow migrate pure PHP project to Yii?
If so, then how to do this? Which steps should I follow in order to reduce the workload and enjoy the benefits the Yii framework presents?
I'm a total Yii newbie, any insights appreciated.
TL;DR : Don't do it. It's a really horrible idea.
The Rant ..
"Framework" is not a magic sauce, that you add to a project, to make it better and shinier.
Doing some research i found Yii turns out to be one of the best frameworks out there.
What a strange research you have done .. I would love to see the materials. Especially, since I would rank it as 3rd worst PHP framework. Only surpassed in it's awfulness by CodeIgniter and CakePHP.
And the reason for it is the extremely bad quality of code, that this framework displays, combined with the bad practices, that it perpetuates.
Why avoid migration?
From your description is obvious, that you are NOT familiar with this framework and have no previous experience with it.
In management of projects there a subject: risk management. And in this case, adding a previously unused framework in final stages of project would constitute a high probability an high impact risk which also, due to the sage of project, is completely unmitigated.
It means that there is a really good chance that something will go wrong. And when it does, it most likely will sink the project. Or at least push back the release data by significant length of time.
In a perfect world frameworks are used to simplify the repetitive tasks of development, at the cost of some performance. Those are the tasks you do at the start of the project. You are not at the start of a project. This means that you will gain no benefits from this "maneuver".
Why not Yii?
As I noted before, there are also reasons not only for avoiding adding framework to an existing project, but also reasons why to avoid Yii in particular.
The inheritance nightmare
All your controller will extend class CController, which extends CBaseController, which extends CComponent
All your "models" will extend ether CActiveRecord or CFormModel, which extends CModel, which extends CComponent.
Both of there chains contain static variables and execute static methods on multitude of different other classes. Combination of these factors will make debugging extremely difficult and tedious.
Global state
There are several forms of global state. One that people in PHP usually know are global variables. But that is not the only form. Every time you have a class that contains a static variable, it also creates a global state, that can (and almost always - will) cause seemingly unrelated instance mysteriously interact.
Use of global state is a core mechanic. You will see static calls all over the codebase, and the Yii's configuration file would not function without global state.
And every time you call Yii::app() you are accessing and/or changing it.
This makes unittesting impossible for Yii applications. And debugging turns into exercise of using grep on your whole project.
Tight coupling
When you create an application in Yii. It becomes bound to it. You cannot execute parts of your application without launching the full framework. Mostly it is due to the static call, that you end up adding to your code.
Every time you add a static call in your own code, that piece of code becomes tied to the name of the class. That essentially is tight coupling.
As you might have noticed (hopefully), there is another way how to achieve the same effect - the use of new operator. That is another way of coupling some code of yours to a specific name of a class.
No interfaces .. none .. whatsoever
No matter how horrible the configuration of a Yii project is, the configuration file was a well intended gesture. The least harmful way to introduce external code and replace existing components in so messed up codebase.
But unfortunately it brings in the focus the problems caused by lack of interfaces and the existing coupling.
One of the component that developers will try to replace is the CUrlManager. Mostly due to way how you can pass additional parameters.
An interface in OOP specifies the contract between two instances. It lets you define the capabilities of an instance, the methods that can be used by others. When it's not there, in a large codebase, you are left guessing, which methods are required and which are not.
In case of Yii components the problem is compounded even further due to static call and deep inheritance. The above mentioned CUrlManager extends CApplicationComponent, which extends CComponent. Also the same file defines CUrlRule and CBaseUrlRule classes.
When you are writing a replacement, you have to write some code, plug it in the configuration and then test it by running your applications. That way you know which method (or parameter) next you need to add.
Basically, it's the "save-an-see-what-blows-up" method of development.
That's not MVC!
Yii does not implement MVC or any of MVC-inspired design patterns. What it calls "MVC" could be described as ActiveRecord-Template-Logic pattern.
Instead of having proper model layer (yes, it should be a layer), the creator(s) of Yii opted for collection of active record and form wrappers. This forces the application logic to be forced in the "controllers".
On the other hand you have glorified templates, instead of proper view instances for containing presentation logic. It is somewhat mitigated by use of widgets, but those instead suffer from SRP violations, because widgets are forced to contain bits of presentation logic and perform partial rendering. The rest of presentation logic ends up again in the controllers.
And to make it all worse, the "controllers" also have to deal with authorization. This usually will mean, that whenever you change the access scheme, you will have to go through every single instance of CController to check whether it needs to be changed too.
It's not MVC. It's a mess with names taken from MVC design pattern and slapped on some components.
All the small things ..
The framework also comes with few minor issue, that do not deserve a separate section:
Defining more then one class per file:
This will get annoying quite fast, because there will be classes that are shoehorned at the class files with completely unrelated filenames. This will mean, that debugging will quite often require use of search.
Slapped on "modules":
By the looks of it, the modules where added to the framework after the fact. Which is why, when you need to set default module, you will have to set it in the configuration files parameter, that is called 'defaultController'.
I actually recently converted a MVC pattern website I had built from the ground up into Yii. It did take some time to set it all up but in all honesty it was well worth it. I was able to throw away a lot of code because there were already Yii extensions doing what I needed. I would also suggest that you keep your database because you can create the controllers and Models using Gii which will save you a ton of time.
I don't know of any quick solutions to this. It depends upon how the code was written. You have the database and your views so it is not really a complete new project when you take into yii. Yii will generate the database models for you. You already have the views from the existing project. Write the controller and actions and modify the views if necessary.
try these links as they refer to the same problem.
How do you convert an old oop project into Yii
tips on migrating an existing site to Yii
Drupal to Yii Migration
Since you already have a code in mvc, things will be much easier for you to migrate. However, while migrating to Yii, since it can generate controller and model very easily using gii, you can take the advantage of it.
So, first generate controller and model using gii, then you can replace your existing code (by replace I mean, substitute your code to the specific function in the controller and model) to the built in controller and model so that the functionality of your site still works. You can modify your view accordingly. But that won't be much of a work.
You can simply register your script for ajax, jquery and css. Those will work as well.
And yes, Yii is the best framework out there so take as much benefit as you can.
Thanks,
Ujjwal
In this project you converted php to yii framework. Its really easy for you if you do following step.
Since you already have a code in mvc, things will be much easier for you to migrate. However, while migrating to Yii, since it can generate controller and model very easily using gii, you can take the advantage of it.
second, If your database is accurate then 50% work complete.when you create CRUD operation using gii then automatically model-view-controller create.if you create mvc in php then it benifit for you.
third,You can simply include your script for ajax, jquery and css. Those will work as well you create a folder in themes(CSS,JS,AZAX,BOOTSTRAP).
four-Protected->view->layout, where you can change your theme..thats all
you also help www.yiiframework.com/doc-2.0/guide-intro-yii.html
if you think my answer is help you then rating me...thank you.
Greetings all!
Looking for some help with MVC in a PHP context. Currently I am building a small, lightweight MVC framework to help expedite application development at work. It's a long hard separation eliminating inline code - at least with numerous projects looming overhead and the temptation to utilize it ever-present.
I understand most of the basic requirements of MVC, and I've already begun porting some of my existing classes that are in Singleton pattern over as utilities in my new framework (these are mostly basic 'handlers' to perform site services - a class for file uploads, authorization, wrapped PDO database queries, error printing etc.)
What I can't seem to grasp moving forward after reading much documentation is the best approach to instantiating views. In my old, inefficient design I would switch off a $_GET variable to switch ouput from within the home view. Just going off intuition, this seems like an extremely bad way of getting the job done.
I've looking into CodeIgniter, and it would seem that there are predefined functions for loading views within that framework. What is the best approach to such an application design? Would it be a class based 'link factory' that utilizes the same variables to fetch content, select the proper view file, and place it in the page flow? Also, how could the new view be included between the header and footer includes in the root index without using switches? This is the only thing really confusing me - I really hope I have worded myself clearly enough.
Thanks all as ever!
I highly recommend "PHP Objects, Patterns, and Practice" by Matt Zandstra. A good bit of the book deals with creating MVC frameworks and would be very, very helpful to you.
It covers these patterns (which you can also research elsewhere):
Front Controller
Application Controller
Page Controller
Template View
View Helper
While I'd suggest going with an established, flexible framework (like Zend), to answer your question, here are the steps involved as I see them (understand I stopped trying to write this kind of stuff a while ago, this is based on my understanding of the existing frameworks I've used).
Some kind of router parses the request and translates to a controller object with an action (or takes the default) and optional parameters. The router then calls the controller object's function matching the action.
The controller object (usually extended from a generic controller object) process the request and determines what data to pass to the view, as well as what view to use. Most frameworks setup a default view based on the action, but ultimately it's up to the controller to decided what view to use.
The view takes the data and displays it.
That is my very simplified take on the process.
I have tried many PHP MVC frameworks and I noticed that in many frameworks you can do things like this:
$this->security->encodeForHTML();
So, basically there is a class Security, which contains a method encodeForHTML(). Isn't this Security class a singleton? Is there a specific name for this kind of "internal" singleton class?
Because there are other classes that are not singletons:
$form = new Form;
In this case, you can create as many forms as you want. I understand the point of this, it clearly doesn't make sense to initialize many security classes, but I am wondering, are there names for these classes (other than singleton and non-singleton)? One guy suggested to use word "plugins" for those classes that can be created and "libraries" for those, which are built in the framework. Does that make sense?
Thanks for your reply!
Current MVC fashion/naming convention calls these Helper Classes/Objects, which is orthogonal to singleton/non-singleton, (helpers often are create as a singleton and/or class with static methods, but they don't have to be)
See Zend Documentation for an example.
A plugin isn't quite the right description. Typically plugins are code/programs written by outside parties to leverage and/or extend functionality within a system. A plugin would be more if the system you were using provided a way for YOU to write a security class and have it automatically instantiated and it's methods available to call, and if your security class could call on System APIs in a standard, non-hack way.
I agree with that 'one guy' you mentioned in your post.
IMO, it really depends on what kind of MVC framework you are using. I haven't tried other frameworks yet, but in CodeIgniter, this falls under two things, models or libraries. Since models are commonly used to handle informations from the database, I would call this 'security' class you mentioned, a library.
I've asked this question on the zfforums as well, but I maybe I'll get a response here.
So the Zend Framework is a general purpose, flexible, loosly coupled, high quality framework. However, I find some of the MVC parts inconsistent and overly complex. Hopefully some of you can justify some of the zf design decisions and answer some questions:
General Questions/Comments
Why doesn't zend mvc follow the same naming conventions as other zend components? For example, mvc uses lower case, plural directory names and class names aren't prefixed with directory info so they can't be easily autoloaded.
I'd like the option to add a module root directory. That way, I wouldn't have to explicitly configure the dispatcher by adding controller/module directories. I'd be able to drop in a module and have it accessible immediately.
Why is there a distinction between view and action helpers? Currently, the helpers aren't designed to be shared throughout the code and there are inconsistent methods of loading and accessing the helpers. Other frameworks allow you to share the same helpers anywhere in your code. I don't see the need to specialize and violate DRY.
Zend View Questions
Why do views use "$this" to access resources? I don't see the need for the extra typing. Some other frameworks extract() an array of view variables and allow loading global functions or autoloading static helpers from within the view: myHelper::someMethod();
Why do view helpers only allow one function per class? That results in a lot of classes and associated maintenance. I'd prefer static classes with any number of methods as already mentioned.
I´m using the Zend Framework in a huge intranet site, since it´s early stages, 0.3 or 0.4 I think, and I followed the most of decisions regarding your questions. I´ll try to explain them a bit:
In most cases you don´t need to use modules. You can drop all your controllers in your application/default directory, name them IndexController or HelpController and you´re done, just access http://www.domain.com/ or http://www.domain.com/help.
If your project starts go grow you can add modules as you wish, prefixing them with the name of the module (directory name) Admin_IndexController or Forum_PostController, acessing them by http://www.domain.com/admin (you´re in admin module, index controller; not in default module/admin controller).
You can set your modules directory at applicatoin/modules, for example, and configure the FrontController to look at this directory for modules. Using addModuleDictory Whenever you create a new directory and put your view/controllers there, they´re auto-discovered by the dispatcher. Here is an example.
As I see they serve clearly distinct purposes. ViewHelpers are used to generate markup and render other actions directly in the view, abstracting menu creation, sidebar, etc. OTOH ActionHelpers interact with the dispatch process, allowing you to redirect to another action, as an example.
Views
In the beggining I too felt it a little awkward, but I got used to. I think the main reason is not to pollute the namespace, but I can be wrong with this. By the way I´m not very fond of the use of extract(), but it´s just my personal preference.
For the main reason that it´s not allowed to have more than one controller per file: autoloading. When you use $this->someViewHelper() the underlying engine looks for a class named *_SomeViewHelper_Helper in your plugin paths. Another reason is that static classes are very hard to unit test against. There´s even a proposal to rewrite the FrontController as an instance class, not a Singleton.
You´re right about the overly complex part that you say in your second paragraph and the developers and community knows about it. It just has to be this way to accomodate all requiriments and variations.
In the end I think that ZF is a very robust framework, giving us the freedom to do what we want.
I hope I could help you clearing your questions.
I don't know all the answers to these but they're interesting questions so I'll have a stab and hopefully someone can fill in the blanks.
General
Classes not in the default module are prefixed with the module name, e.g. Admin_IndexController and would reside in /admin/controllers. I think the reason for the separation, and inconsistent naming (vs. library classes) is that there would be little benefit having them in a nested folder structure. Controllers are part of your implementation so I think it makes sense, personally. Traversing the folders does get a little tiresome, however.
You could modify the dispatcher, or write a plugin to scan for directories and add them.
There is definitely overlap here - the URL helpers are a good example of this. Generally a view helper generates markup so I think there's a big enough distinction.
View
I don't know the exact reason but I'd guess it allows other helpers and view functionality to work together more easily. For example, if you've used the doctype helper to set the doctype, the form element helpers can generate XHTML or HTML as appropriate.
It definitely results in a lot of classes, but I'm not sure about maintenance. I've not run in to any problems. I can see the use in static classes, but remember that Zend_View won't stop you using them. If you have your static classes in your include path (and use Zend_Loader or similar), you can use them instead of or in addition to View Helpers.