SitePoint Sponsor |
|
User Tag List
Results 26 to 50 of 83
Thread: Easy MVC Example
-
Jul 19, 2007, 06:12 #26
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Last edited by blueyon; Jul 19, 2007 at 07:20.
-
Jul 19, 2007, 07:45 #27
Hi Blueyon
I'm a bit of a noob with MVC so sorry about all these questions, It's just I find your example nice and easy to understand..............well "easier"
I'm trying to incorporate a latest news module, but I seem to be having trouble with the model part, would it be something like the following???
PHP Code:class ModuleNews extends Controller {
function fetch() {
$model = $this->locator->createModel('news');
$articles = $model->latest_news();
$view = $this->locator->get('view');
$view->set('articles',$articles;)
return $view->fetch('module/news.tpl');*/
}
}
class ModelNews extends Model {
function __construct($locator) {
$this->locator = $locator;
}
function latest() {
return $this->getRows("SELECT * FROM news");
}
}
-
Jul 19, 2007, 08:11 #28
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I might have got have got some points worng on the model.
You could do it like this:
PHP Code:class ModuleNews extends Controller {
function fetch() {
$view = $this->locator->get('view');
$model_news = $this->locator->createModel('news');
$view->set('articles', $model_news->getLatest());
return $view->fetch('module/news.tpl');
}
}
class ModelNews extends Model {
function getLatest() {
return $this->getRows("SELECT * FROM news");
}
}
$this->database =& $locator->get('database');
-
Jul 19, 2007, 08:19 #29
ahh this could be the problem I'm having, thanks for your help blueyon
-
Jul 19, 2007, 22:39 #30
- Join Date
- Oct 2006
- Posts
- 85
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I can't remember where I saw the example that was my 'eureka!', but here's what I go by:
This is from an encapsulated module perspective (1 module has 1 controller class, 1 model class and 1 view class). There are other ways, if you have one model for news, one model for categories, etc, that can make that a different balance, but mostly the same rules apply.
The controller should be the class/object that is called when opening or running the module. It should handle:
- the access code: is the user allowed to see this page?
- the input validation code: is the supplied data correct?
- selecting the correct models and views, based on incoming data (in the example below, incoming data is the function name which is named like pages, this is not necessarily the best way, but it still shows what a controller does)
The controller is the access logic part.
PHP Code:class Controller {
protected $view = null;
protected $model = null;
public function __construct($name) {
$namemodel = $name . "Model";
$this->model = new $namemodel();
$nameview = $name . "View";
$this->view = new $nameview($this->model);
}
}
class PageController extends Controller {
public function doMain() {
$this->view->viewMain();
}
public function doAdmin() {
if ($_SESSION['access'] != ACCESS_ADMIN) {
// redirect to no access page
}
$this->view->viewAdmin();
}
public function doViewCategories() {
$this->model->loadCategories();
$this->view->viewCategories();
}
public function doAddCategory() {
if (!preg_match("/^[a-zA-Z0-9 _\-]+$/", $_POST['category_name'])) {
$this->doViewCategories();
return;
}
$this->model->sqlAddCategory($_POST['category_name']);
$this->view->viewAddCategorySuccess();
}
//..
}
The model is the business logic part.
PHP Code:class Model {
// something that may be valid for all your model classes. i have stuff, but it's very specific to my apps.
}
class PageModel extends Model {
public function loadCategories() {
$this->data['categories'] = $database->sql("load categories blabla");
}
public function loadProfileData() {
$this->data['profile'] = $database->sql("load profile data blabla");
}
// both the following methods should check that the data exists first.
public function getCategories() {
return $this->data['categories'];
}
public function getProfileData() {
return $this->data['profile'];
}
//..
}
The view does not have to do the formatting itself, but the controller only knows about the view, not any template system or anything, so all data is sent to the view, and must be handled from there.
The view is the presentation logic part.
PHP Code:class View {
protected $model = null;
public function __construct(&$model) {
$this->model =& $model;
}
}
class PageView extends View {
public function viewMain() {
echo "main content for module, no retreived data";
}
public function viewAdmin() {
$profile = $this->model->getProfileData(); // this should throw an error or an exception, as the controller did not call any model method in 'doAdmin()', so the model has no data available.
echo $profile['name']; // ... etc
}
public function viewCategories() {
$categories = $this->model->getCategories(); // works!
// format categories into a neat table and output
foreach ($categories as $cat) {
// format table row
// echo formatted table row, etc
}
// also output form for adding a new category
}
//..
}
It's possible to follow the acces, business and presentation rules pretty strictly. If you have any of the wrong logic in the wrong place, then you're doing something wrong (no shyte?). Before you start writing code, think about what goes where. Everything has its place
-
Jul 20, 2007, 02:18 #31
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
After just glancing at your code i'm sure models should not touch views. Yet you have a model in the view class.
-
Jul 20, 2007, 04:45 #32
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
A controller receives input and issues instructions. It shouldn't pass data to view objects. If you decide to change the data displayed in a view you'd also have to edit the controller. It's up to you to decide if that's likely to be an issue though.
working on: Aperiplus, Rephactor, Phemto
useful links: xUnit test patterns, martinfowler.com, c2 wiki
-
Jul 20, 2007, 07:17 #33
- Join Date
- Oct 2006
- Posts
- 85
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
The model variable in the view class is there so that the view class is able to retreive data from it. It is a pointer variable, ergo the same model as before, which you'll see if you look closely
It doesn't matter which access points are where, as long as you keep the logic separate. Hell, the view can even call the model to perform operations, and still that would keep the logic separate, although it's not optimal.
-
Jul 20, 2007, 07:22 #34
- Join Date
- Oct 2006
- Posts
- 85
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
-
Jul 20, 2007, 07:33 #35
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
In MVC, the controller selects the view, and the view selects the model. A controller should not pass any information to the view, including passing a model instance. The controller may also select a model, although for updating, where the view selects a model for reading. The model, which the controller selects, and the one which the view selects need not be the same.
Furthermore, model is an abstraction -- in a concrete implementation, the model will often be several objects, rather than just one. The controller and view, on the other hand, is often implemented as a single instance each.
-
Jul 20, 2007, 07:53 #36
Hi kyberfabrikken
So is this wrong?
PHP Code:class ModuleEvents extends Controller {
function fetch() {
$view = $this->locator->get('view');
$model_events = $this->locator->createModel('events');
$view->set('latest_events', $model_events->getLatest());
return $view->fetch('module/events.tpl');
}
}
-
Jul 20, 2007, 08:40 #37
- Join Date
- Oct 2006
- Posts
- 85
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
One thing is certain in any case, the model should never do any calls to either the controller or the view. That is definately 'wrong'.
-
Jul 20, 2007, 09:16 #38
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
If you want MVC, then yes.
That would be the way to do it, yes.
If you do it the other way, you don't have V and C separated. In other words you have a 2-tier, consisting of Model and Presentation. For many applications, this is enough; You often don't need a full 3-tier (MVC). If there is a 1:1 relationship between controller and view anyway, the extra decoupling just adds complexity. I think this is the reason, why many people are having a hard time grasping MVC.
-
Jul 20, 2007, 11:30 #39
- Join Date
- May 2004
- Location
- Central USA
- Posts
- 806
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Exactly what I find most of the time. The general consensus seems to be that there are two ways to implement the view:
1. Push data into it from the controller
2. Pull data in from the View layer itself
And although the true MVC-correct way is (2), it does add complexity that is simply not required or even wanted in most implementations, so people often go with (1) in order to not have to create a separate 'View' class for each module/controller they create. I personally don't see a huge problem with pushing data to the view from the controller if it really helps eliminate complexity where it's not needed.Stackbox CMS - Full edit-on-page drag-and-drop CMS
Autoridge - Vehicle information & maintenance part numbers
Twitter | Blog | Online Javascript Compressor
-
Jul 20, 2007, 12:14 #40
- Join Date
- Mar 2007
- Location
- Czech Republic
- Posts
- 375
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
kyberfabrikken:
If there is a 1:1 relationship between controller and view anyway, the extra decoupling just adds complexity.
What exactly does it mean? If the site has only one page template with blocks filled from view, is it 1:1 relationship? If - for example - controller analyses URL and passes action (and name of component for main block) to view, could I merge controller with view?
-
Jul 20, 2007, 12:17 #41
- Join Date
- Feb 2007
- Posts
- 1,274
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Kyber, 3-tier usually refers to the fact that you have
1) a persistence (data) tier,
2) a business logic tier and
3) a presentation tier
MVC is a (composite) design pattern which describes elements of tier 2 (the model lives here) and tier 3 (view and controller lives here). I think that claiming MVC constitutes a 3-tier architecture is add confusion. You can have MVC in a two tier model, too.Actually, many modern web MVC frameworks are close to two tier, as Active Record is a persistence pattern more than a business logic pattern.
I agree that the separation of view and controller is often not as important as separating the two from the model. Trygve Reenskaug and Fowler realized (and noted) this a long time ago.
You made a very good point about the model being an abstraction, and that in practice the model may be a number of objects from the business logic tier (or indeed in simple cases from the persistence tier - think Active Record).
What is also frequently ignored (I believe that Konstruct may be an exception here?) is the fact that also the view and the controller are abstractions. They need not be represented by a single class.
The original MVC pattern was described as a recursive one: The "view" could in fact consist of subviews where each subview could have its own associated controller. This is important because otherwise the single monolithic controller is being strongly coupled to the structure of the view.
(I believe that the recursive nature of the pattern was lost because the UML drawings of the pattern do not capture that characteristic very well)
@Athos:
It doesn't matter which access points are where, as long as you keep the logic separate. Hell, the view can even call the model to perform operations, and still that would keep the logic separate, although it's not optimal.
I happen to believe that having the (sub)view perform actions on the model is indeed desirable. Having an enclosed, self-contained editor (subview+subcontroller) goes directly composability. The controller in the original MVC was much more about creating/placing/managing sub views and controllers than it was about micro-managing input fields of a single view.
---
Some will argue that "web MVC" is different than traditional (GUI) MVC because the web is "disconnected", request/response based. However, as we come to expect more and more interactivity of web applications they approach the behaviours of GUI apps. This is where many of the "web MVC" frameworks will face challenges.
Frameworks such as Rails (which has inspired a lot of PHP frameworks) does not at the present have support for true, composable MVC.
-
Jul 20, 2007, 13:52 #42
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Thanks for correcting me.
Yes, Konstrukt uses multiple components to realise the V and C layer. I don't think it's unique in that respect though; Even the dispather based frameworks (Eg. Struts and RoR inspired ones) has two components for the controller layer - Frontcontroller and Action. But frameworks based on a heirarchy of controllers (Such as Konstrukt) usually have more than those two.
I totally agree. I think the popular dispatcher pattern stems from the transaction script way of thinking about web applications. A single dispatch and command object fits into this discourse. As applications become more complex, it's desirable to break it down to self-contained components (objects/subviews) instead of organising things at the request-level.
-
Jul 20, 2007, 14:24 #43
- Join Date
- Jun 2004
- Location
- Copenhagen, Denmark
- Posts
- 6,157
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Usually, the reason why you'd need MVC over just M+VC, is because the controller should be able to chose a different view, depending on certain conditions. In a web application, this could for example be an application, which - for the same URL - responds with HTML to browsers, and RSS to feedreaders. In theory, that's nice and all, but in practise, it's more desireable to supply a different URL for each of these views.
Since you will then always get the same view from the same controller, the separation between the two is completely theoretical - In practice they are so tightly coupled, that it makes no difference whether you implement them as two components or as one. This is when you might as well merge them into one entity.
You don't need to tie your self into choosing between full MVC and M+VC. I rarely find myself actually needing V and C separation in web applications, so most of the time, I merge then into one. In the few cases, where I actually need multiple views for a single controller, I will just "upgrade" that single VC by splitting it up in a controller and a number of views. The rest of the application can still use the simple solution.
Applying MVC this way means that you're treating it more as a pattern, which can be applied strategically, where needed, instead of a dogma which must be followed at all time. The latter will also work, but it adds an amount of bureaucracy.
-
Jul 20, 2007, 15:38 #44
- Join Date
- Feb 2007
- Posts
- 1,274
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
-
Jul 20, 2007, 22:30 #45
- Join Date
- Oct 2006
- Posts
- 85
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Like I said, my example is only valid in a 1c:1m:1v module. Sure, if you have several models that are accessible to each view or controller, then there is no point in the controller knowing anything about what the view needs, as that would create a complete mess.
My example has the assumption that if the controller can communicate with the model, then there can be raised exceptions to be handled inside the controller, instead of in the view, before the presentation is even considered.
One thing you can do is let the model itself handle which "submodels" to load, and then just extract the functionality that is necessary for this particular module, making it a 1:1:1 module, where the controller can "prepare" everything together with the model, and the view then gets the data that was prepared, or possibly errors.
-
Jul 21, 2007, 08:13 #46
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I have found this:
http://best-practice-software-engine...terns/mvc.html
It explains the different MVC styles depending if its a desktop application or web.Last edited by blueyon; Jul 21, 2007 at 15:28.
-
Jul 22, 2007, 14:43 #47
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I don't know what type of MVC I'm using. All I know is its very similar to a lot of examples on the web. It's also like frameworks such as codeignitor and cake.
It also makes building web application more easy because it structures my code.
-
Jul 22, 2007, 22:02 #48
- Join Date
- Oct 2006
- Posts
- 85
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I think you can't compare MVC for desktop apps and web apps. Some people will disagree, but there's an important difference. Desktop apps are synchronous, while web apps are asynchronous. The closest way to emulate a desktop app would be Ajax with JSP.
-
Jul 23, 2007, 02:02 #49
Sorry to bring this conversation back to a basic level but I seemed to be getting confused with the view layer
If my application was to fetch products that equal x and the result was 0, would my product controller query the db and the select the required view+method IE
$view->NoData(); or would my controller simply select the product view class and let my view class decide?
Thanks in advance
-
Jul 23, 2007, 02:46 #50
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
You can do it ethier way. I use a common view to display no products, no categories, etc..
All that changes is the text.
It depends on what you think is best.
Another example is if you have a product information page and you have additional images to be display at the bottom. The product information page does not require a sperate view to display no additional images. Just put an IF statement to display the message if no additional images found.
Most template engines have IF, ELSE statements and FOREACH loops.
Bookmarks