SitePoint Sponsor |
|
User Tag List
Results 1 to 25 of 83
Thread: Easy MVC Example
-
Jun 26, 2007, 04:59 #1
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Simple MVC Example
I have just done a quick MVC example. It took me about 20 minutes to write.
Its a little to big to post the code on the forum so I have added it as an attachment.
Please let me know what you think!Last edited by blueyon; Jun 26, 2007 at 07:05.
-
Jun 27, 2007, 00:40 #2
- Join Date
- Feb 2006
- Location
- Netherlands
- Posts
- 295
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Uhm, although we obviously have different opinions on how a View and the parsing of it works, I quite like it. It's a darn shame this is in php4, instead of php5 though, you might wish to reconsider that? Also, as I think this is for people new to the subject, I would choose to actually implement at least one model and one view. For people without any MVC experience, it's often unclear where responsibilities lie.
Wait, for those who are experienced in MVC, it's still unclear where responsibilities lie.
-
Jun 27, 2007, 01:57 #3
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I think what I have done is correct. It uses the same sort of MVC style as codeignitor, but not using the loader class.
Last edited by blueyon; Jun 27, 2007 at 06:22.
-
Jun 29, 2007, 09:30 #4
You need a "var $locator;" at the top of your controller.php
-
Jul 12, 2007, 09:28 #5
Hey blueyon
Thanks for the great example it's really nice and clear for an MVC beginner such as myself especially for some of the library objects
So, would I incorporate multiple views and models in each controller?
IE what if the home controller included news artcles, events aswell as main content.
Would it be a bit cheeky to ask for an example with the view(s) and model(s) incorporated
-
Jul 12, 2007, 09:47 #6
would it be something like this
PHP Code:class ControllerHome extends controller {
function ControllerHome(&$locator) {
$this->view =& $locator->get('view');
$this->model =& $locator->get('model');
$this->response =& $locator->get('response');
}
function index() {
$news_model = $this->model->get('news');
$events_model = $this->model->get('events');
$articles = $news_model->get_articles();
$events = $events_model->get_events();
$content = $this->view->fetch('home');
$news_view = $this->view->set($articles);
$events_view = $this->view->set($events);
$template = $this->view->set($content,$news_view->fetch('news'),$events_view->fetch('events');
$this->response->set($template->fetch());
}
}
-
Jul 12, 2007, 11:33 #7
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
You could... However you are going to be faced with a nightmare in regards to maintainance and for future growth; What happens when one part changes? You should be able to do those changes, without effecting the others.
So, you are looking for Composite, where you separate each component into it's own Controller, ie
Code:+ Home Controller + --- News Controller + --- Polls Controller + --- Etc...
PHP Code:class Composite {
protected $children = array();
public function( $id = false ) {
if( $id ) {
$this -> id = $id;
}
}
public function getId() {
return $this -> id;
}
public function getChildren() {
return $this -> children;
}
public function hasChildren() {
return count( $this -> children );
}
public function attach( Composite $composite ) {
$this -> children[$composite -> getId()] = $composite;
}
}
PHP Code:$home = new Home_Controller( 'home' );
$home -> attach( new News_Controller( 'news' ) );
$home -> attach( $polls = new Polls_Controller( 'polls' ) );
// ... etc
PHP Code:// ...
$polls -> attach( new Another_Child_Controller( '...' ) );
// and so on
PHP Code:// ...
public function begin( Composite $composite ) {
ob_start();
$this -> traverse( $composite );
echo ob_get_clean();
}
public function traverse( Composite $composite ) {
$children = $composite -> getChildren();
foreach( $children as $child ) {
ob_start();
$this -> traverse( $child );
$context -> set( $child -> getId(), ob_get_clean() );
} // job done
-
Jul 12, 2007, 16:24 #8
- Join Date
- Sep 2002
- Location
- Canada
- Posts
- 2,087
- Mentioned
- 1 Post(s)
- Tagged
- 1 Thread(s)
If your just refactoring configuration just use inheritance instead of composites.
"A nerd who gets contacts
and a trendy hair cut is still a nerd"
- Stephen Colbert on Apple Users
-
Jul 13, 2007, 02:27 #9
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I'm going to try an update with what Dr Livingston has said here and what kyberfabrikken has said in this post.
-
Jul 13, 2007, 03:18 #10
Cheers for the response guys, certainly makes more sense Dr Livingston I'll have to have a play around, I'd be very interested to see your response blueyon
Thanks again
Crabby
-
Jul 13, 2007, 04:07 #11
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
The only way I can think of to get this to work without messing up the controller or the modules is for the base controller to extend the composite.
Is this correct?
-
Jul 13, 2007, 07:02 #12
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I have not got a clue how to implement the composite pattern with a controller, module loader class and template.
I can implement a composite view, but I'm not sure thats what Dr Livingston means.
-
Jul 13, 2007, 08:55 #13
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Dr Livingston are you shure you have this right?
Your implementing composite controllers. The are plenty of composite view examples, but I can not find any for composite controllers.
-
Jul 13, 2007, 09:07 #14
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
You can implement the Composite as you see fit, it doesn't really have to be implemented from the View layer in particular yes?
I implement the Composite in a number of ways, so you are not really restricted to the View [MVC] alone; Some people implement their Views as Composites, using one controller for example...
But that is but one implementation, and it's not written in stone that you need to follow that particular implementation. So the pattern Composite is exactly the same as that of the Composite View. There is no difference, so it's down to your own implementation of how you manipulate an hierarchacal structure.
Hope this helps?
-
Jul 14, 2007, 06:29 #15
- Join Date
- Jun 2003
- Location
- Melbourne, Australia
- Posts
- 440
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
WACT does it.
Zealotry is contingent upon 100 posts and addiction 200?
-
Jul 14, 2007, 13:44 #16
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I have just looked at wact and yes it does have this feature.
What I'm thinking of is a module manager that feeds the generated html back to the main controller and is set to the template.
You should have the ability on some web applications to install / uninstall modules.
If there is no module manager then you need to do a lot of repeative coding on each controller to load the module and attach it to the main controller.
-
Jul 15, 2007, 03:47 #17
- Join Date
- Jun 2003
- Location
- Melbourne, Australia
- Posts
- 440
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Assuming that most of these 'modules' (however you define them) will have some output in the page (composite view), then you could write a module manager that fits into the front controller (same layout for every page) or the page controller that is selected by the front controller (different layouts for different kinds of pages). Then, I suppose, you only have to do repetitive coding for each module whose output makes up the page.
I can see this approach working well within WACT.Zealotry is contingent upon 100 posts and addiction 200?
-
Jul 16, 2007, 02:16 #18
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
-
Jul 16, 2007, 04:52 #19
- Join Date
- Jun 2003
- Location
- Melbourne, Australia
- Posts
- 440
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
-
Jul 16, 2007, 06:14 #20
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I have just updated the example using Konstrukt's Assembler from another post and added a module loader class.
I'm still having trouble implemeting the composite pattern with my controller.
If there is any one who can given an example with the code I have done showing how to implement the composite pattern with my controller it would be great!
-
Jul 16, 2007, 07:04 #21
Ah good stuff blueyon need to check this out
-
Jul 16, 2007, 07:20 #22
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
> If there is any one who can given an example with the code I have done showing how to
> implement the composite pattern with my controller it would be great
I'll download your file now and take a look later
> I don't want modules loading on every page because some might not require them such
> as when using ajax.
As you recurse over your structure, it's just a case of pulling a given Composite out, prior to execution thus it's ignored altogether. This is what you want, since you can have a base layout structure generated for you on each request, rather than have a different layout for each request.
In this case, you don't really need any sort of configuration, other than how your recursion would know which Composite to pull out.
-
Jul 17, 2007, 06:39 #23
- Join Date
- Feb 2006
- Posts
- 281
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I decided to posting the code might help.
How would you make this a composite controller?
My framework sort of follows the style from an example given on phpit.com.
PHP Code:<?php
// Controller
class Controller {
function __construct(&$locator) {
$this->locator =& $locator;
}
}
// Module
class Module {
var $data = array();
function __construct(&$locator) {
foreach (glob(DIR_MODULE . '*.php') as $file) {
include($file);
$class = 'Module' . basename($file, '.php');
$this->data[basename($file, '.php')] = new $class(&$locator);
}
}
function fetch() {
$module_data = array();
foreach (array_keys($this->data) as $key) {
$module_data[$key] = $this->data[$key]->fetch();
}
return $module_data;
}
}
// Controller Home
class ControllerHome extends Controller {
function index() {
$view1 =& $this->locator->get('view');
$view1->set('title', 'Simple MVC');
$view2 = $this->locator->createView();
$url =& $this->locator->get('url');
$view2->set('home', $url->href('home'));
$view1->set('content', $view2->fetch('content/home.tpl'));
$module =& $this->locator->get('module');
$view1->set($module->fetch());
$response =& $this->locator->get('response');
$response->set($view1->fetch('layout.tpl'));
}
}
// Module Box1
class ModuleBox1 extends Controller {
var $id = 'box1';
function fetch() {
return 'This is box 1';
}
}
?>
-
Jul 18, 2007, 09:01 #24
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
PHP Code:// Controller Home
class ControllerHome extends Controller { ...
Your Controller I refer to it being a Application_Action_Controller, akin to Zend Framework (but differing implementations). But it depends really, on how involved you want to get?
By that I mean, you could have a Composite based Controller structure, but do you need that level of refinement... You could just as well manage easily enough with just a Composite structure on your View instead, going by your posted example (found in download) in my view.
At the end of the day, it really depends on the complexity of your Page structure. If you've got a tonne of separate individual components your page is comprised of, then go the Controller route, otherwise take the View route; Take the wrong route and your going to give yourself more work to do.
PHP Code:interface QComposite_Interface {
public function getId();
public function getChildren();
public function hasChildren();
public function attach( QComposite_Interface $composite );
}
abstract class QComposite implements QComposite_Interface {
protected $children = array();
protected $id;
public function __construct() {}
public function getId() {
return $this -> id;
}
public function getChildren() {
return $this -> children;
}
public function hasChildren() {
return count( $this -> children );
}
public function attach( QComposite_Interface $composite ) {
$this -> children[$composite -> getId()] = $composite;
}
}
interface QAction_Handler_Interface extends QComposite_Interface {}
abstract class QAction_Handler implements QAction_Handler_Interface {
protected $children = array();
protected $id;
public function __construct() {}
public function getId() {
return $this -> id;
}
public function hasChildren() {
return count( $this -> children );
}
public function getChildren() {
return $this -> children;
}
public function attach( QComposite_Interface $composite ) {
$this -> children[$composite -> getId()] = $composite;
}
abstract public function execute( QDataspace_Interface $context );
}
PHP Code:abstract class QAction_Handler_Factory {
protected $children = array();
public function __construct( $children ) {
$this -> children = $children;
}
public function get() {
$args = func_get_args();
$parent = array_shift( $args );
$composite = $this -> create();
if( $parent instanceof QAction_Handler_Interface ) {
$parent -> attach( $composite );
}
foreach( $this -> children as $child ) {
$classname = $this -> formatName( $child );
$instance = new $classname();
$instance -> get( $composite );
}
return $composite;
}
protected function formatName( $name ) {
return 'Q'.ucwords( $name ).'_Factory';
}
abstract protected function create();
}
PHP Code:final class QPage_Factory extends QAction_Handler_Factory {
public function __construct() {
parent::__construct( array( 'head', 'body', 'menu' ) );
}
protected function create() {
return new QPage_Action_Handler();
}
}
final class QHead_Factory extends QAction_Handler_Factory {
public function __construct() {
parent::__construct( array() );
}
protected function create() {
return new QHead_Action_Handler();
}
}
final class QBody_Factory extends QAction_Handler_Factory {
public function __construct() {
parent::__construct( array( 'search' ) );
}
protected function create() {
return new QBody_Action_Handler();
}
}
final class QMenu_Factory extends QAction_Handler_Factory {
public function __construct() {
parent::__construct( array() );
}
protected function create() {
return new QMenu_Action_Handler();
}
}
final class QSearch_Factory extends QAction_Handler_Factory {
public function __construct() {
parent::__construct( array() );
}
protected function create() {
return new QSearch_Action_Handler();
}
}
PHP Code:final class QPage_Action_Handler extends QAction_Handler {
public function __construct() {
$this -> id = 'page';
}
public function execute( QDataspace_Interface $context ) { // script goes here }
}
final class QHead_Action_Handler ... etc ...
Hope this gives you some enlightmentLast edited by Dr Livingston; Jul 18, 2007 at 11:56.
-
Jul 19, 2007, 05:36 #25
Thanks for the reply Dr Livingston, just need to get my head around it
Blueyon, are modules seperate elements of the page IE header, Navigation, News Artcles etc?Last edited by crabby80; Jul 19, 2007 at 06:08.
Bookmarks