I'm using the front controller pattern in conjunction with a command resolver class, whose only function is to map requests from the view to a command object.
Everything works fine, but I'm starting to wonder if my implementation, which basically consists of a switch statement, is actually bad practice.
Would it be better practice to replace this switch statement with an XML file, or to map the requests physically to files in the command class (i.e. the request name would be the file name), or is a switch statement fine for this purpose?
Edit: I am using MVC, the front controller exists in the controller. This is more of a design pattern within a design pattern question.
Front Controller needs a router class, often used along with MVC design pattern.
To see how you can avoid switch, see this nice tutorial at phpro.org:
http://www.phpro.org/tutorials/Model-View-Controller-MVC.html
Here is how the router is constructed in above tutorial.
By using switch, you are hardcoding a lot. How about writting command function which will check possible array of files (possibly from cache which will be filled once by reading directory with files), and load a file if its ok.?
Related
I'm developing an application in Cake that heavily interacts with the filesystem. The basic idea is to monitor and index a folder and it's subfolders and files and save meta data for each file in the database. It's working fine so far, but now I got kind of a problem in understanding the MVC mechanics.
I got this heavy FilesController with a lot of functions checking if a file is up-to-date or if it has moved, updating the database entries and so on... Now I want to call some of this actions from a shell/cronjob and I want to call them in the browser too.
I've heard a lot of people complaining about importing controllers in shells and I think I got the idea why this is a bad idea. But now I want to use the same code that interacts with the FileModel directly in a shell and in a controller. Where to put it? What is best practice in this situation? In a component, loading the model? In the controller, importing it in the shell?
Thanks for your help in advance <3
I got this heavy FilesController with a lot of functions checking if a
file is up-to-date or if it has moved,
Wrong place, heavy controllers are definitely wrong. You want fat models, skinny controllers. If there is logic that extracts meta data I probably would put it into app/Utility/FileMetaData or app/Lib/FileMetaData.php and make it a new class. Depending on what it does you might extend the core class Folder or File.
The processing logic for the meta data and reading the folder should go into a model. The model can be used from the shell like in a controller by using the $uses property with an array of models.
To instanitate that class I would use a helper method (I don't mean a view helper by this!) in the model like getMetaDataReader() that returns the instance. The reason for this is to be able to mock the result of that method call in an unit test. Also, if you ever change the class or constructor args you'll have to change only a single place.
Controllers are clearly wrong in shells. There is no request to deal with. Sure technically you can do the stunt and instantiate them there but it is just wrong and doesn't make any sense. If you think you have to or "need" to do so, something is wrong with your application architecture.
You might want to take a look at my FileStorage plugin as well. You can implement an event listener there and when storing a file have the listener automatically process the the meta data.
I am working with Codeignitor 2.x and I was originally using controllers as modules (though not completely HMVC), in that I had a Top Level controller that would call other lower level controllers. My thinking was that because these lower level controllers were still interacting with the view, that they should remain controllers rather than models or drivers.
What I found, however, is that each instance of a controller also spawns a new instance of CI. So I would have 3 or 4 instances of CI running for each request. Ton of overhead, and also caused session issues.
I have since moved these lower level controllers into the library as drivers. They now capture the CI instance in the construct method, and make modifications to it. This makes it VERY nice to work with, and doesn't require the HMVC extension. The drivers are not externally callable either, so it allows me to funnel all requests through specific entry points.
My question is whether this is structurally correct. I have always held the notion that drivers should only modify the data they are provided through their method calls, but many of these drivers will pull information directly from GET and POST, and while they will not directly append to the View, they are often accessing view files, and passing the processed view to the CI instance for output.
[EDIT] A little more context:
One of the drivers I have created is essentially a user login driver called 'Access'. It makes calls to the 'User' model for create/login/logout methods. The driver uses the POST data to check the User model, then loads the correct view with errors and whatever is needed. The idea, being, with 2 lines, I can include this driver in any controller throughout the project, so there is a significant decrease in code redundancy. Again, I know that the drivers should be confined to their scope, however the driver does not modify anything outside it's scope, but simply returns the view it has created.
Is there another method to for doing this that is more inline with straight MVC?
I can't say whether it is right or wrong. But if I were you, I wouldn't do that. I'd probably refactor some of the code. I'd make sure that they don't grab and manipulate data directly from the $_GET or $_POST superglobals. Instead, pass in some data as arguments to a function call. This would make testing easier, since you don't have to simulate a GET or a POST request. While technically, you could just set the value for the superglobals manually from the code, but I'd not recommend doing that. Supplying data as arguments would be much better, especially if you want to write test cases that are to be executed subsequently. Plus, having the libraries interacting with the scopes beyond its own might introduce some hidden gotchas.
In my opinion, libraries are meant to be something like modules, where you can just drag and drop, and then use them without any hassle. If your code really needs to grab or manipulate values from $_GET or $_POST, maybe they are meant to be models instead. Also, you might want to think whether your code is actually a library or not. Ask yourself, will this code be useful outside this application? Or is it highly dependent and can only be useful for this particular app? If you say yes to the latter, then it's probably should be a model instead of a library. Last thing, you should leave the views to the controller. Just return the data you need from the library/model method then pass it to the view from the controller.
I'm trying to implement url routes into my own mvc framework and I like to find out the best way to do it. I'm thinking three solutions.
Make a XML file and read it in my frontend controller then load the matching controller.
Make a table that stores routes then execute a query in my frontend controller then load the matching controller.
use either xml or table and then load routes into memcache then use it.
my concern for #1 and #2 is that I have to read a table or xml for the every access.
my concern for #3 is that not all the hosting companies support memcache.
Any suggestions would be appreciated!
Added: I think I confused some people. By 'route', I'm actually talking about rewriting...like...I want to rewrite visitors to '/controller/action' when they visit '/hello'
Thanks
I would not use XML or tables for this. This will require additional resources for such (in comparison) easy operation. You should have a script which is loaded by mod_rewrite, it parses the URL, loads the proper controller and executes the action.
Hey I know this is a little late, but please check out my Routes class. I know you may not need it now, but hopefully it will still be useful to others.
With this you could easily do exactly what you need to with simple syntax and rules. All you need is to break down the parts of the returned URL (from a Routes::route() call) to calculate your controller and action method (and any possible parameters).
The reason this routing library doesn't do that for you is because you may not be in an MVC world when using it, but it's not that difficult to create. Because it's so low-level you could even create routes dynamically, say from a database table or memcache.
I think I can re-phase and even generalize the problem:
You want to create a representation for something (in this case URL
routes) that are easily human readable (eg, XML);
You might also like that this representation can be easily
computer-generated (eg, from a database table);
At run-time you don't want the solution to be slow: eg, parsing a
large XML file, reading from disk, or fetching rows from a database.
You don't know what caching solution will be available in a
production environment.
So you should aim to:
Perform the slow operations (reading from a database, parsing XML) as
little as possible - perhaps in a compile or build phase, or "on
first run".
Perform the route matching in a fast way: compile the rules directly
into PHP code, and execute them as regular expressions or some such.
Cache the rule code as a php file and include it as regular code. APC
is a php code cache that is commonly available in all production
environments.
This would lead me to implement a solution with the following classes and methods:
Router::addRoute(pattern, controller) - adds a route
Router::match(uri) - returns matching controller
You can store routes in whatever format you fancy (XML, Json, in a database), and generate a simple PHP include file to load routes quickly at runtime:
<?php
// compiled_routes.php
$router = new Router();
$router->addRoute('/', 'HomeController');
$router->addRoute('/widgets', 'WidgetsController');
tl;dr: separate the route rule-parsing from the route matching. Perform rule-parsing only once, and compile the result into PHP code which can be cached by APC.
Hope that helps.
I had a general question on proper design of a php files and their storage on a server.
The problem is this: I had split a php object's functions into different php files, something like:
File 1 AndroidFlashCard.php
class AndroidFlashCard {
public function retrieveCards($packname){}
public function retrievePacks(){}
....
File 2 RetrieveCards.php
include ($_SERVER['DOCUMENT_ROOT'].'/flash_card/AndroidFlashCard.php');
$connection = new AndroidFlashCard();
$connection->retrieveCards($_REQUEST['pack']);
...
Besides the bad code smell regarded making seperate php files for a single function calls, the problem happens when the location/name of class AndroidFlashCard changes. Suppose we go with this shoddy design and I have 1000 different functions...
The quick and dirty solution that came to mind was to have ANOTHER include file:
File 3 include.php:
include ($_SERVER['DOCUMENT_ROOT']./[location of class])
But this doesn't really change anything, because if the location of the include.php file changes, I'd have to make 1000 changes again.
So let's think about this. If I have to keep making 1000 changes to 1000 php files that only include a reference to a class and then code to execute a function, then maybe THAT is the design problem.
In android, I only know how to execute http requests, which is why I split the function calls into separate files.
If I could get hold of that php object, it would make things easier, but I've a feeling this will be difficult to accomplish.
What is the simpler solution? Is writing directory structures a design part of production work, which after approval, is simply just written in stone?
This sounds like a good case for class autoloading. When you attempt to use the class in say file 2, then php can call an autoload function to actually find the class to include. You will have to write the logic behind it, but thats 1 change rather then a 1000 as you say.
__autoload($class_name)
It's generally a good idea to have all class functions inside the class, only only separate classes into different files. As for directory and code structure, you could have a look at how frameworks do it. Like the Model-View-Controller pattern, has an already thought out code structure. Spesifically, you could have a look at the Zend Framework, and simply use the predefined directory structure which the Zend MVC ships with. Using the Zend autoloader, you don't need to include_file() at all, if you stick to the Zend namespace naming conventions.
straight to the point :
I am using Kohana, and I am looking at another script written in plain PHP. In the script, I have a class ShoppingCart. If I am to convert the script to Kohana, where am I to put the class, its methods and its properties?
Is it in my existing default controller? Or should I put it in a separate controller? Or as noobie as it may sound, will I put it in the model?
That depends on the specifics of the class I suppose. To be honest I don't know anything about Kohana, but there's probably a place for "vendor files" somewhere. Maybe it's best to place it there and write wrapper functions for it in your controller. If the class already integrates well with Kohana you may instead choose to use it as a controller or model directly. Or you might want to take the time to rewrite it to make it work as a controller...
Only you can evaluate the best place for it, there's no hard and fast rule here.
Kohana has a folder for 3rd party libraries. The main one is under system/vendor, you can put it in you application/ as well.
Many PHP class loaders require details like your filename should be the same as the class name (at least that's what I read in the Kohana documentation) if you want the classes to be automatically loaded.
If you need to use 3rd party code in your app it's recommended that you create a folder in your app / module folder called 'vendor' and place all of that code there.
You can then include the files by calling:
include kohana::find_file('vendor', 'filename');
If needs be you can also create a wrapper for the external library, a good example of this is the email helper which uses the 3rd party Swift email library.
If you're porting your own class to kohana then you need to work out what the class will be doing and categorise it accordingly.
If the class will be fetching items from some kind of database then you should make it a model. Libraries are usually sets of code that you want reuse across controllers / models, such as authentication, calendar generation etc. Controllers are used for passing data from models to your views / libraries.
See the docs for more info
As per kohana convention, you should place custom classes in application/libraries folder. However for this, you need to know how to get the class to work after putting it there. If you can't figure that out, you can do anything like putting it in your controller or making another controller of it, etc.