PHP framework URL conventions - php

A lot of frameworks use URL conventions like /controller/action/{id} which is great, but if you need any configuration beyond that, it's up to you to write your own routes.
How would you handle URLs like /users/{id}/friends on the backend? (to list all of a user's friends)
I'm thinking that in the controller, something like this would be appropriate:
class User {
function index() {
echo 'user index';
}
}
class Friend extends User {
function index($user_id) {
echo 'friend index';
}
}
Then you would have the following map:
/users -> User::index()
/users/{id} -> User::view($id)
/users/{id}/friends -> Friend::index($user_id)
I wanted to put the Friend class inside the User class but apparently you can't do that in PHP so this is the best I could come up with. Thoughts?
What URL would use for editing your list of friends? /users/{id}/friends/edit could work, but it doesn't seem appropriate, since you should never be editing someone else's friend list. Would /account/friends/edit be a better choice? Where would you put the corresponding code for that? In a friend controller, or a user controller, or a specialized account controller?
Bonus question: which do you prefer? /photos/delete/{id} or /photos/{id}/delete
The answers:
So, what I've gathered from the answers is that if the "thing" is complicated (like "friends") but doesn't have its own controller, you can give it one without a model, or if it's not, you should stuff it in with whatever it's most closely related to. Your URLs should not influence where you put your code. Most people seem to think you should stick to /controller/action/{id} whever possible, because it's what people are familiar with.
No one really commented on the extended class aside from saying it's "awkward". Perhaps FriendList would have been a more appropriate class in that case if I really wanted to separate it out.
Thanks for all the answers :)

The routes you're talking about, and the way you're using subclasses to achieve this structure, seems a bit awkward to me. The standard convention of /controller/action/{id} works great for simple actions, but if you're creating a complex application you will always need to create custom routes. There are probably some good guidelines to use when creating these routes, but it really boils down to staying consistent across your application and keeping things as simple as possible.
I don't see any good reason to have /user/{id}/friends mapping to a "Friend" controller. Why not just have "friends" be an action on the User controller? Once you actually drill down to view a specific friend's page, you could use a Friend controller (/friends/view/123) or you could repurpose your User controller so that it works for a friend or the currently logged in user (/user/view/123).
Re: the bonus question, I'd stick with /photos/delete/{id} (/controller/action/{id}) as that's the most widely accepted mechanism.

I would prefer /photos/{id}/delete. My reasoning is that if you take one component off the end of an URL, it should still make sense.
It's pretty easy to assume what /photos/{id} should do: view the set of photos for that {id}.
But what should /photos/delete do? That's really unclear.
I know that there's kind of a default convention of /controller/action/id, but that organization is for the sake of mapping to the class/method architecture of controllers. I don't think it's a good idea to organize the UI to accommodate the code (the URL is in a way part of the UI).
Re comments: Yes, /photos/{id} maybe makes more sense to view a given photo by its id. /users/{id}/photos perhaps to view a collection. It's up to you.
The point is that you should think of the UI in terms of users, not in terms of code organization.

You can do either or. The problem is when you mix the two. /users/{id}/friends and /users/friends/{id} When someone has the id of "friends" this will fail. This may seem like a trivial case but it's very popular to use usernames for ids. You will have to limit user names for every action.
Sometimes you can't do /{controller}/{action}/{id}
I did a indie music site a while back and we did
/artist/{username}
/artist/{username}/albums
/artist/{username}/albums/{album}
We didn't want to test for conditionals so we didn't do
/artist/{username}/{album}
Since we didn't want to check for anyone with an album named "albums"
We could have done it
/artist/{username}
/artist/{username}/albums
/albums/{album}
but then we would lose the SEO advantage of having both the artist name and the album name in the URL. Also in this case we would be forcing album names to be unique which would be bad since it's common for artist to have album names the same as other artist.
You could do pure /{controller}/{action}/{id} but then you would lose some SEO and you can't do URL shortening.
/artist/view/{username}
/artist/albums/{username}
/album/view/{album}
Getting back to your example.
/users/{id}/friends/edit could work,
but it doesn't seem appropriate, since
you should never be editing someone
else's friend list.
In this case it should be /friends/edit since your user id is duplicate information assuming your in a session somehow. In general you want to support URL shortening not URL expansion.
(Bonus question)
Neither, i'd use REST. DELETE /photo?id={id}

