I'm working with a MVC modular structure, kind of like you can have with Zend (i'm not using Zend). The directory structure is as follows:
/www
/Config
/Modules
/default
/controllers
indexController.php
loginController.php
/models
/views
blog
/controllers
indexController.php
/models
/views
...
I have a few question about this structure. I have a loginController in my "default" folder. Obviously a user goes to that page to login.
A logged in user can then post someting on the blog. But this is where my problem is. How can different modules share data, like user data?
In this scenario the "default" module will also have a "userModel". But the blog also displays a list of 'newest users'. So somehow it needs access to the userModel which is inside the "default" module.
And i could think of more examples where a certain module needs data from another module.
But this means that a 'module' is in a way almost always dependant on another module. So that's why i don't see any use in this structure. Or am i doing something wrong here..??
I would actually rethink what exactly you put in the modules.
The structures from Model layer should be shared between different modules (also .. your naming convention sucks: modules, models, models, modules, module models .. confusing). The modules are there to package the the part related to interaction.
When you work with domain business object representing "article", logic does not magically change from module to module. Instead there are just limits to what each user can do with it. Depending on, if user is authorized to performs some command or not.
You might benefit from reading this SO topic .. while more focused on authorization at controller's level, the same ideas can be applied on domain objects.
Also, you should carefully read M. Fowler's article on GUI Architectures.
It seems that the 'module' approach is the one that doesn't fit here. In MVC you have only three entities: Model View and Controller.
Controllers can load any model, for example as you mentioned: post_controller needs both post and user models so let it be that way. Because models represents data, it is incorrect to have two user models doing the same thing.
So I would get rid of the module approach because it is an anti pattern you notice that when start repeating classes and/or code through all the application.
Related
I'm building a PHP powered website in this structure:
/public
/js
/css
/img
/index.php
.htaccess
/site
/inc
_header.php
_footer.php
.
.
/func
_base.php
.htaccess
.
.
So a public dir and source (site) dir with all calls routed to index.php, That's the structure, but I am a newbie and I find trouble getting started. All pages will be passed to the index as $_GET request and the appropriate layout/file will be included. but how to go with if it's like index.php?products=prod&page=info
For templating I'll use plain/vanilla PHP like so:
product-name.php:
$product = array(...);
include_once INC_DIR."products.tpl.php"
This is a learning project but I intent to make a personal website using this approach.
Sorry if it's appears to be a vague question, I'm new in PHP and English is not my native Lango.
Cheers!
This may be too broad as there's no definitive answer - however you're asking earnestly for advice so I'll make this a community wiki answer that anyone can improve upon (or kill off as they see fit).
I think you're off to a good start but there are a few things to consider:
Keeping the http files separate from application files is a good idea but I'd split it one further in future, instead of:
/public
Split that into:
/http
/https
Giving you two document roots, one for http documents and the other for https. That way, in future, if you need to add an SSL Certificate you can keep the secure part completely separate from the non-secure part. This means if you put a "Contact Us" form (for instance) under /https it can never be accessed over http - http://www.example.com/contact simply won't work (it doesn't exist under that docroot).
If you add a CMS that could also have it's own document root so that you can completely lock it down (e.g. restrict access by IP address) and that should also have an SSL Cert.
The structure of your /site directory is entirely down to you but it might be worth looking at the MVC pattern. Essentially this is a way of separating concerns, Model, View and Controller. A very simplified explaination would be:
Models are your things - it's really an entire layer that holds your classes and how they talk to the database. You might have a Product class that holds the structure of a product, with an associated Product/database class that does the fetching and updating of that product in the database.
Views are your templates - essentially how you display things on the screen.
Controllers are the glue that stick everything together - so a product category controller would know to fetch the Category model with the category id (from $_GET) which would propagate itself with the category intro from the database and all the relevant products (which would have propagated themselves from the database). The Controller would then attach the Category View to generate what you see on the screen.
With this in mind, it's likely your /site folder might look more like:
/site
App.php // core application class (eq base.php)
/model
/category
Category.php
/db
Category.db.php
/product
Product.php
/db
Product.db.php
/user
User.php
/db
User.db.php
/controller
IndexController.php // for the homepage perhaps
CategoryController.php // for a product category
ProductController.php // for a product
/view
Index.phtml
Category.phtml
Product.phtml
/sub
header.phtml
footer.phtml
index.php
The index file now simply becomes a kind of router - you pass it variables and it fetches the relevant Controller which performs the actions required.
Essentially it will be a very sparse file, it could literally be something as simple as:
require_once realpath("path/to/App.php");
$app = App::start(); // using a Singleton Pattern
$app->fetch($_GET)->content();
Singleton Pattern: Creating the Singleton design pattern in PHP5
Most MVC systems use something like Apache's mod_rewrite to route all requests to the index page. This allows you to use RESTful URLs like http://www.example.com/toys/dinosaurs - your Controller then fetches the data relevant to /toys/dinosaurs; it could be mapped to a category using an url table in the database for instance.
This is essentially how most Frameworks work in PHP but you might be interested in looking at some for inspiration, education or to use one on this project:
Phalcon : https://phalconphp.com/en/
Symfony : https://symfony.com/
Laravel : http://laravel.com/
Yii : http://www.yiiframework.com/
... and there are oh, so many others ...
How to organize controllers under /app/controllers in sub-
folders in CakePHP? I want to create a folder like admin inside the controllers folder and I want to create some controller related to admin. If it is possible, then how can i call a controller from a sub folder?
You can use App::build() to let CakePHP know for additional packages/configurations.
App::build(array(
'Controller' => array('/path/to/controllers', '/next/path/to/controllers')
));
You need to re-think your application structure. Cake has something built in called prefix routing that you should probably be using.
This is also available in 1.x
You can't alter the CakePHP file structure "just like that". It would require serious modification of the core to achieve this, but there is almost never a good reason to do so. If you properly follow the naming conventions, everything should be easy to locate.
What you could do (that is still following conventions and comes close to what you're looking for) is create a plugin for all your admin related tasks and then you can put all that logic under app/Plugin/plugin_name/Controller instead. That way it has it's own place, although you will need to load the plugin from you main application for this to work.
My site structure is currently like this:
/cms/
/data/ - caches etc
/modules/
/public/ - aliases from site public folders
/website1
/images
/layouts, views, scripts, css etc
(no index.php because of the alias)
This works fine, my system looks to the alias folder to run the app. However, I've now got to the point where I would like to extend one of the module controllers.
Ideally my structure would be:
/cms/
.. as above
/CLIENT_ID/
/modules
..extending/overriding scripts
However, this is the problem: the controller to be called must be called according to Zend's file name structure (Module_IndexController etc), so to extend the base classes would be:
Module_IndexController extends Module_IndexController
Which obviously wouldn't work nicely. My thought is that it should be:
CLIENTID_Module_IndexController extends Module_IndexController
But I'm stuck on ideas on how to implement this? I can add the controller directory using: addControllerDirectory on the front controller but I'm guessing I need to change the called class name somewhere?
I can then check if the folder is a directory and run the overriding class rather than the base one.
Any ideas? I'm open to restructuring the folders, but obviously need to keep media files in the public folder.
The problem is that you are not using the conventional directory structure that Zend_Dispatcher, Zend_Autoloader and Zend_Controller are programed to work with.
In my opinion you have two possible solutions:
customize Zend_Autoloader and Zend_Controller and Zend_Dispatcher. You can find possible customizations here, here and here.
modify the directory structure.
In this second case consider theese possible projectual choices:
create independent standalone zend framework projects for all the sites, and create in those the aliases of the CMS folders
like the previous but customizing the module locations with:
http://framework.zend.com/manual/en/zend.controller.modular.html#zend.controller.modular.directories
Use the CMS as a library: you put all the cms files in folder outside the /websiteN and then in websiteN's application.ini you set includePaths.library = /path/to/cms/folder". There are a lot of possible problems in this possibilty, that must be valuated knowing your project. In this way you can call models, extends websites's classes to extend cms's, but you cannot use your cms as the entry point and manager of the user interactions at variuos levels.
As you said, you can tell Zend the base controller directory for each module.
$controller = Zend_controller_Front::getInstance();
$controller->setControllerDirectory(
array("module_name" => "directory_path")
);
I would think Zend would want the naming convention to be ClientId_Module_Controller. But, if you really get stuck with the naming convention, and are using php 5.3 you could use namespaces.
What It Is
Here is what I've done so far:
core/
controllers/ (contains the controllers used by the app)
models/ (contains the models used by the app)
views/ (contains the views used by the app)
base_controller.php (the controller every other extend)
base_model.php (the model every other extend)
vendors/
phprouter/ (a simple router class)
pimple/ (a simple DI container class)
configuration.php (contains all the app configuration)
index.php (includes the configuration, vendors, base model, base controller, sets the DI container up and route the request)
See the code here: http://pastebin.com/pxUpUvv6
Please note that the given code is just an example, therefore the controllers, models, views aren't in place yet. Also, it may be buggy—as untested—, but it doesn't matter right now.
Request Flow
The client requests index.php.
The configuration, vendors, base controller, base model are included.
The DI container and the dependencies are initialized, we can now inject them anywhere.
We map controllers to URL and the router does its job.
The controller is fetched (although this is not in the example code, as noted above).
We do some stuff.
The method then calls ::call_model(), which includes the corresponding model from core/models/, and then calls the same method we're using from the model class corresponding.
The model is fetched.
More stuff.
The model then calls ::call_view()', which includes the corresponding view from core/views/.
The view is fetched and render the page to the client.
FYI: Corresponding
Examples of controller, model, view which correspond:
Controller Controller_Products::list() at core/controllers/Controller_Products.php
Model Model_Products::list() as core/models/Model_Products.php
View at core/views/Model_Products_list.php
Issues Being Faced
Actually, I feel a bit uncomfortable with this structure. Dunno, it seems to be far from scalable, modulable...
Does only the basic folder structure—core{, /controllers, /models/, /views}, vendors at the root—looks good to you?
I feel like I should get __autoload() outside of index.php, which seems a little too big to me. If so, what about DI container?
Maybe if I get to needing more than two external library, it should be better not to have them included one by one, manually? But how?
Putting all the configuration in a file configuration.php at the root looks to me like old-fashioned PHP4. Thanks to the power of Pimple, I could embed this configuration directly into it but yet, where?
I think the way I handle ::call_model() (core/base_controller.php) and ::call_view() (core/base_model.php) is a bit awkward. Would you agree? What'd be a simplified way to redo the whole thing?
Considering all my issues, would it eventually be better for me to use a framework as Symfony?
If something isn't clear, feel free to ask.
Thanks.
Yes.
You can use autoload and DI container together. There is example, how autoload can be used with naming convention. I recommend to use spl_autoload.
With autoload you can remove all (or almost all) includes.
In index.php, I guess.
Yes, it's wrong way. First of all, try to not use static methods. Also, models should have methods with descriptive names, not just 'call me and I will do all what I can'. It's more complex problem - you need to understand how Controller and Model should do their cooperation. As variant, read some books. Controller should call methods of Model, to get data for some situation. Model it's not just place for code of controller. Different controllers can use different models. Models too can use another models.
Answer to this question can not be objective :)
I'm currently working on my own PHP Framework, and I need some help figuring out if I'm going in the right direction or not...
The framework is both for my own use and to generally advance my PHP skills further. I've encountered numerous problems that by overcoming them I have learned a great deal, and love being able to create something from nothing, so I'd rather not see answers like "Just use Zend"! ;)
I have read a bunch of articles both on Stack Overflow and a bunch of other sites, but can't quite get the right answer I need, so hopefully someone can give me some helpful advice!
I've tried a few different solutions, but I've just ended up confusing myself and I'm not sure which direction to go now! Can't quite get my head around it all...
'Theoretical' framework structure
- .htaccess
- index.php
- private/
- app/
- bootstrap.php
- modules/
- default/
- controllers/
- pages.php
- index.php
- models/
- views/
- admin/
- controllers/
- models/
- views/
- config/
- config.php
- autoloader.php
- lib/
- Some_Library
- Class1
- class1.php
- Class2
- class2.php
- public/
- css
- images
- scripts
Details
index.php is the main file, where every request is routed to with .htaccess.
private/ can't be accessed publicly, obviously.
public/ contains all the public files.
app/ contains all app-specific code.
lib/ could contain Zend or another library (I'm also working on my own), to be called with autoloaders
bootstrap.php is the app-specific code... Do I need this? is the main 'index.php' enough?.
modules/ would contain each module... Do I need modules at all?.
default/ is the default module that will contain the MVC's for most requests (used when 'admin' isn't the first part of the URL).
admin/ is the module that will contain the MVC's for the admin section.
Anyways, to my question...
I thought it would be better to separate the admin section from the rest of the website, but that's where I'm getting stuck. I have made the above structure to work with it, but I'm not sure if this is the most effective way.
If a request site.com/videos/view/1/ comes to my site..
Module: Default
Controller: Videos
Action: View
Params: array( '1' )
and if the request site.com/admin/pages/view/1/ comes to my site..
Module: Admin
Controller: Pages
Action: View
Params: array( '1' )
Is this the right way to go about this? Or am I over-complicating it and doing something that's not worth doing?
Should I have a completely separate application framework for my admin section...? Do I even need to separate the admin section's MVC's from the rest of it all?
Sorry for the massive question, just wanted to give you as much info as possible! Feel free to answer whichever part you can =P
One Solution for admin routing is what CakePHP does,
you first define a configuration for the admin string
and then in your controller use actions with a specific naming convertion
//Configuration ============================
Configure::write("admin_routing" , true );
Configure::write("admin_prefix" , "admin" );
//Controller ===============================
class MyController extends AppController{
function index(){
//Will map to /mycontroller/
}
function admin_index(){
//Will map to /admin/mycontroller/
}
}
You can generalize this by using a routing system
just look how your favorite framework does it
On another note
The modules folder seems to be unecesary
I agree with antpaw you should add a globals view and model folder in order to share them across applications
I don't get why autoloader is inside the config directory and not as part of the lib directory, you can also just move the boostrap.php to the config directory
Hope this helps
I know this was asked a long time ago, but I was in the exact same situation a few days ago.
The asker's proposed solution is basically what I went with, oddly enough. Basically, I borrowed a concept from ASP.NET MVC2 called "areas". Areas are sections of the site that have their own controllers and view (also models, but I don't know why ... models should generally be universal). So this is very similar to your initial idea.
In any case following their folder+routing structure made quite a lot of sense for my application (admin type area, a users area, and another level in between). Take a look at it and you might find some success there.
My routing just takes into account areas. The routes are hard coded, so if I need another area I just adjust my routing file. Oh also, my autoloaders are set to look in the area folder if $area is specified.
/admin/team/add/ is read as, Area: Admin, Controller: team, Action: add
whereas
/team/add/ would read as, Area: [none], Controller: team, Action: add
Folder structure kinda like this:
app/
areas/
admin/
controllers/
views/
staff/
controllers/
views/
controllers/
models/
views/
i would suggest you to use a bootstrap.php that manages all the routings so you never run into issues like "i wish i could nest one folder more into my admin module".
i also wouldnt use modules and keep the default controllers right inside the controller/ dir and the admin controllers inside the controller/admin dir. same for models and views.
btw its really not clever not to share the models between different parts of your application, they are going to be the same in 99% of all cases. thats why mvc is so powerful. sometimes you even can share some of the view parts inside your app between the front- and backend.