I found a standard Yii app's protected
folder structure nearly perfect. With a few simple moves and a little bit change to the code, I managed to bring it to the level, which I found as fully perfect. I want to share my point of view, in case someone would like to use this structure as well.
Some remarks ¶
Note, that this is purely organisational approach. I don't think, that changing your application protected
folder structure will influence security or performance (in both negative or positive meanings) as well as any other aspect except code organisation.
Since some folders are separated into subfolders, I was able to resign from adding something to class names. For example, contact form model was renamed from ContactForm
to just Contact
, because it is separated from data models in models/form
subfolder. This means purity and simplicity for me, but my lead to classes names' conflicts more often. Keep that in mind.
components
folder ¶
In default Yii application, virtually anything that looks similar to the component is kept all together in the protected/components
folder. I found this less useful, so I proposed to separate this folder into four subfolders:
behaviours
-- contains all the behaviours,extenders
-- all classes, that extends framework's base classes, for exampleController
,functions
-- classes, that acts like common function repositories or helpers,widgets
-- for all the visual widgets.
Note: Some propose naming functions
folder with better suiting helpers
name.
Changing structure this way, you have to also change small part of your app's configuration. I.e. change:
'import'=>array
(
'application.components.*',
to:
'import'=>array
(
'application.components.extenders.*',
'application.components.functions.*',
'application.components.widgets.*',
Using this structure, I was able to resign from adding for example E
to class names to distinct them from base classes (with C
in the beginning of a name). So base controller (but extended from CController
) remained named as Controller
(just like in auto-generated app) and CWebUser
, extended by me, remained just WebUser
, without need to rename it to EWebUser
.
Since, behaviours are usually not automatically included/loaded, you don't have to change anything for them. Just remember, to include `.behaviours' subfolder, in path-alias, format, when providing path to their classes, whenever you're using them.
models
folder ¶
Similar change goes for models. Default Yii code organisation keeps all models together and distinguish form models from data models by adding Form
into form models class name. That was something, that I didn't like from the very beginning, so I split protected/models
folder structure into two subfolders:
data
-- all data related models`,form
-- models for all forms.
Similar change to application's configuration must be taken here. Change:
'import'=>array
(
'application.models.*',
to:
'import'=>array
(
'application.models.data.*',
'application.models.form.*',
And also take all side-effects (name simplification as advantage and possible name conflicts as disadvantage) into consideration.
views
folder ¶
There were some forum rummors a year or two ago, that putting layouts in the same structure level as all other controller-related views might be sometimes confusing. I fully agree with that. Situation gets even worse, if you're using widgets, that renders some views. So, to cleanup protected/views
folder structure, I've separated it into three subfolders:
controllers
-- moved all other views' folder here,layouts
-- remains untouched, as in original, auto-generated app,widgets
-- views for possible widgets.
Views that are general or application-wide (for example error.php
) are kept in original place, i.e. directly under protected/views
folder, without further spearation to some folder. But, you may consider creating general
subfolder and keep them there.
To make your application working with new views
folder strucuture, this time you don't change nothing in app's config. Instead, you have to modify your base controller (protected/components/Controller.php
in original Yii structure or protected/components/extenders/Controller.php
in above presented), i.e. the one from which all your app's controllers extends from.
All you have to do, is to copy there getViewPath
function's code, taken from Yii sources and modify path returned in it:
public function getViewPath()
{
if(($module = $this->getModule()) === null) $module=Yii::app();
return $module->getViewPath().DIRECTORY_SEPARATOR.'controllers'.DIRECTORY_SEPARATOR.$this->getId();
}
This will force all your controllers (all extending from this base controller) to look for their views in protected/views/controllers
subfolder.
You have to do similar operation for widgets -- i.e. create own, base, master Widget
(or EWidget
or anything else) components, with overridden getViewPath
returning path with widgets
subfolder in views
folder. And then you have to change all your widgets class definitions to extend from your own Widget
(or EWidget
or anything else) instead of original, base CWidget
.
As for widgets, situation gets a little bit complicated, as getViewPath
implementation in base CWidget
is much more complex and uses additional checkTheme
switch. Since I'm lazy and I'm not using themes at all, I have reduced this code to just simple:
class Widget extends CWidget
{
public function getViewPath()
{
return Yii::app()->getViewPath().DIRECTORY_SEPARATOR.'widgets';
}
}
But, if you're using themes, then you're at the beginning of probably long and probably painful journey, since original CWidget.getViewPath()
implementation contains references to private variables (like $_viewPaths
), which are inaccessible in your extended class.
Summary ¶
Changes introduced here requires only a few minutes of work, but might result in cleaner (better in my opinion) folder structure. If you like my approach, go ahead and feel free to implement it in your own application. Good luck! :]
Very useful article
Thanks buddy! Very useful article.
Good one
It is useful to handle the classes inside components like widgets, functions etc
Very Useful
Great article - very useful.
I've been looking for a good Admin implementation aside from the module approach and have wondered about splitting models such that the admin model extends the base user (business) model and keeping it in a separate directory would also help ... thanks!
widgets views dir and themes
But, if you're using themes, then you're at the beginning of probably long and probably painful journey, since original CWidget.getViewPath() implementation contains references to private variables (like $_viewPaths), which are inaccessible in your extended class.
You're right, that's seems painfull :( If someone do the job it could be nice to share ...
(thanks for that wiki page)
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.