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.
Related
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
I have a CakePHP app and would like to incorporate a simple REST API, at first just for GET requests without authentication.
I have the conventional structure, e.g.:
Post (post model),
postsController (posts controller), method names match the routes.
views/posts (posts views - e.g. index.ctp etc)
Say I wanted a few REST API routes how would I add them alongside my normal views and controller methods. I presume having a separate apiPostsController might be a good idea but I'm not sure how to implement.
Route wise, for a given example.com/posts/view/123, the API equivalent might be example.com/api/v1/posts/view/123.
How might I implement this?
Looking at the book, the given instructions make use of the conventional controller and views which are already in use for actually viewing the app.
Why do you think you need another controller? This is not DRY. You'll replicate a lot when you do this.
If your API methods behave that much different you can still use prefix routing and prefix the methods with api, for example: api_some_action().
I guess your API is using XML or Json, see this chapter of the book how to archive this along side the regular HTML views: JSON and XML Views.
Router::connect('/api/:version/:controller/:action/*',
array(),
array(
'version' => 'v1|v2',
)
);
This route should work.
I am working my way through a Yii tutorial book and am currently learning about filters. Filters can be applied in general for the controller or just to specific actions.
The example I am working on is creating a new Issue. Each Issue belongs to a single Project, so we add a filter to ensure the project_id is passed to the issue/create page. Since the issue/create is the only page that needs the project_id, we are applying the filter to a single action:
public function filters(){
return array(
'accessControl', // perform access control for CRUD operations
'projectContext + create',//check to ensure valid project context
);
}
My question is this: If a filter only applies to a single action in the controller, why not just put the filterProjectContext() code directly into the actionCreate() function?
According the yii docs, and my experience with other frameworks, filters are not meant to be coupled with actions. Rather, filters allow you the ability to access PHP globals such as $_REQUEST values before they reach any actions. For example, I worked on a project where we wanted to highlight all translated text if a url parameter was passed with a specific value. We could have done this in the controller but felt it was better to implement the business rule within a filter. The filter ended up looking like:
// Symfony code, but should demonstrate the idea
if ($context->getRequest()->getParameter('highlightTranslations') === 'y') {
// Tell translator API to highlight any subsequent translations
}
The beauty of the filter is that this code would be executed regardless of which action was requested. My suggestion is that you don't co-mingle filter logic with action logic.
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
I've noticed many sites are able to use a username or page title as an action. How is this done?
For example instead of www.example.com/users/my_username (where the users action is generic and responsible for fetching user data) how could I make this www.example.com/my_username?
Thanks very much.
All modern frameworks follow router ideology. So for this task you just need to write yet another route.
How to do this - is a specific task for particular framework.
In CodeIgniter it would be a route like zerkms said. You can define routs in /system/application/config/routes.php. Here's the CodeIgniter documentation on URI routing. Essentially you take the part of the URL (such as the username) specified in your route as a variable and can do a lookup against your db with it.
With mod_rewrite you could write a rule that redirects www.example.com/user/my_username (or without the user) to www.example.com/user/?name=my_username.