Foreword: The following text is of decent size, because I tried to maximize the value to other readers with similar, fundamental and conceptual questions.
Introduction
Currently I am developing an web-based event management tool, which uses the Laravel MVC framework to maintain a proper application structure and ease development.
The goals targeted with the application are to
provide a efficient way to create (respectively CRUD) events
invite registered users to those events
allow users to confirm their participation on previously created events
Following the MVC-Pattern, I created
a Model named Event
a EventController
multiple views
a static event view, displaying already existing events
a form view for creation and editing named eventForm
eventIndex, a list of all events
Up to this point, everything seemed to be relatively straight-forward, but I ran into design problems, when I tried to implement further functionality to allow users to confirm their participation on specific events.
Further Details
For further clarification, each Event has a number of attributes (some omitted):
Title
Description
Multiple EventDates, consisting out of this attributes:
Title
A timespan (for example 09-20-2013 09:00 AM to 09-20-2013 05:00 PM)
The aforementioned EventDate is also a model with an associated database table.
Distinguished by the account a user is logged in with, I made a boolean variable $admin available to all views and controllers, which is used to alter the view event in the following way:
$admin = true: The view is a static page, showing the Events attributes and EventDates in a table
$admin = false: In addition, the view has a hidden form and buttons for each EventDate table row, allowing the users to confirm or decline their participation on each of the EventDates
Using a variable and #if...#endif-blocks to alter the view seems acceptable to me, as, despite of the hidden form, the differences between User-Mode and Admin-Mode are quite small.
The Problem
Now, the problem I am stuck at, is the following:
Who is responsible for processing the POSTed data of the User-Mode hidden form?
At first, here a few facts to the current development state:
The Event controller currently offers the following functions:
/* CRUD functions */
public function CreateEvent()
public function ShowEvent($id)
public function UpdateEvent($id)
public function DeleteEvent($id)
/* Form display helpers */
public function NewEvent()
public function EditEvent()
The EventDate Model is separate from the Event Model, as a Event has multiple EventDates
Confirmations are stored per user and EventDate in another separate table bound to the EventDateConfirmation model
Solution approaches
These are the options I have thougth of:
The EventController, which must be extended with methods like CreateEventDateConfirmation() and so on, leading to multiple CRUD methods, which not even belong to this controller, as they are not directly regarded to the Event model and no change at all happens in the events table
In a separate EventDateConfirmationController, only responsible for getting and setting the EventDateConfirmation model data, with two usage possibilities:
Calling the EventDateConfirmationControler methods from the EventController by using the somewhat clunky
Controller::resolve(DEFAULT_BUNDLE,'EventDateConfirmationController')->CreateConfirmation($params);
Setting the route which responds to the hidden form POST-request to the corresponding EventDateConfirmationController action directly
The first possibility has the disadvantage of calling an external controller in a unpleasant way which seems wrong to me, the second is not practicable when the form also contains data which belong directly to a event and therefore must be handled by the Event controller
??
In my opinion, neither #1 nor #2 are good solutions to the problem, as they seem to be hack-ish and do not fit very well in the MVC-pattern.
What alternatives are available, which would be a clean solution to this problem?
Thank you in advance!
I think you might be able to do #2 and make it a little less hackish but still not have to change much from before. Otherwise I think #1 is not a good choice.
Realistically what I would do if I were in your circumstance is create the EventDateConfirmationController and in the User-Mode view, make it a separate form that is asynchronous ajax. Either submit the form when the user clicks [assuming] the checkbox that he/she is going, or on when they submit the other form.
I definitely feel like javascript can help you keep your code consistent and still MVC like.
Related
So I've been working on an PHP MVC for a client for about 3 weeks now, I've got pretty far.
I'll explain a small part of the system.
There are three types of users, Fitters, Agencys, and Admins.
these can all log in and have limited functionality, admin obviously has all functionality!
The admin can add, edit and delete users, jobs, stock blah blah the usual.
The way I've set it up so far is like so...
The query string is like: /admin/users/?method=agency&action=add
This will call the admin controller, and call the users function.
The users function will then call the users model.
The users model contains functionality to add, edit, delete, admins, fitter, and agencies.
action=add&method=admin will call add_admin() which will dynamically return a form for admins
action=edit&method=fitter will call edit_fitter() which will dynamically return a form for editting fitters
Now I was wondering...
Would it be better for me to have an ADD class. with ALL the add methods like, add_fitter, add_agency, add_admin, add_job, add_stock etc... and then have a class for EDIT, a class for DELETE, and a class for VIEW ???
Would this be a good way?
I thought that by doing this, I can limit the dependancy on classes like the USERs class.
Because the users class adds, edits, deletes, inserts, updates and views fitters, agencies, and admins. So the user class needs a Validator, a database, a Form class that returns html forms for adding and editting etc etc.
However if i had ONE class for ALL the adding, then it would eradicate the dependancy for a validator? because the add class would be responsible for returning the form. Nothing else
The reason I'm asking this question is because I'm new to MVC. and I dont want to spend the next couple of hours changing all my code, and then realising that theres a problems with my proposed pattern.
So i'm just asking you kind people, can you foresee a problem with this method?
is this how its usually done?
or is this method steered clear of for a reason?
ANY advice or tips will be GREATLY appreciated!
Just to be clear... I'm asking whether I should have separate classes for Add, Edit, Delete and view
Alex
I think the best way is store the access level of the user (session, etc), and render the page according to what was stored in the session. Urls need to be only /admin/users/?action=add
Or
admin/user/edit/?id=27
router/controller/action/?param1=value1
Just if anybody was curious, i did implement my mvc this way and it's much better!
I am trying to program in MVC architecture.
So, I have one HTML form where user can insert, let's say, a movie. I have one controller for that (for adding that movie) and one view for the HTML form.
But I also want user to be able to edit that movie after he added it. So, he presses a button "Edit a movie" and he's redirected to the new URL and I have new controller and new view (it has the same form as when user adds the movie, but only now he sees values in inputs which he entered previously, I hope you understand what I mean) for this editing form.
Also, when I want to show how his movie looks like to other users, I once more time have new Controller and new View for that.
edit: I also have to validate what he enters. So, that validations should be in model? Because I validate twice, it doesn't seem right.
Is it correct thinking of MVC? Or what's the best approach for making this? Thanks.
You got it almost right, but there is still some place to simplify it. Common thing is to create action functions inside of your controller which handle certain (surprise, surprise) actions user can do. Usually you'd have, for example, Article controller with actions add, remove, edit etc. This way you centralize actions for common entity of your application and prevent overflow of controllers. It's easier to maintain, easier to find if you want to change something asap and you will nicely follow DRY principle.
Another thing you could do is to create abstract base controller for common stuff that's used in multiple controllers (dynamic loading of meta data from database comes in mind).
Having multiple views is fine. You don't have much of a choice anyway. But I'd recommend using some templating engine which would make your life easier and once again force you to not repeat yourself. Twig or Smarty would be perfect choice.
Validation logic should be located in model. Model is responsible for most of the backend logic (data manipulation, its validation...). Controllers just take requests, loads appropriate data from Models and point you to proper View. Don't get confused though, you usually end up validating your Models inside Controller (calling validate() functions, for example).
Anyway, in the end, you'll find out there are quite many ways how to look at MVC pattern. Some people prefer "fat models" and "skinny controllers", some the other way around. Use whatever fits your needs and keep it simple!
If you want some studying materials, take a look at Symfony2 framework or CakePHP tutorials. There are some valuable information regarding this topic. Maybe you'll end up using one of them instead of reinventing the wheel :)
No, it is overly complicated.
You do not need different controller for another action you want to make on something. Eg. if you have a controller for creating a movie, you do not need separate controller for editing it. You need separate action, not controller.
Basically you should employ DRY (Don't-Repeat-Yourself) rule for that. If view only differs by the values and form's action, just use one view for both actions (create & edit). View should generate similar code for both actions - one will have no form fields filled, with form's action set to eg. "movies/create" and the second one will have prepopulated form fields with form's action set to eg. "movies/<movie_ID_here>/update" (naming convention is up to you).
Validation should be in model, but as additional help for the users you can validate it also on the client side, using JavaScript or HTML5 (depending what you want), so they do not need to submit the form to know they forgot about something.
Using a typical project layout for me, I might have something like the following:
Controllers
| |
| - MoviesController.php
|
Models
| |
| - Movie.php
Views
| |
| - Movies
| |- Create.php
| |- Edit.php
| - Partials
| |- _MovieForm.php
MoviesController contains two actions - Create() and Edit($id), which have their own views. I personally would have a third action as well, which handles the form submission from both actions:
public function Save()
{
//...snip...
}
Create() simply loads the corresponding view. Edit() is slightly different in that it retrieves an existing record from the database first, using our Model, before passing it to the view.
The two views have a nested "partial", which is a fragment of commonly used HTML - in this case, _MovieForm.php, which has our form inputs (which are capable of displaying passed-in values).
The form also contains a hidden input field for our row id. This is only given a value when we call the Edit() action.
The form submits to the Save() method of MoviesController, which checks if we have a passed row id. If so, get our row from the database (again, represented by our Model), update the values, and call our Model's Save() method.Model::Save() runs our validation logic on our data and either saves to the database, or passes the data back along with our validation error message to the view.
Hope this helps :)
When should a new model or controller be made? Should there only be controllers that go with a corresponding view 1 to 1 and like so with controllers and models? Or is it good practice to have controllers for functionality not tied up with any particular view? Take for example voting, should all voting code go in a voting controller or be spread among controllers that have views using voting. Seems likely a voting controller would be best.
First of all , you cannot actually implement classical MVC in php. The best you can do is Model2 MVC.
Model - responsible for all the business logic. Has no clue about where the data is stored or actually comes from. The storage and retrieval is responsibility of DataMappers or DAOs. Model itself should never contain SQL. Ever.
Controller - binds model(s) to the view and changes the state of both. It does not retrieve information from models for sending it to view.
View - responsible for all presentational logic. Retrieves information from models and binds it to appropriate templates. View itself is not a template.
You can wither have 1:1 relationship between views an controller or many:many. it depends on how you implement the view itself.
For example, your view can require a separate object which handles the rendering. And providing different type of objects ( this is where polymorphism matters ), you can make your view to render either xml, html or json.
Or you can do the same by changing the templates. A ListView class can render a list of articles as well as list of users, if the basic presentation logic does not change and you provide just a different template for each.
In the case of voting , it seems ok to have a single controller for all voting related operations, and you can have a single view with switching the templates for your output.
Some of this sort of thing is down to preferences and opinion; there's no single correct way. Some approaches might be more flexible, but maybe at the expense of being more complex.
With regard to your example of "voting", that may depend upon how voting is going to be used in your site. Will votes appear on different types of pages? If so, some sort of component is a good approach; the voting component view can then be used to display its data within different pages, with a Voting component controller accepting the results of votes and then maybe redirecting somewhere else (or accepting votes by an Ajax request).
Very often you'll find that a models (and controllers) map more or less 1:1 to tables in a database. So if I have a table users, I might have a corresponding User model, and UserController controller.
Remember what a controller is intended to do: respond to a request, working out which models need to be loaded, then asking them to store, manipulate and return data which is then transferred to the view for displaying. It's fine to have controllers that don't map directly to models. You might have a controller called DebugController that responds to requests to http://examples.com/debug/, and doesn't map directly to a Debug model and table, but gathers information about the system and various models (of course, there is the argument that all that stuff should be wrapped up into a Debug model, which in turn loads other models and assembles the data that the controller requests).
As for views, you will normally have more than one view for a given controller; often one view per action. So UserController::indexAction() has views/user/index.php, UserController::editAction() has views/user/edit.php etc.
The approach might be flexible, that is true.
Models - Describe the tier that is communicating directly with database, all the SQL queries.
You can have model for each table in DB that will handle all actions connected to that table (select, insert, update, delete).
You can have model for each "logical entity", modul in your application that will handle the actions for this entity. Like in your example "Voting", where you can define the logic of this modul.
(Check if the user has allready voted, getVoteCount...)
Controler - Handle the request by executing functions in the model (they should not comunicate directly in DB) and passing the processed data to appropriate View. If you need to present the same data differently on different page, the controler should decide on which view to send the data.
View - You need view for each page, form, module in you application. It is on personal experiance how you are going to organize the views.
This is my first foray into using an MVC construct (CodeIgniter). I'm hoping someone can tell me where the following elements belong. I have them written; I just want to make sure they're placed properly in their respective locations. This is how my application will run:
Call a DB and see if we have a user signed up
Route to a signup page
Route to the main preferences page for existing users
Make DB queries for producing a new user
Make update queries when users change their preferences
The service being provided is a cron job cycling every 10 minutes, which I still have written outside of CodeIgniter. Is this something I should/could add to the logic somewhere? It pings Twitter, and does stuff with any new tweets. Let me know if I can clarify any part of this!
Model
Controller
Controller
Model
Model
Rule of thumb: if it involves the database or the state of the application, it belongs in a model. If it is HTML or presentation logic, it belongs in a view. Controllers handle the rest of the logic, and help link the views and models together.
There are a lot of other things that come up too:
Where should I sanitise data? As it comes from the model - in the controller or finally before I view? I do it generally in the view if it's something like htmlspecialchars() (though I'm sure others might disagree).
Wikipedia has a very good article.
Rather than use a full-blown PHP MVC, I'm designing one that will best-fit my uses. I have the basic framework done, and have coded the models and controllers I'll need to run my website.
Now I'm moving onto the Views, and I've encountered a small dilemma. My approach is working fine for me, but for future reference, I want to know if what I'm doing is a bad habit to get into.
What I'm trying to do:
In my View, I'm calling a Model that runs my authentication system, and requesting the login status of a user. I then use that boolean to decide whether to show certain elements within the view, and where to place others.
Should I be designing separate views for each login status, or is this approach fine? However, if I'm going to be implementing this MVC into the work I'm doing for my clients, I need to use the best practices.
Any advice would be appreciated!
Can I call the model from the View?
Yes, you can. As long as you maintain the separation of concerns between M,V and C, you are free to call upon the Model (or the Controller) from the View. Most MVC diagrams show a bidirectional connection at least between View and Model. What you don't want to do though, is place logic/code from the Model (or the controller) into the View and you don't want to modify the model from there.
For example, you might have a widget on your page that aggregates the latest ten blog posts headlines from your favorite blogs on each page of your website. You get the headlines by calling, say MyFavFeeds::getLatest(); in your model. What are your options now?
You could add the code to fetch the headlines into the controller, but that would require you to replicate it in each and every controller action, which is against the DRY principle. Also, the controller's concern is handling user input for specific actions and fetching the headlines on each call is likely not even related to these actions.
If your architecture supports it, you could fetch that data in some sort of preDispatch hook, that is, the headlines get loaded and injected into the View from a plugin or callback. That would be DRY, but a second developer might not be aware of that plugin and accidently overwrite the variable holding the headlines from his controller action. And there might be cases in which you wouldn't want to load the headlines, e.g. when just rendering confirmation pages for form submissions, so you'd have to have mechanism for disabling the plugin then. That's a lot to consider.
You place the call to (not the code of) MyFavFeeds::getLatest() into the View or Layout template or, better, a ViewHelper, that encapsulates the call to your model class and renders the widget. This way you don't have to worry about overwriting any variables or repetition. And when you don't need the headlines on your view, you simply don't include it.
About your other question:
In my View, I'm calling a Model that
runs my authentication system, and
requesting the login status of a user.
I then use that boolean to decide
whether to show certain elements
within the view, and where to place
others.
Authentication is something you will want to do early in the application flow, before any controller actions are called. Thus, you should not run your (entire) authentication system in the View. The actual authentication is not View-related logic. Just requesting the user status after authentication, on the other hand, is okay. For instance, if you want to render a widget showing the user name and giving a login/logout button, it would be fine to do something like
<?php //UserHelper
class UserMenuHelper
{
public function getUserMenu()
{
$link = 'Logout';
if(MyAuth::userHasIdentity()) {
$link = sprintf('Logout %s',
MyAuth::getUsername());
}
return $link;
}
}
If you got larger portions of your GUI to be modified by a User's role, you might want to break your View apart into partial blocks and include them based on the status, instead of writing all the HTML into a View Helper.
If you are only looking to render a navigation based on the user role, have a look at Zend Framework's Zend_Navigation and Zend_Acl to see how they do it.
You can, but you shouldn't. Except for a few extreme cases (and branching your view based on logged-in status is definitely not an "extreme case"), it's pretty much always A Bad Idea to call model stuff from a view.
What you probably want to do in your situation is pass the boolean to the view through the controller. That way, if you change something about the User model, the view doesn't have to know, so long as the controller keeps the behavior the same.
While I only know enough about MVC to get myself in trouble, I've always lived by the fact that unless your view is STRICTLY user interface, then it shouldn't be there.
Also, I've also ran with the idea of thin controllers, fat models.
Going off of these, I'd suggest adding a method to your authentication system model that returns the appropriate view to render and passes that to the view.
Okay, I would really try to keep my Views as logic-free as possible. If you need to switch anything based on e.g. the result of a model method, put a controller in place that delegates the rendering.
Just make sure you follow the basic idea: Do your stuff in the models, Tell your models what to do from your controllers and also tell your views what to show from your controllers.