I am working on the php side and my friend is working on the iPhone side. We are creating an app with friends and groups. I was wondering if it was better to use separate files for each task such as create group, delete group, add friend, remove friend or is it better to use one update class that calls the necessary function.
I can see two methods and personally I'd pick the first one because it allows me to be the most flexible, but of course the decision is yours to make.
Get/Post to one file
You have one connector file that your objective-c application posts on, and then that connector file contacts your other files.
An example of this flow might looks like:
iPhone (POST request) {'method':'addGroup', 'groupName':'My Group'} -> connector.php
Then connector.php will contact groups.php and run the method addGroup.
For addGroup, you could have it use GET instead, such as connector.php?method=addGroup&addGroup=My%20Group.
Of course, authentication should always be with POST, so you'll have to use POST for that and for more complex or larger amounts of data.
Get/Post to multiple files
This could be a viable option too. In your document root, you would simply have all the file exposed such as:
/htdocs
/addGroup.php
/removeGroup.php
/editGroup.php
/login.php
/logout.php
Then your iPhone app will contact each one of these end points.
In conclusion I'd prefer the first method simply because you are left with only one end point, this allow you to control which methods are available for the user to run.
So first thing first, the organization you want is really dependent on the organization you need. Everyone organizes things based on what they are comfortable with, so the question itself is a bit subjective. (Not to mention there are several ways you can go about this, again, all depending on your organization.)
One method is to put all your CRUD (CReate - Update - Delete) operations for individual domain objects (friends and groups in this case) in single files. So in this case you might have files called create.php, update.php, delete.php and they might look something like:
<?php
class Update
{
public function updateUser()
{
//code to update a user
}
public function updateGroup() { ... }
}
?>
Your other classes would look similar.
You would then create a mechanism for deciding which type of object to run the update operation on, likely through parameters passed in your GET or POST variables.
Another way (and the method I would lean towards), would be to add your operations directly in with the domain objects. Like so:
<?php
class User
{
public function updateUser()
{
//update the user
}
public function deleteUser()
{
//delete the user
}
....
}
?>
Hope that helps clarify some. Again, this is a fairly subjective question, so it really depends on your coding and organizational preferences.
Related
I'm building an application in a classic CI mvc setup where the user has a general/generic tasklist.
The main purpose of a task is to indicate the user that he has to complete a specific action and will redirect him to the page where he needs to complete this action.
In a very simplistic way the db scheme of the task looks like this:
The tasklist it self will be somewhat of a list which redirects the user:
My problem is when the user is redirected to the specific page on which the action needs to occur we lose the context of the specific task. So even if the task is completed (in this example for instance the document is uploaded) the task itself doesn't know that and we don't really have a connection to update the task.
After some research the Observer design pattern looks like the one that can handle this need. But through all the examples I fail to make a click on how to actually implement this into our current system.
In a controller handling the upload of the document is the function upload_doc(){} which when is succesfully executed should also update the task that is connected or subscribed to this document upload.
class Dashboard extends MY_Controller{
public function __construct()
{
parent::__construct();
// Force SSL
$this->force_ssl();
}
public function upload_doc(){
//Handle doc upload and update task
}
}
Can anyone help me in a noobfriendly way how I can achieve this setup within the CI framework?
Thanks in advance!
If it comes to design patterns I always try to find a referencing documentation/github repo with design pattern examples for the requested language. For PHP I can warmly recommend this one here:
https://designpatternsphp.readthedocs.io/en/latest/Behavioral/Observer/README.html
An example implementation could look like this. Attention: I have no experience with CodeIgniter. This is just a way to illustrate how you could implement this with the given code example.
class Dashboard extends MY_Controller
{
private function makeFile()
{
// I would put this method into a file factory within your container.
// This allows you to extend on a per module-basis.
$file = new File();
$file->attach(new UpdateTask);
$file->attach(new DeleteFileFromTempStorage);
$file->attach(new IncrementStorageSize);
$file->attach(new AddCustomerNotification);
return $file;
}
public function upload_doc()
{
// My expectation is that you have some task-id reference
// when uploading a file. This would allow all observers
// to "find" the right task to update.
$file = $this->newFile();
// enhance your file model with your request parameters
$file->fill($params);
// save your file. Either your model has this functionality already
// or you have a separated repository which handles this for you.
$fileRepo->persist($file);
// Finally notify your observers
$file->notify();
}
}
Hope this helps.
If I understand your problem & intentions right (to set a relation between a record created in one place & some action, happening elsewhere), then Observer (if we're referring to the same idea from the same book) won't solve it, it is not even applicable here because of PHP & the generic stateless nature of web, i.e. execution spanning across multiple program invocations. The classic patterns from the GoF book are designed and intended for a single execution within a single program.
You'd need to wire you custom logic which would bind together a task record and user's actions that follow. The simplest approach would be to add a cookie to the user's browser with a task ID so that ID would be accessible to the document upload controller and it would update the rest of the system. And there you can make use of the classic Observer, pretty much as per Christoph's answer or any other example on the internet.
I am creating a web application where users can submit different types of content. Currently, processing the content and saving it is done by something like a ContentService which further delegates tasks to a ContentMapper (for the DataMapper pattern) etc.
As the application is growing, there needs to be other tasks involved with a submission of a ContentObject. For instance, there needs to be calls to a PermissionService (to determine which users are allowed to view the content), as well as a NotificationService (to determine how the users are notified about a new content).
Should I put these auxiliary service (Permission/Notification) calls in the controller or in the service for the goal of creating structured code?
Ie, do I do this:
ContentService->createNewContent()
// in ContentService
public function createNewContent($contentObject) {
// Database calls and other stuff, validation..
PermissionService->determinePermissionsForContent($contentObject)
NotificationService->notifyUsers($contentObject)
}
or do I put these things (since they are more separate and I'm trying to abide by SRP) into the controller?
ie
// in ContentController
$contentObject = // something creates the contentObject from user-data
ContentService->saveNewContent($contentObject)
PermissionService->determinePermissionsForContent($contentObject)
NotificationService->notifyUsers($contentObject)
I'm mainly confused because the auxiliary services are essentially run only when the content is saved and they might require certain data (ie the database id) that's why I'm thinking about them in the ContentService.
On the other hand, if I put them inthe controller, this seems to adhere more to SRP since then ContentService is not doing too many things.
Which is preferred?
The second approach would definitely not make it more-SRP-adherent, since you would need that something to create your contentObject (which you tried to gloss over).
Note: I am not entirely sold on the notion of having a PermissionService since permissions are part of the content's "meta-data".
My approach should be to have two services called from the controller:
public function postContent($request)
{
$contentParams = [
'title' => $request->getParam('foo'),
'text' => $request->getParam('bar'),
];
$library->addEntry($contentParams);
$notifier->sendUpdates();
}
.. where first call creates that new content and the second one checks for the newest additions ans sends out the notifications. And there is no point in dragging that $contentObject everywhere, since both of them should be interacting with a shared repository.
Bottom line is this: your second approach is better, but there is no point in that dangling content object. It looks more to me like you have not figured out how to let your services to share the domain objects.
I run an arcade site and over the past few years it's had many features added, it's got to the point where procedural programming just looks way too complicated and adding new features or making simple design modifications can be very tricky.
Therefore I've decided to try and recode the site from the ground up with the same features but in an OOP format.
The issue I have is picking the classes, I understand OOP and how it should work but always seem to have trouble getting started. I am unsure whether I should be trying to make functions for classes such as a user class with log in user function or if the user class should just be to add/update/show user details and the log in part would be better in a system class?
At the moment I've started with the following class and functions but do they fit in this category?
<?
class User {
var $userId,
$username,
$userRole,
$userEmail;
function isLoggedIn(){
}
function login($postusername, $postpassword)
{
}
function increaseLoginCount(){
}
function logout(){
}
}
?>
I could then have something like the following in a page.php .. (connect class not shown)
<?
$db = new Connect;
$db->connect();
$user = new User;
if(!$user->isLoggedIn())
{
echo "Please Log In.";
if($_POST['user'])
{
$user->login($_POST['username'], $_POST['password']);
}
}
else
{
if($_POST['logout'])
{
$user->logout();
exit;
}
echo $user->username." Logged In.<br />";
}
?>
But then the site would have pages to show game categories and I don't know where the displayGames() function would fit as it's not a single game so wouldn't go in the 'Game' class?
I've tried to find 'real world' examples but php code showing me how to make an elephant change colour or dance doesn't really help ...
Let's start with some textual analysis, highlights by me:
I run an arcade site and over the past few years
Think about how much you are able to cope with and what you are dealing with. Also understand that over the years you have gained specific knowledge about running arcade site. You have gained profession in your area. Never underestimate your own position and assets, it's the base you're operating from and you will introduce changes to. This includes your site's userbase.
it's had many features added, it's got to the point where procedural programming just looks way too complicated and adding new features or making simple design modifications can be very tricky.
If systems grow, they become more and more complicated. That's not specific to procedural programming only, it's a matter of fact. As you're running the site now for many years, you know how things changed, especially in the area how the user interfaces with your site.
Therefore I've decided to try and recode the site from the ground up with the same features but in an OOP format.
It's said that it could be possible to use OOP techniques to make re-useable software, there is (and can not be) any proof of this.
But there are only very few examples in commercial software development where re-writing the whole application from scratch was a success. Very few. The rules of commercial software development might not apply in your specific case, so just saying.
Think twice before you recode the site. Doing a lot of work only to achieve the same is somewhat fruitless and can be disappointing. Instead probably look more specifically which of your current design is introducing the biggest problem you would love to change.
It is possible with PHP to mix procedural and object-oriented style, which can be especially useful when you have legacy code (a common definition of legacy code is code w/o automated tests).
The issue I have is picking the classes,
I try to rephrase that: For what write classes for?
I understand OOP and how it should work but always seem to have trouble getting started.
The beginning is always the hardest step. You're in the position ready to make decisions now, but you can't look into the future. Reduce the risk by eliminating the most risky part. You've probably started to ask a question here to gain some feedback to base your decisions on, but that will probably not reduce the burden and might lead to confusion. However, getting educated is most often a good thing.
I am unsure whether I should be trying to make functions for classes such as a user class with log in user function or if the user class should just be to add/update/show user details and the log in part would be better in a system class?
That highly depends on the nature of your application and the nature of the user. Probably the most of your script only need to know if a user is concrete or anonymous (an anonymous user has not logged in), it's ID, name or nickname.
The application should provide that user to any consuming component, so each command/script does not need to deal with a) obtaining users information and handling users (like logging in), b) verifying if the component is valid for the user (access control). That should be placed somewhere else, e.g. in the application controllerPofEAA.
Each of your scripts/commands that has the application controller object, can ask for the user and just interact with the user.
However this is just technically speaking. Deal with the fact of yourself being unsure, work with that information. Try to better formulate your concrete problem, list pros and cons for a specific way of solving it, get away from concrete code again before starting to code. Then compare pros and cons. Try to make things more simple and less complicated.
Probably write down in simple words what should be happening instead of writing code.
At the moment I've started with the following class and functions but do they fit in this category**?**
Your code is quite bare, so it's hard to say much about it - especially as I don't know what your arcade site is (and what the category is you write about). It's still good for an example probably. What can be seen in your classes is that you tightly integrate everything with each other.
For example you start with the DB. That's common, because the DB is a central component for any application. The application needs the DB to operate on. However you want to keep things loosely coupled so that all your commands can be run with some other DB or a new user object that is connected with some even other DB than the rest of your application's data objects.
$application->getDB();
As the user is such a central subject in each application, it should have a very simple interface. All the glory details about authentication, retrieving of the users properties etc. should be delegated into another class/component, so that you can change the implementation where users are stored and how they authenticate:
/**
* #package command.modules.games
*/
function ListGamesCommand(Request $request, Response $response)
{
$application = $request->getApplication();
$user = $application->getSession()->getUser();
$games = $application->getModels()->build('games');
$games = $games->findByUser($user);
$response->setProp('games', $games);
}
As this example shows, you can add the functionality when you need it. E.g. as long as your application does not need to actually log in users, why care about how it's written now?
Create a factory that is producing the user for the application object - whatever it will need now or in the future (see the Two Piles of Objects in The Clean Code Talks — Inheritance, Polymorphism, & Testing). If you then need the authentication, either add it to the session object or the user object interface.
The authentication itself would be implemented in a class of it's own anyway, the Authenticator. So you can review your interfaces later on as well, by moving the invocation of authentication from session to user or whatever. Only a fraction of your commands will need to deal with these specific task and as all new code is under automatic tests as you want to rewrite and benefit from OOP, you have ensured that all the places are covered and properly re-factored.
Same is true for accessing request variables. If you want to make use of the benefits of OOP - which is highly connected with indirection (and each layer of indirection comes with a price) - you should first of all make your base classes operate on specific data and not on any data (like globals and superglobals, I've seen $_POST in your example code).
So enable your new code to operate on a request and deliver a response (Input - Processing - Output):
$request = new Request($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV);
$response = new Response;
Example taken from the BankAccount - Sample application used for PHPUnit training
Now everything below this can operate on a Request and a Response object - process input and turn it into output. The domain command (your scripts/commands that do the thing) do not need to care any longer about extracting input from the HTTP request like using $_POST or $_GET they can take it directly from the Request - or if you write a class of commands of it's own - this can be even more tailored. And some commands can operate on requests and responses of their own.
The next big topic is the user-interface. You write you want to:
I've decided to try and recode the site from the ground up with the same features but in an OOP format.
I already wrote that such a doing can be fruitless. To have a benefit of OOP code would mean that the next time you change your code, you're still able to re-use components. As software changes constantly, this time now is already the next time. So you want to already re-use existing code. I assume one part of your existing code is the output logic. So the existing output logic needs to interface with the exemplary Request and Response above.
I bet you love websites. You love to make them just work and look great. You've build your site over the years and even not everything is like you wish it to be, you don't want to drop it. So it's crucial for your re-write that you don't destroy everything but you can preserve it's working form from now to the future (See as well Preserve a Working Application; last point of the list).
In webapps the view is such a crucial part. If you loose the view, your site will loose it's identity. If you change too much of it, your site will loose users that are comfortable with using it today.
If you break it,
will you even notice?
can you fix it?
On the other hand you want your application code (the features, the functionality) to not be that tightly bound to it any longer to have a benefit in rewriting your code. As you want to rewrite your application, let's take a look:
.---------. .-------------.
| website | ---> [interface in ] ---> | application |
| user | <--- [interface out] <--- | |
`---------´ `-------------´
As this schema shows, to make your application more independent to whatever the interaction looks like (can be a website, a (smartphone) GUI or the ticketing system), the application code should be replace-able. You don't want to code the logic to obtain a users games for example for every type of user-interface in the new application code, but you did in the old application code.
Taking the User object as an example here. How it authenticates and where it is stored shouldn't be something your new application commands code are concerned about. It's just there if the command needs it. Not globally but specifically if the command asks for it.
Where-as the registration and lost password procedures are part of your existing application and continue to exist.
Now you need to bring the old and the new code together.
So you will probably start with an interface for HTTP requests and a HTTP response. The view kicks in with that Interface Out. You assign/pass all needed data for the view via that interface, your application does not know the view any longer. You don't deal with any CSS, Javascript or HTML code within your new application code. That's just the sugar on top for the output. Your application should interface as well via console/telnet in plain text or as a remote XMLRPC service, AJAX endpoint - whatever.
So you can probably just generalize your view code and inject variables to it. To write a view layer could be as simple as including a PHP file. It operates on variables that are available within it's scope. It can make use of "helper" functions (template macros) that are available in it's scope. It can make use of view model objects. It's even possible to write your own language for the view (templating language, a Domain Specific Language (DSL)).
But this is only possible if you create an interface that allows the application code to do so.
So what you now do is to move away the HTTP/HTML/CSS/JS from your application into an adapter of it's own. That adapter is able to formulate the generic command that can be passed to any application via interface in.
The application will only take care to execute the command and deliver it's response via interface out. So you have two domains now: Your application and the website.
You can start to create these two new domains and then offer an interface in and out for your legacy code and one for your new code.
You also have "two" applications next to each other. They are finally bound together (invisible in their own code) with your database which takes care that the data of your site is in order. And that's what the database is for. Separate the data from your code, so you can change your code over time.
Also if you want to re-code, draw a border between the existing code and the new code.
Good luck! And I hope reading this will show you some options for your specific case. Also take note that you don't turn your controllers into just another facade to the database. Probably you've got the best benefits (don't know your concrete biggest problem) by using a lightweight HTTP abstraction and a view layer only as it might be that your application is for websites only.
Because as in HTTP / PHP:
[Interface In] Plain Text HTTP request
[Application] Free to go
[Interface Out] Plain Text HTTP response
You normally need only some functionality to parse the input and build the output.
Additionally not using fat models has the benefit that you access your data quickly and sequentially, e.g. if you don't need to pass the output at once (buffered, one-block), you can make of the benefit to stream the output to the server.
You should decide which parts are important to refactor for your application, not OOP or not. Like procedural, OOP needs to be done well as well. If you today run into problems by writing procedural code, OOP code might not the answer to your problem. The need to write better procedural code might be it. Just saying, it's not easy to refactor an application and you should identify the actual problem first.
If you break it, will you even notice?
If you break it, can you fix it?
The crucial part is that you can notice and that you have everything at hand to do the fix.
Get your website under test, so you can say if changing code here or there is actually doing good. Be able to turn any change back if it comes to light it's not working (better).
That done you can easily decide about a new feature or not. As long as you don't need to introduce new features, there is no need to change anything in how you write features. And until there, you can't plan for the new features.
So better think twice before re-writing your application. As written, this can kill the project.
See as well: How to implement MVC style on my PHP/SQL/HTML/CSS code?SO Q&A
OOP is all about identifying areas of responsibility and constructing self-contained units of code intended to handle one, and only one, of those areas. A general rule of thumb is that each object in your system should embody an equivalent object or concept in the real world but that's not always true as you need to also worry about abstract things that are needed to make your system work (I mean abstract here in the sense that they don't represent an item of business logic, but are still needed to make the system work. I don't mean abstract classes, which is something else altogether).
For example, in your gaming site, you're probably going to have to deal with Games, Users, Moderators, Accounts, Reviews, Comments and so on. Each of these should be a class in its own right, and every instance of that class should represent a particular User, Game, Comment and so on.
But classes have areas of responsibility, and a stated above, a class should deal with its area of responsibility and nothing else. Rendering a page is not the responsibility of any of the object classes mentioned above. This is where the classes that don't represent the entities of your system come in. You'll probably need a class for a Page, a class for a Session, a class for database connections (though PHP has you covered there already with PDO and some of the other DB modules such as mysqli).
To render a page you'd use an instance of a page class. You'd pass it a reference to the logged in user object, references to any game objects you'd want it to display, and so on. Then you'd have it render the actual HTML. The Page class doesn't need to know anything about the inner workings of the objects you pass it, other than about the APIs that those objects expose (known in OOP circles as the object's protocol, in otherwords their public methods and properties). A (very basic) Page class might look like this:
class Page
{
private $user = NULL;
private $games = array ();
public function setUser (User $user)
{
$this -> user = $user;
}
public function getUser ()
{
return ($this -> user);
}
public function addGame (Game $game)
{
$this -> games [] = $game;
}
public function getGames ()
{
return ($this -> games);
}
public function generate ()
{
$user = $this -> getUser ();
$games = $this -> getGames ();
$pageFile = '/path/to/a/php/script/representing/the/page/markup.php';
require ($pageFile);
}
public function __construct (User $user, array $games)
{
$this -> setUser ($user);
foreach ($games as $game)
{
$this -> addGame ($game);
}
}
}
The actual markup.php script would probably look something like this:
<html>
<head>
<title>Games page for <?php echo ($this -> user -> getName ()); ?>
</head>
<body>
<p>Hello, <?php echo ($this -> user -> getName ()), here are your games.</p>
<?php if (count ($this -> games)) { ?>
<ul>
<?php foreach ($this -> games as $game) { ?>
<li><?php echo ($game -> getName ()); ?>: your best score is <?php echo ($game -> getHighScore ($this -> user)); ?></li>
<?php } ?>
</ul>
<?php } ?>
</body>
</html>
As you might have noticed, if you use this approach then your application's modules will tend to fall into one of three categories. Your business logic objects like User and Game, your display logic like the markup.php file, and the third group that serves as a form of glue logic and coordination like the Page class.
Whilst in this particular case it's specific to your site, if you were to generalize this approach further it would fall into a design pattern known as MVC, which stands for Model, View, Controller (well actually it's closer to a pattern called PAC for Presentation, Abstraction, Controller, but it's almost always called MVC in the PHP community for some reason, so we'll just say MVC for now). A pattern is a generalization of a class of problems that programmers run into on a regular enough basis that having a toolkit of pre-made solutions is handy.
In the case of your gaming application, User and Game are models, Page is a controller, and markup.php is a view. If you substitute a different markup.php script into this code you can use it to present the exact same data in a completely different way, say as an XML file for example. You could also use the same models with a different controller to get them to do different things. The important thing to keep in mind here is that models should not concern themselves with how they are being used, that way they can be used in different ways depending on what the controller needs to achieve.
As MVC is a pattern, there are already toolkits that exist to build MVC (though they aren't really MVC ;) ) applications in PHP. These are called frameworks. There are plenty to choose from out there, such as Symfony, CodeIgnitor, Zend Framework and so on. The most popular framework these days is Zend, though I'm not personally a fan of it. (I would say that the beta versions of Zend Framework 2 do look a lot better than the current version of the framework though).
I hope this has been helpful for you. I know OOP can be daunting at first. It does require you to change your way of thinking as a programmer, but don't worry, it will come with enough practice.
All the members in the user class look like they belong there. It's important to separate the gui code from other code, I'd put displayGames() in some sort of gui class.
GordonM's post is a good one to get you started. I would certainly recommend using an established framework to get you started - they do a lot of the heavy lifting for you and will help you get used to OOP within PHP. Personally, if you're using PHP5.3 I'd recommend Symfomy2 but that's purely a personal preference. What I would also suggest is you get hold of a copy of the "Gang of Four" book. It's pretty much essential reading and although it comes mainly from a non-request-driven-environment background many of the patterns are still relevant in PHP.
My question is simple but (I guess) hard to answer:
Do I really need a complete Model-View-Controller design pattern in my PHP Website / Web-App?
I can't understand how a Controller could be useful with PHP since every PHP site is generated dynamically on every request. So after a site is generated by PHP, there is no way to let the View (the generated HTML site in the Browser) interact with the controller, since the Controller is on the server side and generated once for each site request, even if the request is AJAX...
Do I understand something completely wrong?
Why should I use any kind of MVC PHP Framework like Zend or Symphony?
EDIT:
For example lets assume, there should be a website to represent a list of customers in a table:
My Model would be a simple Class Customer on the server side that queries the database.
My View would be the generated HTML code that displays the Model (list of Customers).
And the controller? Is the controller only evaluating the GET or POST to call the correct method of the model?
Do I have understand something completely wrong?
Yes.
The MVC pattern is not for the browser. The browser sees HTML anyways. Whether this HTML is generated with C++, PHP, Java or whatever it doesn't matter. The browser doesn't care what design patterns were used to generate this HTML.
MVC is a design pattern to organize and separate responsibilities in your code. So it's not for the browser, it's for the developers writing the code. It's to create more maintainable code where you have a clear separation between your business logic (Model), the communication between the model and the view (Controller) and the UI (View).
Whether you should use the MVC pattern in your web site is a subjective question that I prefer not to answer as it will depend on many factors.
Short Answer
Yes. A controller will be responsible for preparing data to display for rendering and sometimes handle GET and POST requests that originating from your client. It should leave HTML generation to the view.
Long Answer
MVC can be very helpful in keeping applications maintainable and your code base sane. The pattern helps ensure separation of concerns of your code and in most cases will steer yor clear of 'spaghetti php' where your application logic is tangled with the HTML generation. A sample MVC setup below (there are sure to be many variations of this, but it gives you the idea):
Model
Responsible for fetching data from the database and saving changes when requested. One example might be a php object that represents a user with name and email fields.
Controller
Responsible for massaging and manipulating data and preparing it for display. The prepared data is passed to a view for rendering, with the view only needing to be aware of just the data it needs to render. For example: a controller may look at a query string to determine what item to fetch to render and combine this with several additional model queries to get additional data.
Often controllers will also be responsible for handling GET and POST requests that originate from your HTML client and applying some sort of manipulation back on your database. For example - handling form submits or AJAX requests for additional data.
View
The view is responsible for actually generating the HTML for display. In PHP, a view would often be a template file with minimal logic. For example, it might know how to loop over items provided to it from the controller or have some basic conditionals.
Application MVC vs PHP/Python/etc. MVC
From your other comments it sounds like you are familiar with using MVC in the context of a desktop or mobile application.
One of the main differences between MVC in the two is the granularity at which the controller is manipulating the view and responding to events.
For example, in a traditional application the controller might listen for click events originating from a button and respond appropriately.
When your doing server side html generation however, your controller is only 'alive' for a brief moment while its preparing html to ship out over the wire. This means that it can only do so much to setup and prepare the view for display.
Instead of listening traditional events from the UI, it can instead react in different ways to future GET and POST requests. For example, you may have a "save" button on a form trigger a POST request to your server (such as yourpage.php?action=save&value=blah). While handling this request your controller might access your models and apply changes, etc.
I realise that I am answering a very old questions, however, I do not believe that any other question has answered your initial concern appropriately, and this will hopefully add something useful for others who may stumble across this question in their learning about MVC.
Firstly, I will start by saying I read an interesting article about the confusion which exists within the PHP community about MVC and it is worth a read if you are asking this type of question.
Model-View-Confusion part 1: The View gets its own data from the Model
Secondly, I do not believe you have misunderstood anything at all, rather you have a better understanding of PHP and MVC which is allowing you to ask the question. Just because something has been defined and accepted by the community at large, it does not mean you should't question its use from time to time. And here is why.
There is NO memory between requests (except for SESSION state) within a PHP application. Every time a request is received the entire application fires up, processes the request and then shuts down i.e. there are no background application threads left running in the background (at least none which you can use within your application) where you could, theoretically, maintain application state. This is neither good, nor bad, it is just the way it is.
Understanding this, you can probably start to see what you are thinking is correct. Why would a View (which is allowed to access its own data from the Model) need a Controller? The simple answer, is that it doesn't. So for the pure display of a Model, the View is perfectly entitled to fetch its own data (via the Model) and it is actually the correct way to implement MVC.
But wait. Does this mean we don't need Controllers? Absolutely NOT! What we need to do is use a Controller for its appropriate purpose. In MVC, the Controller is responsible for interpreting user requests and asking the Model to change itself to meet the users request, following this, the Model can notify it's dependencies of the change and the View can update itself. Obviously, as you know, in the context of a PHP web application, the View is not just sitting and waiting for update notifications. So how can you achieve the notification?
This is where I believe MVC got hijacked. To notify the View it's Model has changed, we can simply direct them to the URL of the View which accesses the now updated Model. Great, but now we have introduced something into the Controller. Something which says, "Hey, I'm a controller but now I have knowledge of the location of the View." I think at this point, someone thought, "why do I bother redirecting the user? I have all the data which the View needs why don't I just send the data directly to the View?" and bang! Here we are.
So let's recap.
A View CAN access the Model directly within MVC
The Model houses the business logic for the Domain Objects
A Controller is not meant to provide the View access to the Model or act as any type of mediator
The Controller accepts user requests and makes changes to it's Model
A View is not the UI/HTML, that is where a Template is used
A practical example
To explain what I have been describing, we shall look at a simple, commonly found function within most websites today. Viewing the information of a single logged in user. We will leave many things out of our code here in order to demonstrate just the structure of the MVC approach.
Firstly lets assume we have a system where when we make a GET request for /user/51 it is mapped to our UserView with the appropriate dependencies being injected.
Lets define our classes.
// UserModel.php
class UserModel {
private $db;
public function __construct(DB $db) {
$this->db = $db;
}
public function findById($id) {
return $this->db->findById("user", $id);
}
}
// UserView.php
class UserView {
private $model;
private $template;
private $userId;
public function __construct(UserModel $model, Template $template) {
$this->model = $model;
$this->template = $template;
}
public function setUserId($userId) {
$this->userId = $userId;
}
public function render() {
$this->template->provide("user", $this->model->findById($this->userId));
return $this->template->render();
}
}
And that's it! You do not require the Controller at all. If however you need to make changes to the Model, you would do so via a Controller. This is MVC.
Disclaimer
I do not advocate that this approach is correct and any approach taken by any developer at any point in time is wrong. I strongly believe that the architecture of any system should reflect its needs and not any one particular style or approach where necessary. All I am trying to explain is that within MVC, a View is actually allowed to directly access it's own data, and the purpose of a Controller is not to mediate between View and Model, rather it is intended to accept user requests which require manipulation of a particular Model and to request the Model to perform such operations.
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.