It also depends on how you are storing your data. I could imagine in some cases you need a 'friend-list' to be a entity in your model. A logical approach would then be to specify a unique identifier for each friend-list, a primary key.
This would logically result in the following route, as you only need a primary key of the friend-list to edit or delete it...
/friends/edit/{friendListId}
It's up to you to decide. As pix0r stated: convention for small applications is /{controller}/{action}/{id} where {id} should be optional to match with most of your websites actions. In some cases applications get big and you want to define specific routes with more than 3 elements. In some cases certain entities just get a bigger meaning (above example) and you could decide to define a custom controller for it (which makes the default route perfect again...).
I'd stick with the default route /controller/action/id but just don't start making controllers for everything (like friends) in the beginning. The Model-View-Controller pattern makes it very easy for you to change routes later on, as long as all your route-links and actions (forms etc.) are generated based on routes and actions. So you don't really have to bother that much :)

The URLs themselves don't really matter too much. What is more important is what goes in each of your controllers. In your example you had your friend list extend the User class. If your list of friends is really just a list of users, maybe it should extend the Users controller so that you deal with lists of users in one place.
class Users {
public function index() {
$users = $this->findUsers();
}
protected function findUsers($userId=null) { ... }
}
class Friends extends Users {
public function index($userId) {
$users = $this->findUsers($userId);
}
}
If you have a hard time figuring out which class to extend write out what you need from each of the classes and pick the one with the longest list.

Related

Where is the best place to put application-wide logic (notifications) in CakePHP?

I've had a quick search on Stackoverflow but not really found an answer to a question that I have. Sorry if it's already been answered and I've missed it!
I'm working on an application, and similarly to Facebook, there will be 'notifications' but in my case it'll be items that require actions from the user. It would just be a 'count' of the actions that are required and nothing else.
I've followed a fat model, skinny controller approach through my application and so far so good. I have a good idea of what goes where, and when to use a plugin, app model, app controller, etc.
However, I'm a little confused about where to put this notification/action 'count'. I'm guessing either afterFilter() in the app_controller.php file, but that's just a guess. I'm just looking for the most efficient place to put it.
So, where's the best/fastest/most efficient place to put this count call?
Thanks!
Kingsley
EDIT: I just realised it's worth pointing out that this particular call is on a model. So, at the moment I have to load that model, and then call it.
The ideal place is in an Element. You can then use requestAction() to tell it where to retrieve it's data from.
The Element is placed into a view (or used to display a Flash message). Within it, it pulls it's data (requestAction) from a Controller's Action. That action get's it's data from the Model of your choice just like you would in any other action. This allows complete separation of concerns (ie MVC).

Why is $uses considered bad practice in cakePHP?

I have 3 tables that contain user information, one for students, one for teachers and one for administrators.
They are not related in any way. I wan't to create a dashboard for the Administrators, where a list of students and teachers shows up.
The only way I found to achieve this was using the $uses variable in the Administrators controller. However, I have read in many places that this is bad practice.
Any solutions?
Another, perhaps better practice is the use of ClassRegistry::init('MyModel')->myMethod() (more reading # Cake API)
This only loads the object when it's used, as opposed to loadModel or uses, with ClassRegistry the models are treated as singletons.
--
that you are doing something wrong: you need access to a model that has nothing to do with your current controller.
There are plenty of conditions where you would need to access all of your models data, from one controller, but never a definitive answer on how to do it without breaking convention!
You can always use another Model which is not related by using
$this->loadModel('NewModelName');
Then you can access new loaded model by:
$this->NewModelName->add(); // whatever method model has defined
Why prefer loadModel() over uses?
To gain performance. How? uses calls the loadModel function itself to load all the models you specify in uses array. But the problem is if only one of your action needs a particular model, whats the good thing to include it in every action. e.g. only add() action requires an unrelated model, but if you have specified it in uses array, no matter what action gets called a completely unrelated model is going to load. To put simply it will be inefficient. Its like you have declared variables in a C programme but never used them. In case of C compiler will warn you that you are not using your variables, but unfortunately cake couldn't tell you.
Its alright to use uses if all your actions needs to load that model, use loadModel() otherwise.
You probably didn't read my answer in your other question :))
I have 3 tables that contain user information, one for students, one for teachers and one for administrators. They are not related in any way. I wan't to create a dashboard for the Administrators, where a list of students and teachers shows up.
The problem is you are separating similar data into 3 different tables, in this case, user information. So when you try to manage this data, you hit a brick wall: because you leave out the relationships when you separate them in 3 tables.
The only way I found to achieve this was using the $uses variable in the Administrators controller.
You got the wrong idea about the controller. Each controller manage the data flow of a particular model (and related models). It doesn't mean that you have to stay in Admin controller to do administrative things. What model you want to manipulate decides what controller you need to be in.
However, I have read in many places that this is bad practice.
Now for the main question: using $uses is a red flag that you are doing something wrong: you need access to a model that has nothing to do with your current controller. Now, there're always exceptions in programming, sometimes we need to have access to that model. That's where loadModel comes in. Because it should be rare. If you need the model a lot, then you'll need to call loadModel a lot, which is cumbersome, which is what $uses is for, but then that means something's wrong with your app design :))
So, you can say using $uses is a sign of bad decision (in DB design or application structure); and so is using loadModel a lot.
Edit: Any solutions?
I gave one solution in your other question. But if you want to have them all in one place, you can have 1 users table with user information. Each User can hasOne Student, Teacher, Administrator and a 'group' field to decide what group the User is. The third solution is using $uses. Its performance impact won't be a problem really. But it will be pretty convoluted when you develop your app further. That's what you need to worry about. For example, I can say that, if you use Auth, you'll need to tweak it a fair bit to get it working with 3 models. If you use the users table, it will be a lot easier.

