PHP MVC Custom URI Without Controller Specified - php

What I am looking for is a way to implement MVC without needing the controller specified in the uri. The problem I am finding is that the only way I can have a simple url like example.com/blue-widget is if I first query the database to determine if the product table has the custom uri specified of "blue-widget" if it returns a row at all I can then route to the product controller. The problem with this method is that I have to query each table and then check if any rows are returned to determine which controller to route to. This feels like overkill. Especially if I end up needing more than a handful of controllers.
I would like to keep the traditional functionality of a typical MVC application so that the routing is controller/action/arguments. I simply want to add the feature so that the routing portion could determine what controller to use based on a custom-uri preferably without needing to query the database, but if that is the only option I will have to accept that and maybe minimize it to a single query that determines which table it is found in.
In short traditionally for me to access the product page of blue-widget I would need to have a url at minimum like this:
example.com/product/blue-widget
What I am looking for is a url like this:
example.com/blue-widget
but having some sort of logic to determine if the uri blue widget is a product, or a page, or a category etc without needing to create any kind of map of every possible custom uri.
This is a custom MVC implementation and not based on any particular framework.

There are two primary options as I see it:
have your router configured so that by default it matches classical /:controller/:action/:id structure, and if mo match is found, then it defaults to /:id pattern, with default values for :controller and :action segments.
have your router to primarily function using APCu cache, where each :id has a matching entry of controllers and action names associated with it. If the cache lookup fails, then it falls back standard pattern-matching as a backup.
Maybe this post is also useful: https://stackoverflow.com/a/19309893/727208

Related

How do RESTful controllers work in Laravel 4, how to use them properly?

I'm new to MVC's (this is my first time using one in a real scenario) and I am a little bit confused about how controllers (should) work.
After reading the Laravel documentation, I came to the conclusion that for general tasks like handling loading the sites (different sites are connected together), pages, admin, etc. I need RESTful controllers.
For the simple tasks it worked. It was easy and very fun to use. I had a Route like this:
Route::controller('admin', 'AdminController');
I had functions like
public function getProduct($id)
and it worked. (It was used to get a specific product: ../admin/product/1)
Now I want something more complex. Like
../sites/loadsite/mysite/mypage/mysubpage/123?myoption=yes
How do I do this? How do I begin, how to approach the problem? Do I have to use Route::get() for every single thing or is there a "nicer" way of doing this?
Laravel provides the "Resource Controllers" helper for generating RESTful routes for corresponding controller methods:
http://laravel.com/docs/controllers#resource-controllers
You can use this to easily create the standard REST routes for a given model, or, as shown in the example provided at laravel.com, you can restrict to only certain routes. The table they provide demonstrates how given paths map to given actions / controller methods.
Regarding the example url you give: ../sites/loadsite/mysite/mypage/mysubpage/123?myoption=yes, I'll break the question into two pieces, the url and query string:
Regarding the URL /sites/loadsite/mysite/mypage/mysubpage/123. This would not be considered by many to be a "RESTful" route. Instead of pages and subpages, you should be thinking in terms of models, and sometimes submodels. It is commonly considered best practice to avoid deeply nested routes, which typically means anything more than a single layer of depth: /model/{id}/submodel/[id]
Regarding the query string at the end of the url: ?myoption=yes: Laravel provides access to query string parameters by using the Input::get("Param") function. You do not have to designate query string params in your routes, they can simply be accessed in your controller method.
The "nicer" way is resource controllers - which of course may be combined with route prefixing and filters (e.g. authentication filters), etc.
Inside the methods of resource controllers, you can retrieve additional input (the option in the query string of your example) and process it with validation and whatever you want.

CodeIgniter core changes

CI looks for Segment[1] for controller (in controller dir) and Segment[2] for Method. Now, I have specific requirement by business application which needs that I do not want CI to look or by force go to controller dir to load but I will have something like this "domainURL/module_identifier_id/controller/method/".
Here, every request will be coming along with its associated Module's Identifier ID which will have complete module's configuration and other data (controller files, module location where it was uploaded, all menus and their URLs which will have same URL mechanism which we want to design for developers to develop modules and upload) stored in DB.
We need to get this ID and play with it to fetch relevent records and point CI to load controller from where we want it and indeed rest for methods etc every thing needs to be working as it is.
I hope you understand what we are looking for that we have our own main controller type file where all of the requests will be coming with customizing protocol as described above and developers will be following it by all means, that there must be module identifier first and then controller, method etc...
Let me know if you have any query to be cleared on?
I think I would just use routes for this:
$route[(:any)/(:any)/(:any)] = '$2/$3/$1';
This should just rearrange your segments the way you want, without completely changing the way the native routing system works.

PHP MVC - URL without action

