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.
Related
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.
In a site where I have 2 similar forms in different pages, since some of the fields are the same, it seems logical I should have one class that validates the fields from both forms.
My question is, where should such a class reside? In /assets? In /includes?
This question goes for any other files (such as 3rd party scripts) as well.
What is the best organization practice for files that do not fall in the /controller and /model directories?
"Assets" generally refers to static assets like images and CSS files, so that's out. If you're not using an MVC framework or if the framework you're using that doesn't have a convention for this (try googling around) I'd recommend creating a directory like /lib, /lib/validators, or perhaps /common. In the end it's most important to pick something that makes sense to you (and other developers who might be working on the project). You can always move files around later if you realize a different structure might be better.
This is very complex topic to talk about, so take a look at symfony framework directory structure:
http://andreiabohner.files.wordpress.com/2007/03/cheatsheetsymfony001_enus.pdf
and try to mimic it in some way. It stores forms in /lib/form/ - you can use for example /form, if your directory structure isn't that complex. Assets are static elements like images or CSS files, as Jordan said. Includes are usually used to store config or so, it's not used in modern development at all.
I'm have a home-grown MVC where a lot of pages share common tasks and libraries, so 99% of my model's work is to call things like Form::validateForm() and return the results to the Controller rather than the model doing all the work.
This means that /foo/form can use the same Form class as /bar/form without needing to replicate any behavior.
It may not be "best practices" to have Classes handle the heavy lifting rather than models, but I do find it allows all those common tasks to be abstracted from the directory structure.
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
I am quite a new Zend Framework user but I am not new to PHP or Programming. I have been going through the code to try and get to grips with how everything slots together. One of the parts I have been looking at is how classes are Autoloaded in the system. I can see that:
Zend_Application_Bootstrap references Zend/Application/Bootstrap.php
Zend_Controller_Action references Zend/Controller/Action.php
... etc etc
Essentially _ get converted to the directory sepearator and get autoloaded.
What I don't understand (although im sure there is a good reason) is why this convention isn't followed for action controllers?
IndexController references Application/controllers/IndexController.php
Why not:
Application_Controllers_Index -> /Application/Controllers/Index.php
or
Controllers_Index -> /Application/Controllers/Index.php
?
I am guessing giving the class a suffix reduces some complexity in the system somewhere, from first looks at the zend framework everything is very well thought out - I cannot imagine conventions are introduced without good reason.
Can anyone explain why controllers are prefixed, or even better point me to some code in the core showing why they have to be prefixed?
Thanks :)
To be honest, I'm not entirely certain as to why the conventions were originally developed. I suspect they had to do with how other frameworks were evolving at the time -- in particular, RoR was spiking in popularity, and this was how they defined application resources. (At the time of the original MVC iteration, I was just starting at Zend; I did a rewrite in fall of 2006, but the goal of that was to keep it as consistent with what had been developed previously, while simultaneously offering better and more flexibility.)
We've continued along the paragigm as it reinforces the idea that all items under the application/ hierarchy are resources, and not your library code. This is particularly important due to the fact that you may have non-class code within this tree (view scripts, layouts, etc.).
However, this has certainly made for a few headaches -- the introduction of the resource loader shows that we had a problem we needed to resolve. The resource loader basically addresses the symptoms, but not necessarily the root cause (poor conventions). As we work on ZF2, this is something we will be revisiting. If you're interested in posting your thoughts, I invite you to do so on the zf-contributors mailing list.
File names and classes names of Controllers should has a postfix Controller. Zend see a postfix in class name, and understand, that it is a controller. He finds this class in controllers folder.
I'm only fairly new to Zend Framework myself, but from what I can tell, given the way the Zend Framework currently stands there is no good reason for this. I'm not sure if it's a hangover from the way things started out, or just the preference of people involved, but I've heard this will be changed for ZF 2.0.
I'm building my personal CMS and need your advice organizing core functions and classes.
I have folders:
/shared
/classes
DB.php
Session.php
Config.php
...
/libraries
Arrays.php
DateTime.php
Email.php
...
The files in 'classes' folder contains core classes (one class per file).
Now the question is about /libraries/ - they contain functions that may be used in any class, and sometimes they use some other function from another library, and sometimes they need to access some core class.
Should i just write them as functions, or make them static and wrap in some class?
Basically i need them everywhere, but keep them organized.
Should i just write them as functions,
or make them static and wrap in some
class? Basically i need them
everywhere, but keep them organized.
Have you looked into namespaces yet? Wrapping all of your functions into a namespace would probably be your best bet.
My suggestion is to first think through about the architectural goals of your CMS. Sure, it's going to be 100% yours, but that doesn't mean you wont suffer from not begin sure whats hooked where and how, what this does and how do I get that from here.
That's why I definitely wouldn't suggest you have libraries calling libraries. From my point of view, none of your classes should be dependent on anything else except for the first few core classes in your application flow since you'd like to distributed the work in some other single purposed self-contained classes. You should aim for singularity and atomicity with your core classes.
I don't know what your architectural pattern will be (I'll presume it's going to be MVC, HMVC or PAC), but I think it's best you first define a few core classes [/core] that will lay the foundations on initializing the application by instancing some libraries [/libraries] that are required for parsing the incoming requests request and doing some default tasks before initializing the requested controller [/controllers].
Libraries should have a single purpose. The session handling library should solely handle sessions, the routing library routing, etc. Initially you can create your base controller and base model and put it in [/core] and have controllers [/controllers] and models [/models] extend your base controller and model from [/core].
As always, the less coupled your components are the better. A good solution will be lightweight, small and extensive in it's purpose. It helps if you change any design ideas in the future that you can simply change the core classes and have a huge impact on the whole application without having to make any further changes in other places.