PHP MVC (no framework), should I be calling a lot of methods in my controller or model?

I've been working on creating my own MVC app in PHP and I've seen a lot of differing opinions online about how exactly this should be set up. Sure, I understand there seems to be a general "It's MVC, it is what you make of it" approach, but I'm running into 2 seemingly conflicting viewpoints.
A little background on my app: I'm using smarty as my presenter and an object-oriented approach. Seems simple enough, but I'm trying to figure out the ubiquitous "what is a model" question.
If I take a look at some tutorials and frameworks, they seem to view the model as strictly a class that inherits DAL methods from an abstract class, with a little bit extra defined in the class itself as your data needs differ from object to object. For example, I might see something like $productModel->get(5) that returns an array of 5 products from the database. So what if I need to query multiple models? Do I store all of the data in the controller or an array and pass that to the view? Then if I'm dynamically calling my controller, how can I persist the data unique to the controller necessary to render the view? This seems bad, especially because I then have to pass in things like "controllerName", "controllerData", and my View::render() method gets hugely bloated with parameters, unless I pass in the controller itself. Maybe I'm missing something here.
Let's say I want to make a login that queries a users table. Login is a model or a controller, depending on certain implementations I've seen online. Some implementations (I'll call this method 1) make a LoginController with method login() that might do a comparison of $_POST and what's returned from the user model instance $user->get(1) to see if a user is validated. Or maybe login() might be a method in a default controller. On the flipside, an implementation (implementation method 2) that resembles more of a Joomla approach would make a Login model and declare all of the actions inside of that. Then any data that needs to get assigned to the view would get returned from those methods. So login->login() would actually check post, see if there's a match, etc. Also the User model would probably be instantiated inside that model method.
My feelings about 1: The controller is fat. Additionally the controller is storing data pulled from models or passing in ten thousand variables. It doesn't seem to jibe with the idea that the model should be passing data to the view that the controller should be blind to. Also, let's say I want to wrap everything that is in a specific model handled by a specific controller in an outer template. I'd have to copy this template-setting code all across my controller functions that interface with this model. It seems grossly inefficient.
My feelings about 2: It doesn't make for having actions that aren't model methods. If I want to go to my site root, I have to make an index model or something that seems like overkill in order to have a model that passes data to the view. Also, this doesn't seem to be a very popular approach. However, I do like it more because I can just do View::render(mymodel->func()) and ensure that the data is going to be passed back just the way I like it without having to crap up my controller with code merging a thousand query results together.
I've waded through far too many religious arguments about this and want to know what you guys think.
I've built my own framework in the past too so I know what you're going through. I've heard the saying "build fat models" and I agree with that -- as long as the main goal is to return data. I considered the controller to be "The Overlord" as it manipulated data and directed where it should go.
For a login controller i might create something it like...
Post URI: http://example.com/login/authenticate
LoginController extends ParentController {
public function authenticate() {
$credential_model = $this->getModel('credentials');
// Obviously you should sanitize the $_POST values.
$is_valid = $credential_model->isValid($_POST['user'], $_POST['email']);
$view = $is_valid ? 'login_fail.php' : 'login_success.php';
$data = array();
$data['a'] = $a;
// .. more vars
$this->view->render($view, $data);
}
}
In my opinion data should always flow from the model -> controller -> view as it makes the most sense (data, manipulation, output). The View should only have access to what it has been given by the controller.
As for this...
Then if I'm dynamically calling my controller, how can I persist the data unique to the controller necessary to render the view?
Well I would imagine you're building a 'base' or 'parent' controller that gets extended off of by your dynamically called controllers. Those child controllers can have properties that are needed for for the view to render -- honestly I'd need an example to go further.
Hopefully this helps a bit. If you ask more specific questions I might be able to give a better thought out opinion.
If you're writing your own app, I think the best solution is to do it yourself and find out.
Ultimately, whatever makes the most sense to you, and whatever makes it easier for you to conceptualize your app and quickly add to or change it, is going to be your best option.
If one way is "wrong", then you'll find out through experience, rather than someone else telling you. And you'll know the entire situation that much better, and know EXACTLY why one way is better.
What helped me when I was writing my own framework in PHP was, strangely enough, CherryPy. It made the concept of an object-oriented web app so simple and obvious, and I enjoyed using it so much, that I modeled the basic structure of my PHP framework to imitate CherryPy.
I don't mean to imply you should learn CherryPy. I mean that simplicity, clarity, and enjoying developing with your own web app go a LONG way.
If I were to give one piece of specific advice, I'd say try to avoid retyping code; write your code to be reusable in as many situations as possible. This will not only be good for your app, but for future apps you may write or work on.
You might check out Eric S. Raymond's Rules for Unix Programming. I think they're definitely applicable here.

PHP OOP question

i was just looking for a bit of advice, currently my DB design is that one user has many blog postings. Now i have a user class and a blog class.
However im not sure about the proper way to get all blog posts for that user. Do i create a getAllBlogs() function in the user class which returns blog objects or do i create a main blog class that you can search by user, so it'd be getAllBlogsForUser($id)
Thanks :-)
I'd personally use the later option. This is because the blog class knows how to deal with the blog table(s). I wouldn't want to write blog-specific DB code in the user class. On the other hand, you still can add User::getAllBlogs() as a wrapper around Blog::getAllBlogsForUser().
It's really up to you. Since users are pretty tightly coupled to blogs, you could do both.
Consider how nicely they could play together:
<?PHP
class User {
protected $_blogs;
public function getBlogs($force=false){
if (empty($this->_blogs) || $force){
$this->_blogs = BlogClass::getBlogsByUser($this->user_id);
}
return $this->_blogs;
}
}
Now you can grab a user's blogs whenever you want, and it will fetch them only when necessary. The $force parameter can be used to force a reload.
i am not sure if this is actually a helpful answer .. however if your db design is done correctly with the correct normalization practices in place .. it should be indicative of your class layouts as well. as User is an independent entity, and posts use user_id or something as the foreign key , it should clearly give you the idea who should be the master. Users can exist with-out posts , however posts can not exist with out users. So it makes sense to put the get posts method in the postings class rather than the users class.
I'd use both, like User::getPosts and Posts::findByUserId ("Posts" as model name sounds better to me than "Blogs" ). Both methods have similar functionality and which one to use depends on the context, for example, frontend will rather use Users model, while in admin interface 'finder' methods could be more appropriate.
I would create both. Your User::getBlogs() could use Blogs::getBlogsByUserId($idUser) since when you are in the user context, you will have access to the user's id to pass to the Blogs method.