I'm currently creating my own custom MVC framework in PHP that uses the MVC URL standard:
example.com/{controller}/{action}/{id}
This works fine, however, one of my controllers called "books" does not need the action in the URL:
example.com/{controller}/{id}
The index method of the books controller displays a list of books:
example.com/books
I want the controller to display a specific book if an ID follows:
example.com/books/47
At the moment, I have to use this URL to view a specific book which isn't as nice:
example.com/books/view/47
What would be the best way to go about doing this?
If you want to provide the ability to create custom URLs, then you will have to look into creating a routing mechanism. Usually in PHP it is done by employing simplified URL patterns, that are transformed into regular expression.
Then, when user's request gets handled at bootstrap stage, the routing mechanism applies all of the regular expressions on by one. When the match is found, the appropriate route is selected.
The the resulting state of request instance is combination of the data that was extracted with regular expressions, supplemented by default values that are associated with each of those patterns.

Nesting controllers with the Front Controller Pattern and MVC

I'm developing a web application in PHP using an MVC-approach (not using any framework, pure PHP). As is often the case with MVC, every request arrives at a front controller which routes it to the corresponding controller, and executes the requested action. The URL structure looks like this:
www.site.com/controller/action
Let's say I'm building an e-commerce site which has products in different categories. Possible URLs could be:
www.site.com/sofas/overview
www.site.com/video-games/overview
For the first URL, the "sofas" controller is loaded, and the overview() method of it is executed. This all works well until we have to nest these products within parent catagories. I'll take the two previous URLs to demonstrate what I mean:
www.site.com/furniture/sofas/overview
www.site.com/electronics/video-games/overview
Now, the "video-games" controller is nested within the "electronics" controller. However, with the current 'load controller -> execute action' structure this won't work.
A possible solution would be to create a method within the parent controller ("electronics") which gets executed in case an unexisting action is requested ("video-games"). This method checks whether the requested action exists as a controller. If so, the controller gets loaded and the action ("overview") of it gets executed.
I fruitlessly searched for solutions to this limitation of the standard front controller pattern, including here on SO. I think my implementation of MVC is now correct, but the front controller still brings limitations.
I think the thought that you have to have a different "controller" for each different product type may where you are running into problems.
Unless you are going to have drastically different views for each product type, I would think the controller would be linked to a concept such as "catalog" (or "product" or whatever you want to call it). So for example your URL structure might look like
www.site.com/catalog/furniture/sofas/overview
www.site.com/catalog/electronics/video-games/overview
With the catalog portion of the URI determining the controller and the additional URI segments in essence being parameters passed to the controller indicating the specifics of the request.
This would work nicely with an OOP inheritance structure in that you could have a root 'product' class, and then extend that class with subclasses for furniture, electronics, etc. which would each have their own properties specific to the category. You would the further sub-class for sofas, video games, etc.
All your controller would have to do is evaluate the request URI to determine which class to load for the request. So something like:
// assume URI has been parsed to get value such as "sofas", "video-games", etc. into a variable called $class_to_load
$product = new $class_to_load;
$product->overview();
You are confusing MVC structure with routing issues.
The controller should be probably something like a product controller, or a category controller. Group controllers by functionality.
Now routing deals with the structure of the request and where this gets sent in the application.
You should have a routing layer that knows (for example) to send /<category>/<subcategory>/<action> to the appropriate controller (say products controller) with appropriate arguments (i.e category and subcategory) so it can construct a response.
Only directly mapping the url to controller and action (i.e enforcing /<controller>/<action>) is a very limited way of constructing the architecture of your application.

How to decide on controllers for web application?

I use php and usually structure my application into model-view-controller so its always accessed via index.php with class and method attributes. Class attribute passed as part of URL specifies controller class and method simply method to be called. This seems to be pretty common, but then I'm always having trouble in figuring out what controllers shall I create. What is the best, easiest and most applicable way to decide on what controllers should be created? I understand it depends on web application itself but must be some general way of thinking to get this process started.
I've found that building controllers based on your application's objects works well, and can take care of most actions you'll want for your app.
Take a look at SO -- there's URLs starting with /questions, /tags, /users, etc. I'd suggest a design which starts by creating a different controller for each object. /questions (or /questions/list) returns a list of all the questions. /questions/[0-9]+ returns the details of a particular question with that id number. /questions/ask returns the Ask Question interface.
As you continue building your app, you might find that the controller-based-on-objects method doesn't meet all your needs. For example, on my site (http://www.wysiap.com), I eventually made a /list controller to simplify my Grails URL mapping. But in most cases I did use this method and it's easy to figure out which controller should be doing different actions.
I recommend to think about the pages you'll need in your applications to accomplish all the requested tasks. You'll group similar tasks on the same page and create as many pages as you need. A page can be sliced in different views for specific actions.
With this in mind you could have one controller per page. Each view of the page can have its own method (action) in the controller. And inside the method of each view you can have a switch() that will enable you to have several tasks for the view. Example:
index.php (Dashboard controller)
/question-list (QuestionList controller, action index, display the whole page)
/question-list/add (QuestionList controller, action add, manage the "add" view with tasks like show-form, validate-form, insert-question)
/profile (Profile controller, action index)
/profile/edit (Profile controller, action edit, manage all the tasks requested for your profile)
...
I design most of my web applications this way and using Zend-Framework

Categories