Best way to organize applications?.... (MVC design pattern)

When building applications, whats the best way to decide what goes where. How do you know what functions to put in what controllers and models. For example, I'm building an application that is based highly on location. Users can post different things, that will in turn be shown to other users within a certain distance. Also, each user will have their own profile page that will show everything posted by that user regardless of location.
So I have models like this
class UserModel extends BaseM{
get_user($uid);
get_all_users();
edit_user($new_data);
delete_user($uid);
add_user($new_user);
get_user_articles($uid);
get_user_reviews($uid);
get_user_foo($uid);
}
class ArticleModel extends BaseM{
get_article($aid);
get_all_articles();
add_article($new_article);
delete_article($aid);
}// similar to ReviewModel, and other models
class LocalModel extends BaseM{
get_local_articles($zip_code, $range);
get_local_reviews($zip_code, $range);
get_local_foo($zip_code, $range);
}// holds all location related functions
As you can see, I lumped everything dealing with a user (needs a userID) in the userModel, everything dealing with location (needs a zip-code) in the localModel, and then everything else has its own model.
I was wondering whats the best way to figure out what goes where, is there like a rule of thumb for this kind of stuff?
Well you're 80% there already. You've got your models broken out and that is a big battle. Next design the app that you want. If you end up with a lots of repetitive "elements" on multiple pages, then each element should be a view. Otherwise each page should be a view. Or some combination of the two.
Once you have you pages defined and you know the data flow of the app, all that remains is the controller.
It may be practical in a small app to have a single controller. Or for really complex apps, you may have multiple controllers - no more than one per "page" though.
Just keep in mind - the Model should be view agnostic (you can retool the UI without impacting the model). The views should be blind to where the data comes from or where it's going - everything gets filtered through the controller.
See my previous answer to a similar question here:
I normally use this approach: try to put it somewhere. if after a while you use it, it feels awkward, then it's not in the right place.
In general every model class should have methods that make sense for itself, and eventually return other models. Refrain from putting too much computational intelligence in your models. If there's something that feels strange in either classes, there's probably a third class in between to be discovered.

Categories